diff --git a/[refs] b/[refs]
index 6906d903140c..ca52d18b5864 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: d7867959e7e928ab52ef204e2559937e5c9fc4ce
+refs/heads/master: 821077b2617ef70662a861393c929d7e47609512
diff --git a/trunk/CREDITS b/trunk/CREDITS
index 7fb4c73e0228..192f749eba25 100644
--- a/trunk/CREDITS
+++ b/trunk/CREDITS
@@ -1097,7 +1097,7 @@ S: 80050-430 - Curitiba - Paran
S: Brazil
N: Kumar Gala
-E: kumar.gala@freescale.com
+E: galak@kernel.crashing.org
D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support
S: Austin, Texas 78729
S: USA
diff --git a/trunk/Documentation/DocBook/Makefile b/trunk/Documentation/DocBook/Makefile
index 7018f5c6a447..1c955883cf58 100644
--- a/trunk/Documentation/DocBook/Makefile
+++ b/trunk/Documentation/DocBook/Makefile
@@ -20,6 +20,12 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
# +--> DIR=file (htmldocs)
# +--> man/ (mandocs)
+
+# for PDF and PS output you can choose between xmlto and docbook-utils tools
+PDF_METHOD = $(prefer-db2x)
+PS_METHOD = $(prefer-db2x)
+
+
###
# The targets that may be used.
.PHONY: xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs
@@ -93,27 +99,39 @@ C-procfs-example = procfs_example.xml
C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example))
$(obj)/procfs-guide.xml: $(C-procfs-example2)
-###
-# Rules to generate postscript, PDF and HTML
-# db2html creates a directory. Generate a html file used for timestamp
+notfoundtemplate = echo "*** You have to install docbook-utils or xmlto ***"; \
+ exit 1
+db2xtemplate = db2TYPE -o $(dir $@) $<
+xmltotemplate = xmlto TYPE $(XMLTOFLAGS) -o $(dir $@) $<
+
+# determine which methods are available
+ifeq ($(shell which db2ps >/dev/null 2>&1 && echo found),found)
+ use-db2x = db2x
+ prefer-db2x = db2x
+else
+ use-db2x = notfound
+ prefer-db2x = $(use-xmlto)
+endif
+ifeq ($(shell which xmlto >/dev/null 2>&1 && echo found),found)
+ use-xmlto = xmlto
+ prefer-xmlto = xmlto
+else
+ use-xmlto = notfound
+ prefer-xmlto = $(use-db2x)
+endif
-quiet_cmd_db2ps = XMLTO $@
- cmd_db2ps = xmlto ps $(XMLTOFLAGS) -o $(dir $@) $<
+# the commands, generated from the chosen template
+quiet_cmd_db2ps = PS $@
+ cmd_db2ps = $(subst TYPE,ps, $($(PS_METHOD)template))
%.ps : %.xml
- @(which xmlto > /dev/null 2>&1) || \
- (echo "*** You need to install xmlto ***"; \
- exit 1)
$(call cmd,db2ps)
-quiet_cmd_db2pdf = XMLTO $@
- cmd_db2pdf = xmlto pdf $(XMLTOFLAGS) -o $(dir $@) $<
+quiet_cmd_db2pdf = PDF $@
+ cmd_db2pdf = $(subst TYPE,pdf, $($(PDF_METHOD)template))
%.pdf : %.xml
- @(which xmlto > /dev/null 2>&1) || \
- (echo "*** You need to install xmlto ***"; \
- exit 1)
$(call cmd,db2pdf)
-quiet_cmd_db2html = XMLTO $@
+quiet_cmd_db2html = HTML $@
cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
echo ' \
Goto $(patsubst %.html,%,$(notdir $@))
' > $@
@@ -127,7 +145,7 @@ quiet_cmd_db2html = XMLTO $@
@if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \
cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi
-quiet_cmd_db2man = XMLTO $@
+quiet_cmd_db2man = MAN $@
cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi
%.9 : %.xml
@(which xmlto > /dev/null 2>&1) || \
diff --git a/trunk/Documentation/DocBook/kernel-api.tmpl b/trunk/Documentation/DocBook/kernel-api.tmpl
index a8316b1a3e3d..0519c9dc0065 100644
--- a/trunk/Documentation/DocBook/kernel-api.tmpl
+++ b/trunk/Documentation/DocBook/kernel-api.tmpl
@@ -68,9 +68,7 @@ X!Iinclude/linux/kobject.h
Kernel utility functions
!Iinclude/linux/kernel.h
-
+!Ekernel/printk.c
!Ekernel/panic.c
!Ekernel/sys.c
!Ekernel/rcupdate.c
diff --git a/trunk/Documentation/DocBook/stylesheet.xsl b/trunk/Documentation/DocBook/stylesheet.xsl
index 64be9f7ee3bb..3ccce886c349 100644
--- a/trunk/Documentation/DocBook/stylesheet.xsl
+++ b/trunk/Documentation/DocBook/stylesheet.xsl
@@ -3,4 +3,5 @@
1
ansi
80
+
diff --git a/trunk/Documentation/atomic_ops.txt b/trunk/Documentation/atomic_ops.txt
index 8eedaa24f5e2..23a1c2402bcc 100644
--- a/trunk/Documentation/atomic_ops.txt
+++ b/trunk/Documentation/atomic_ops.txt
@@ -115,6 +115,33 @@ boolean is return which indicates whether the resulting counter value
is negative. It requires explicit memory barrier semantics around the
operation.
+Then:
+
+ int atomic_cmpxchg(atomic_t *v, int old, int new);
+
+This performs an atomic compare exchange operation on the atomic value v,
+with the given old and new values. Like all atomic_xxx operations,
+atomic_cmpxchg will only satisfy its atomicity semantics as long as all
+other accesses of *v are performed through atomic_xxx operations.
+
+atomic_cmpxchg requires explicit memory barriers around the operation.
+
+The semantics for atomic_cmpxchg are the same as those defined for 'cas'
+below.
+
+Finally:
+
+ int atomic_add_unless(atomic_t *v, int a, int u);
+
+If the atomic value v is not equal to u, this function adds a to v, and
+returns non zero. If v is equal to u then it returns zero. This is done as
+an atomic operation.
+
+atomic_add_unless requires explicit memory barriers around the operation.
+
+atomic_inc_not_zero, equivalent to atomic_add_unless(v, 1, 0)
+
+
If a caller requires memory barrier semantics around an atomic_t
operation which does not return a value, a set of interfaces are
defined which accomplish this:
diff --git a/trunk/Documentation/oops-tracing.txt b/trunk/Documentation/oops-tracing.txt
index c563842ed805..9f30ac6ca47b 100644
--- a/trunk/Documentation/oops-tracing.txt
+++ b/trunk/Documentation/oops-tracing.txt
@@ -30,7 +30,9 @@ the disk is not available then you have three options :-
(1) Hand copy the text from the screen and type it in after the machine
has restarted. Messy but it is the only option if you have not
- planned for a crash.
+ planned for a crash. Alternatively, you can take a picture of
+ the screen with a digital camera - not nice, but better than
+ nothing.
(2) Boot with a serial console (see Documentation/serial-console.txt),
run a null modem to a second machine and capture the output there
diff --git a/trunk/Documentation/video4linux/CARDLIST.bttv b/trunk/Documentation/video4linux/CARDLIST.bttv
index 2404099996ac..330246ac80f8 100644
--- a/trunk/Documentation/video4linux/CARDLIST.bttv
+++ b/trunk/Documentation/video4linux/CARDLIST.bttv
@@ -140,3 +140,4 @@
139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
140 -> Osprey 440 [0070:ff07]
141 -> Asound Skyeye PCTV
+142 -> Sabrent TV-FM (bttv version)
diff --git a/trunk/Documentation/video4linux/CARDLIST.saa7134 b/trunk/Documentation/video4linux/CARDLIST.saa7134
index 57c9d631db56..efb708ec116a 100644
--- a/trunk/Documentation/video4linux/CARDLIST.saa7134
+++ b/trunk/Documentation/video4linux/CARDLIST.saa7134
@@ -80,3 +80,5 @@
79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
80 -> ASUS Digimatrix TV [1043:0210]
81 -> Philips Tiger reference design [1131:2018]
+ 82 -> MSI TV@Anywhere plus [1462:6231]
+
diff --git a/trunk/Documentation/video4linux/CARDLIST.tuner b/trunk/Documentation/video4linux/CARDLIST.tuner
index ec840ca6f455..9d6544ea9f41 100644
--- a/trunk/Documentation/video4linux/CARDLIST.tuner
+++ b/trunk/Documentation/video4linux/CARDLIST.tuner
@@ -67,3 +67,4 @@ tuner=65 - Ymec TVF66T5-B/DFF
tuner=66 - LG NTSC (TALN mini series)
tuner=67 - Philips TD1316 Hybrid Tuner
tuner=68 - Philips TUV1236D ATSC/NTSC dual in
+tuner=69 - Tena TNF 5335 MF
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 2313de23b0da..509927e40bbb 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -1565,7 +1565,7 @@ S: Maintained
LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
P: Kumar Gala
-M: kumar.gala@freescale.com
+M: galak@kernel.crashing.org
W: http://www.penguinppc.org/
L: linuxppc-embedded@ozlabs.org
S: Maintained
@@ -1873,6 +1873,16 @@ L: linux-tr@linuxtr.net
W: http://www.linuxtr.net
S: Maintained
+OMNIKEY CARDMAN 4000 DRIVER
+P: Harald Welte
+M: laforge@gnumonks.org
+S: Maintained
+
+OMNIKEY CARDMAN 4040 DRIVER
+P: Harald Welte
+M: laforge@gnumonks.org
+S: Maintained
+
ONSTREAM SCSI TAPE DRIVER
P: Willem Riede
M: osst@riede.org
diff --git a/trunk/Makefile b/trunk/Makefile
index 8560b79268ba..c31914400953 100644
--- a/trunk/Makefile
+++ b/trunk/Makefile
@@ -1193,6 +1193,17 @@ else
__srctree = $(srctree)/
endif
+ifeq ($(ALLSOURCE_ARCHS),)
+ifeq ($(ARCH),um)
+ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
+else
+ALLINCLUDE_ARCHS := $(ARCH)
+endif
+else
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
+endif
+
ALLSOURCE_ARCHS := $(ARCH)
define all-sources
@@ -1208,7 +1219,7 @@ define all-sources
find $(__srctree)include $(RCS_FIND_IGNORE) \
\( -name config -o -name 'asm-*' \) -prune \
-o -name '*.[chS]' -print; \
- for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ for ARCH in $(ALLINCLUDE_ARCHS) ; do \
find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
-name '*.[chS]' -print; \
done ; \
diff --git a/trunk/README b/trunk/README
index 4ee7dda88ba3..61c4f7429233 100644
--- a/trunk/README
+++ b/trunk/README
@@ -81,6 +81,11 @@ INSTALLING the kernel:
failed patches (xxx# or xxx.rej). If there are, either you or me has
made a mistake.
+ Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
+ (also known as the -stable kernels) are not incremental but instead apply
+ directly to the base 2.6.x kernel. Please read
+ Documentation/applying-patches.txt for more information.
+
Alternatively, the script patch-kernel can be used to automate this
process. It determines the current kernel version and applies any
patches found.
diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig
index 3df7cbd924a1..70b007e66926 100644
--- a/trunk/arch/arm/Kconfig
+++ b/trunk/arch/arm/Kconfig
@@ -702,6 +702,8 @@ menu "Device Drivers"
source "drivers/base/Kconfig"
+source "drivers/connector/Kconfig"
+
if ALIGNMENT_TRAP
source "drivers/mtd/Kconfig"
endif
diff --git a/trunk/arch/arm/common/locomo.c b/trunk/arch/arm/common/locomo.c
index 557e52c1c869..1b7eaab02b9e 100644
--- a/trunk/arch/arm/common/locomo.c
+++ b/trunk/arch/arm/common/locomo.c
@@ -623,8 +623,6 @@ static int locomo_resume(struct platform_device *dev)
locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
spin_unlock_irqrestore(&lchip->lock, flags);
-
- dev->power.saved_state = NULL;
kfree(save);
return 0;
@@ -775,7 +773,7 @@ static int locomo_probe(struct platform_device *dev)
static int locomo_remove(struct platform_device *dev)
{
- struct locomo *lchip = platform__get_drvdata(dev);
+ struct locomo *lchip = platform_get_drvdata(dev);
if (lchip) {
__locomo_remove(lchip);
diff --git a/trunk/arch/arm/common/scoop.c b/trunk/arch/arm/common/scoop.c
index 32924c6714fe..0c3cbd9a388b 100644
--- a/trunk/arch/arm/common/scoop.c
+++ b/trunk/arch/arm/common/scoop.c
@@ -153,7 +153,7 @@ int __init scoop_probe(struct platform_device *pdev)
printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
- reset_scoop(dev);
+ reset_scoop(&pdev->dev);
SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
diff --git a/trunk/arch/arm/kernel/apm.c b/trunk/arch/arm/kernel/apm.c
index b0bbd1e62ebb..a2843be05557 100644
--- a/trunk/arch/arm/kernel/apm.c
+++ b/trunk/arch/arm/kernel/apm.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/arm/kernel/smp.c b/trunk/arch/arm/kernel/smp.c
index e55ea952f7aa..373c0959bc2f 100644
--- a/trunk/arch/arm/kernel/smp.c
+++ b/trunk/arch/arm/kernel/smp.c
@@ -256,9 +256,7 @@ void __cpuexit cpu_die(void)
asmlinkage void __cpuinit secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu;
-
- cpu = smp_processor_id();
+ unsigned int cpu = smp_processor_id();
printk("CPU%u: Booted secondary processor\n", cpu);
diff --git a/trunk/arch/arm/mach-footbridge/common.c b/trunk/arch/arm/mach-footbridge/common.c
index dc09fd200c16..bbe6e4a0bf6a 100644
--- a/trunk/arch/arm/mach-footbridge/common.c
+++ b/trunk/arch/arm/mach-footbridge/common.c
@@ -132,14 +132,14 @@ void __init footbridge_init_irq(void)
static struct map_desc fb_common_io_desc[] __initdata = {
{
.virtual = ARMCSR_BASE,
- .pfn = DC21285_ARMCSR_BASE,
+ .pfn = __phys_to_pfn(DC21285_ARMCSR_BASE),
.length = ARMCSR_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = XBUS_BASE,
.pfn = __phys_to_pfn(0x40000000),
.length = XBUS_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}
};
@@ -153,28 +153,28 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = {
.virtual = PCIMEM_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_MEM),
.length = PCIMEM_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCICFG0_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG),
.length = PCICFG0_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCICFG1_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG),
.length = PCICFG1_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIIACK_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IACK),
.length = PCIIACK_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIO_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IO),
.length = PCIO_SIZE,
- .type = MT_DEVICE
- }
+ .type = MT_DEVICE,
+ },
#endif
};
@@ -187,13 +187,13 @@ static struct map_desc co285_io_desc[] __initdata = {
.virtual = PCIO_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IO),
.length = PCIO_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIMEM_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_MEM),
.length = PCIMEM_SIZE,
- .type = MT_DEVICE
- }
+ .type = MT_DEVICE,
+ },
#endif
};
diff --git a/trunk/arch/arm/mach-pxa/Kconfig b/trunk/arch/arm/mach-pxa/Kconfig
index e201aa9765b9..cd506646801a 100644
--- a/trunk/arch/arm/mach-pxa/Kconfig
+++ b/trunk/arch/arm/mach-pxa/Kconfig
@@ -72,6 +72,12 @@ config MACH_HUSKY
depends PXA_SHARPSL_25x
select PXA_SHARP_C7xx
+config MACH_AKITA
+ bool "Enable Sharp SL-1000 (Akita) Support"
+ depends PXA_SHARPSL_27x
+ select PXA_SHARP_Cxx00
+ select MACH_SPITZ
+
config MACH_SPITZ
bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
depends PXA_SHARPSL_27x
diff --git a/trunk/arch/arm/mach-pxa/Makefile b/trunk/arch/arm/mach-pxa/Makefile
index d210bd5032ce..32526a0a6f86 100644
--- a/trunk/arch/arm/mach-pxa/Makefile
+++ b/trunk/arch/arm/mach-pxa/Makefile
@@ -11,8 +11,9 @@ obj-$(CONFIG_PXA27x) += pxa27x.o
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o
-obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o
+obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o
+obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
+obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o
obj-$(CONFIG_MACH_POODLE) += poodle.o
obj-$(CONFIG_MACH_TOSA) += tosa.o
diff --git a/trunk/arch/arm/mach-pxa/akita-ioexp.c b/trunk/arch/arm/mach-pxa/akita-ioexp.c
new file mode 100644
index 000000000000..f6d73cc01f78
--- /dev/null
+++ b/trunk/arch/arm/mach-pxa/akita-ioexp.c
@@ -0,0 +1,223 @@
+/*
+ * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
+ * (uses a Maxim MAX7310 8 Port IO Expander)
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* MAX7310 Regiser Map */
+#define MAX7310_INPUT 0x00
+#define MAX7310_OUTPUT 0x01
+#define MAX7310_POLINV 0x02
+#define MAX7310_IODIR 0x03 /* 1 = Input, 0 = Output */
+#define MAX7310_TIMEOUT 0x04
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
+
+/* I2C Magic */
+I2C_CLIENT_INSMOD;
+
+static int max7310_write(struct i2c_client *client, int address, int data);
+static struct i2c_client max7310_template;
+static void akita_ioexp_work(void *private_);
+
+static struct device *akita_ioexp_device;
+static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
+DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL);
+
+
+/*
+ * MAX7310 Access
+ */
+static int max7310_config(struct device *dev, int iomode, int polarity)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ret = max7310_write(client, MAX7310_POLINV, polarity);
+ if (ret < 0)
+ return ret;
+ ret = max7310_write(client, MAX7310_IODIR, iomode);
+ return ret;
+}
+
+static int max7310_set_ouputs(struct device *dev, int outputs)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return max7310_write(client, MAX7310_OUTPUT, outputs);
+}
+
+/*
+ * I2C Functions
+ */
+static int max7310_write(struct i2c_client *client, int address, int value)
+{
+ u8 data[2];
+
+ data[0] = address & 0xff;
+ data[1] = value & 0xff;
+
+ if (i2c_master_send(client, data, 2) == 2)
+ return 0;
+ return -1;
+}
+
+static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *new_client;
+ int err;
+
+ if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+ return -ENOMEM;
+
+ max7310_template.adapter = adapter;
+ max7310_template.addr = address;
+
+ memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
+
+ if ((err = i2c_attach_client(new_client))) {
+ kfree(new_client);
+ return err;
+ }
+
+ max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
+ akita_ioexp_device = &new_client->dev;
+ schedule_work(&akita_ioexp);
+
+ return 0;
+}
+
+static int max7310_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, max7310_detect);
+}
+
+static int max7310_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ akita_ioexp_device = NULL;
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(client);
+ return 0;
+}
+
+static struct i2c_driver max7310_i2c_driver = {
+ .owner = THIS_MODULE,
+ .name = "akita-max7310",
+ .id = I2C_DRIVERID_AKITAIOEXP,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = max7310_attach_adapter,
+ .detach_client = max7310_detach_client,
+};
+
+static struct i2c_client max7310_template = {
+ name: "akita-max7310",
+ flags: I2C_CLIENT_ALLOW_USE,
+ driver: &max7310_i2c_driver,
+};
+
+void akita_set_ioexp(struct device *dev, unsigned char bit)
+{
+ ioexp_output_value |= bit;
+
+ if (akita_ioexp_device)
+ schedule_work(&akita_ioexp);
+ return;
+}
+
+void akita_reset_ioexp(struct device *dev, unsigned char bit)
+{
+ ioexp_output_value &= ~bit;
+
+ if (akita_ioexp_device)
+ schedule_work(&akita_ioexp);
+ return;
+}
+
+EXPORT_SYMBOL(akita_set_ioexp);
+EXPORT_SYMBOL(akita_reset_ioexp);
+
+static void akita_ioexp_work(void *private_)
+{
+ if (akita_ioexp_device)
+ max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
+}
+
+
+#ifdef CONFIG_PM
+static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ flush_scheduled_work();
+ return 0;
+}
+
+static int akita_ioexp_resume(struct platform_device *pdev)
+{
+ schedule_work(&akita_ioexp);
+ return 0;
+}
+#else
+#define akita_ioexp_suspend NULL
+#define akita_ioexp_resume NULL
+#endif
+
+static int __init akita_ioexp_probe(struct platform_device *pdev)
+{
+ return i2c_add_driver(&max7310_i2c_driver);
+}
+
+static int akita_ioexp_remove(struct platform_device *pdev)
+{
+ i2c_del_driver(&max7310_i2c_driver);
+ return 0;
+}
+
+static struct platform_driver akita_ioexp_driver = {
+ .probe = akita_ioexp_probe,
+ .remove = akita_ioexp_remove,
+ .suspend = akita_ioexp_suspend,
+ .resume = akita_ioexp_resume,
+ .driver = {
+ .name = "akita-ioexp",
+ },
+};
+
+static int __init akita_ioexp_init(void)
+{
+ return platform_driver_register(&akita_ioexp_driver);
+}
+
+static void __exit akita_ioexp_exit(void)
+{
+ platform_driver_unregister(&akita_ioexp_driver);
+}
+
+MODULE_AUTHOR("Richard Purdie ");
+MODULE_DESCRIPTION("Akita IO-Expander driver");
+MODULE_LICENSE("GPL");
+
+fs_initcall(akita_ioexp_init);
+module_exit(akita_ioexp_exit);
+
diff --git a/trunk/arch/arm/mach-pxa/corgi_pm.c b/trunk/arch/arm/mach-pxa/corgi_pm.c
new file mode 100644
index 000000000000..599be14754f9
--- /dev/null
+++ b/trunk/arch/arm/mach-pxa/corgi_pm.c
@@ -0,0 +1,228 @@
+/*
+ * Battery and Power Management code for the Sharp SL-C7xx
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include "sharpsl.h"
+
+static void corgi_charger_init(void)
+{
+ pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
+}
+
+static void corgi_charge_led(int val)
+{
+ if (val == SHARPSL_LED_ERROR) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+ } else if (val == SHARPSL_LED_ON) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+ GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ } else {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+ GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ }
+}
+
+static void corgi_measure_temp(int on)
+{
+ if (on)
+ GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+ else
+ GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+}
+
+static void corgi_charge(int on)
+{
+ if (on) {
+ if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) {
+ GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPSR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ } else {
+ GPSR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ }
+ } else {
+ GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ }
+}
+
+static void corgi_discharge(int on)
+{
+ if (on)
+ GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+ else
+ GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+}
+
+static void corgi_presuspend(void)
+{
+ int i;
+ unsigned long wakeup_mask;
+
+ /* charging , so CHARGE_ON bit is HIGH during OFF. */
+ if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON))
+ PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON);
+ else
+ PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON);
+
+ if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE))
+ PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ else
+ PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE);
+
+ if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN))
+ PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ else
+ PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN);
+
+ /* Resume on keyboard power key */
+ PGSR2 = (PGSR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(0);
+
+ wakeup_mask = GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) | GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_CHRG_FULL);
+
+ if (!machine_is_corgi())
+ wakeup_mask |= GPIO_bit(CORGI_GPIO_MAIN_BAT_LOW);
+
+ PWER = wakeup_mask | PWER_RTC;
+ PRER = wakeup_mask;
+ PFER = wakeup_mask;
+
+ for (i = 0; i <=15; i++) {
+ if (PRER & PFER & GPIO_bit(i)) {
+ if (GPLR0 & GPIO_bit(i) )
+ PRER &= ~GPIO_bit(i);
+ else
+ PFER &= ~GPIO_bit(i);
+ }
+ }
+}
+
+static void corgi_postsuspend(void)
+{
+}
+
+/*
+ * Check what brought us out of the suspend.
+ * Return: 0 to sleep, otherwise wake
+ */
+static int corgi_should_wakeup(unsigned int resume_on_alarm)
+{
+ int is_resume = 0;
+
+ dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR);
+
+ if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) {
+ if (STATUS_AC_IN()) {
+ /* charge on */
+ dev_dbg(sharpsl_pm.dev, "ac insert\n");
+ sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+ } else {
+ /* charge off */
+ dev_dbg(sharpsl_pm.dev, "ac remove\n");
+ CHARGE_LED_OFF();
+ CHARGE_OFF();
+ sharpsl_pm.charge_mode = CHRG_OFF;
+ }
+ }
+
+ if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL)))
+ dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n");
+
+ if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT))
+ is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT);
+
+ if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP))
+ is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP);
+
+ if (resume_on_alarm && (PEDR & PWER_RTC))
+ is_resume |= PWER_RTC;
+
+ dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+ return is_resume;
+}
+
+static unsigned long corgi_charger_wakeup(void)
+{
+ return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) );
+}
+
+static int corgi_acin_status(void)
+{
+ return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0);
+}
+
+static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
+ .init = corgi_charger_init,
+ .gpio_batlock = CORGI_GPIO_BAT_COVER,
+ .gpio_acin = CORGI_GPIO_AC_IN,
+ .gpio_batfull = CORGI_GPIO_CHRG_FULL,
+ .status_acin = corgi_acin_status,
+ .discharge = corgi_discharge,
+ .charge = corgi_charge,
+ .chargeled = corgi_charge_led,
+ .measure_temp = corgi_measure_temp,
+ .presuspend = corgi_presuspend,
+ .postsuspend = corgi_postsuspend,
+ .charger_wakeup = corgi_charger_wakeup,
+ .should_wakeup = corgi_should_wakeup,
+ .bat_levels = 40,
+ .bat_levels_noac = spitz_battery_levels_noac,
+ .bat_levels_acin = spitz_battery_levels_acin,
+ .status_high_acin = 188,
+ .status_low_acin = 178,
+ .status_high_noac = 185,
+ .status_low_noac = 175,
+};
+
+static struct platform_device *corgipm_device;
+
+static int __devinit corgipm_init(void)
+{
+ int ret;
+
+ corgipm_device = platform_device_alloc("sharpsl-pm", -1);
+ if (!corgipm_device)
+ return -ENOMEM;
+
+ corgipm_device->dev.platform_data = &corgi_pm_machinfo;
+ ret = platform_device_add(corgipm_device);
+
+ if (ret)
+ platform_device_put(corgipm_device);
+
+ return ret;
+}
+
+static void corgipm_exit(void)
+{
+ platform_device_unregister(corgipm_device);
+}
+
+module_init(corgipm_init);
+module_exit(corgipm_exit);
diff --git a/trunk/arch/arm/mach-pxa/sharpsl.h b/trunk/arch/arm/mach-pxa/sharpsl.h
index 4879c0f7da72..b0c40a1d6671 100644
--- a/trunk/arch/arm/mach-pxa/sharpsl.h
+++ b/trunk/arch/arm/mach-pxa/sharpsl.h
@@ -115,7 +115,7 @@ extern struct battery_thresh spitz_battery_levels_noac[];
#define CHARGE_LED_ERR() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR)
#define DISCHARGE_ON() sharpsl_pm.machinfo->discharge(1)
#define DISCHARGE_OFF() sharpsl_pm.machinfo->discharge(0)
-#define STATUS_AC_IN sharpsl_pm.machinfo->status_acin()
-#define STATUS_BATT_LOCKED READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
-#define STATUS_CHRG_FULL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
-#define STATUS_FATAL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
+#define STATUS_AC_IN() sharpsl_pm.machinfo->status_acin()
+#define STATUS_BATT_LOCKED() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
+#define STATUS_CHRG_FULL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
+#define STATUS_FATAL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
diff --git a/trunk/arch/arm/mach-pxa/sharpsl_pm.c b/trunk/arch/arm/mach-pxa/sharpsl_pm.c
index 6c9e871c53d8..c10be00fb526 100644
--- a/trunk/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/trunk/arch/arm/mach-pxa/sharpsl_pm.c
@@ -21,7 +21,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -45,15 +45,15 @@
#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD 10 /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */
#define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */
#define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */
#define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */
#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */
#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */
-#define SHARPSL_CHARGE_ON_JKVAD_HIGH 0x9b /* 6V */
-#define SHARPSL_CHARGE_ON_JKVAD_LOW 0x34 /* 2V */
+#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */
+#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */
#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */
#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */
@@ -160,9 +160,10 @@ struct battery_thresh spitz_battery_levels_noac[] = {
/*
* Prototypes
*/
-static int sharpsl_read_MainBattery(void);
+static int sharpsl_read_main_battery(void);
static int sharpsl_off_charge_battery(void);
-static int sharpsl_check_battery(int mode);
+static int sharpsl_check_battery_temp(void);
+static int sharpsl_check_battery_voltage(void);
static int sharpsl_ac_check(void);
static int sharpsl_fatal_check(void);
static int sharpsl_average_value(int ad);
@@ -228,7 +229,7 @@ static void sharpsl_battery_thread(void *private_)
if (!sharpsl_pm.machinfo)
return;
- sharpsl_pm.battstat.ac_status = (!(STATUS_AC_IN) ? APM_AC_OFFLINE : APM_AC_ONLINE);
+ sharpsl_pm.battstat.ac_status = (STATUS_AC_IN() ? APM_AC_ONLINE : APM_AC_OFFLINE);
/* Corgi cannot confirm when battery fully charged so periodically kick! */
if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON)
@@ -236,7 +237,7 @@ static void sharpsl_battery_thread(void *private_)
schedule_work(&toggle_charger);
while(1) {
- voltage = sharpsl_read_MainBattery();
+ voltage = sharpsl_read_main_battery();
if (voltage > 0) break;
if (i++ > 5) {
voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
@@ -317,10 +318,10 @@ static void sharpsl_charge_toggle(void *private_)
{
dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
- if (STATUS_AC_IN == 0) {
+ if (STATUS_AC_IN() == 0) {
sharpsl_charge_off();
return;
- } else if ((sharpsl_check_battery(1) < 0) || (sharpsl_ac_check() < 0)) {
+ } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
sharpsl_charge_error();
return;
}
@@ -335,7 +336,7 @@ static void sharpsl_charge_toggle(void *private_)
static void sharpsl_ac_timer(unsigned long data)
{
- int acin = STATUS_AC_IN;
+ int acin = STATUS_AC_IN();
dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
@@ -364,7 +365,7 @@ static void sharpsl_chrg_full_timer(unsigned long data)
sharpsl_pm.full_count++;
- if (STATUS_AC_IN == 0) {
+ if (STATUS_AC_IN() == 0) {
dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
if (sharpsl_pm.charge_mode == CHRG_ON)
sharpsl_charge_off();
@@ -399,12 +400,12 @@ static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp)
{
int is_fatal = 0;
- if (STATUS_BATT_LOCKED == 0) {
+ if (STATUS_BATT_LOCKED() == 0) {
dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
is_fatal = 1;
}
- if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL == 0)) {
+ if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL() == 0)) {
dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
is_fatal = 1;
}
@@ -461,12 +462,12 @@ static int read_max1111(int channel)
| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
}
-static int sharpsl_read_MainBattery(void)
+static int sharpsl_read_main_battery(void)
{
return read_max1111(BATT_AD);
}
-static int sharpsl_read_Temp(void)
+static int sharpsl_read_temp(void)
{
int temp;
@@ -480,7 +481,7 @@ static int sharpsl_read_Temp(void)
return temp;
}
-static int sharpsl_read_jkvad(void)
+static int sharpsl_read_acin(void)
{
return read_max1111(JK_VAD);
}
@@ -522,16 +523,14 @@ static int get_select_val(int *val)
return (sum/3);
}
-/* mode 0 - Check temperature and voltage
- * 1 - Check temperature only */
-static int sharpsl_check_battery(int mode)
+static int sharpsl_check_battery_temp(void)
{
int val, i, buff[5];
/* Check battery temperature */
for (i=0; i<5; i++) {
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
- buff[i] = sharpsl_read_Temp();
+ buff[i] = sharpsl_read_temp();
}
val = get_select_val(buff);
@@ -539,8 +538,13 @@ static int sharpsl_check_battery(int mode)
dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
if (val > SHARPSL_CHARGE_ON_TEMP)
return -1;
- if (mode == 1)
- return 0;
+
+ return 0;
+}
+
+static int sharpsl_check_battery_voltage(void)
+{
+ int val, i, buff[5];
/* disable charge, enable discharge */
CHARGE_OFF();
@@ -552,7 +556,7 @@ static int sharpsl_check_battery(int mode)
/* Check battery voltage */
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_MainBattery();
+ buff[i] = sharpsl_read_main_battery();
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
}
@@ -575,14 +579,14 @@ static int sharpsl_ac_check(void)
int temp, i, buff[5];
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_jkvad();
- mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD);
+ buff[i] = sharpsl_read_acin();
+ mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
}
temp = get_select_val(buff);
dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
- if ((temp > SHARPSL_CHARGE_ON_JKVAD_HIGH) || (temp < SHARPSL_CHARGE_ON_JKVAD_LOW)) {
+ if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) {
dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
return -1;
}
@@ -591,7 +595,7 @@ static int sharpsl_ac_check(void)
}
#ifdef CONFIG_PM
-static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
+static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
{
sharpsl_pm.flags |= SHARPSL_SUSPENDED;
flush_scheduled_work();
@@ -604,7 +608,7 @@ static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
return 0;
}
-static int sharpsl_pm_resume(struct device *dev)
+static int sharpsl_pm_resume(struct platform_device *pdev)
{
/* Clear the reset source indicators as they break the bootloader upon reboot */
RCSR = 0x0f;
@@ -622,7 +626,7 @@ static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable
dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
/* not charging and AC-IN! */
- if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN != 0)) {
+ if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN() != 0)) {
dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
sharpsl_pm.charge_mode = CHRG_OFF;
sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
@@ -671,7 +675,7 @@ static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enab
dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
}
- if ((STATUS_BATT_LOCKED == 0) || (sharpsl_fatal_check() < 0) )
+ if ((STATUS_BATT_LOCKED() == 0) || (sharpsl_fatal_check() < 0) )
{
dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
corgi_goto_sleep(alarm_time, alarm_enable, state);
@@ -711,7 +715,7 @@ static int sharpsl_fatal_check(void)
dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
/* Check AC-Adapter */
- acin = STATUS_AC_IN;
+ acin = STATUS_AC_IN();
if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
CHARGE_OFF();
@@ -725,7 +729,7 @@ static int sharpsl_fatal_check(void)
/* Check battery : check inserting battery ? */
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_MainBattery();
+ buff[i] = sharpsl_read_main_battery();
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
}
@@ -739,7 +743,7 @@ static int sharpsl_fatal_check(void)
}
temp = get_select_val(buff);
- dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_MainBattery());
+ dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_main_battery());
if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) ||
(!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT)))
@@ -771,7 +775,7 @@ static int sharpsl_off_charge_battery(void)
dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
/* AC Check */
- if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery(1) < 0))
+ if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
return sharpsl_off_charge_error();
/* Start Charging */
@@ -793,7 +797,7 @@ static int sharpsl_off_charge_battery(void)
dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
- if (sharpsl_check_battery(0) < 0)
+ if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
return sharpsl_off_charge_error();
CHARGE_OFF();
@@ -811,7 +815,7 @@ static int sharpsl_off_charge_battery(void)
/* Check for timeout */
if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
return 1;
- if (STATUS_CHRG_FULL) {
+ if (STATUS_CHRG_FULL()) {
dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n");
sharpsl_pm.full_count++;
CHARGE_OFF();
@@ -840,7 +844,7 @@ static int sharpsl_off_charge_battery(void)
sharpsl_pm.full_count++;
return 1;
}
- if (STATUS_CHRG_FULL) {
+ if (STATUS_CHRG_FULL()) {
dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
CHARGE_LED_OFF();
CHARGE_OFF();
@@ -886,13 +890,13 @@ static struct pm_ops sharpsl_pm_ops = {
.finish = pxa_pm_finish,
};
-static int __init sharpsl_pm_probe(struct device *dev)
+static int __init sharpsl_pm_probe(struct platform_device *pdev)
{
- if (!dev->platform_data)
+ if (!pdev->dev.platform_data)
return -EINVAL;
- sharpsl_pm.dev = dev;
- sharpsl_pm.machinfo = dev->platform_data;
+ sharpsl_pm.dev = &pdev->dev;
+ sharpsl_pm.machinfo = pdev->dev.platform_data;
sharpsl_pm.charge_mode = CHRG_OFF;
sharpsl_pm.flags = 0;
@@ -935,8 +939,8 @@ static int __init sharpsl_pm_probe(struct device *dev)
else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING);
}
- device_create_file(dev, &dev_attr_battery_percentage);
- device_create_file(dev, &dev_attr_battery_voltage);
+ device_create_file(&pdev->dev, &dev_attr_battery_percentage);
+ device_create_file(&pdev->dev, &dev_attr_battery_voltage);
apm_get_power_status = sharpsl_apm_get_power_status;
@@ -947,12 +951,12 @@ static int __init sharpsl_pm_probe(struct device *dev)
return 0;
}
-static int sharpsl_pm_remove(struct device *dev)
+static int sharpsl_pm_remove(struct platform_device *pdev)
{
pm_set_ops(NULL);
- device_remove_file(dev, &dev_attr_battery_percentage);
- device_remove_file(dev, &dev_attr_battery_voltage);
+ device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
+ device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
@@ -969,23 +973,24 @@ static int sharpsl_pm_remove(struct device *dev)
return 0;
}
-static struct device_driver sharpsl_pm_driver = {
- .name = "sharpsl-pm",
- .bus = &platform_bus_type,
+static struct platform_driver sharpsl_pm_driver = {
.probe = sharpsl_pm_probe,
.remove = sharpsl_pm_remove,
.suspend = sharpsl_pm_suspend,
.resume = sharpsl_pm_resume,
+ .driver = {
+ .name = "sharpsl-pm",
+ },
};
static int __devinit sharpsl_pm_init(void)
{
- return driver_register(&sharpsl_pm_driver);
+ return platform_driver_register(&sharpsl_pm_driver);
}
static void sharpsl_pm_exit(void)
{
- driver_unregister(&sharpsl_pm_driver);
+ platform_driver_unregister(&sharpsl_pm_driver);
}
late_initcall(sharpsl_pm_init);
diff --git a/trunk/arch/arm/mach-pxa/spitz.c b/trunk/arch/arm/mach-pxa/spitz.c
index 4e9a699ee428..2df1b56615b1 100644
--- a/trunk/arch/arm/mach-pxa/spitz.c
+++ b/trunk/arch/arm/mach-pxa/spitz.c
@@ -345,6 +345,16 @@ static void spitz_irda_transceiver_mode(struct device *dev, int mode)
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
}
+#ifdef CONFIG_MACH_AKITA
+static void akita_irda_transceiver_mode(struct device *dev, int mode)
+{
+ if (mode & IR_OFF)
+ akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+ else
+ akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+}
+#endif
+
static struct pxaficp_platform_data spitz_ficp_platform_data = {
.transceiver_cap = IR_SIRMODE | IR_OFF,
.transceiver_mode = spitz_irda_transceiver_mode,
@@ -417,6 +427,32 @@ static void __init spitz_init(void)
platform_device_register(&spitzscoop2_device);
}
+#ifdef CONFIG_MACH_AKITA
+/*
+ * Akita IO Expander
+ */
+struct platform_device akitaioexp_device = {
+ .name = "akita-ioexp",
+ .id = -1,
+};
+
+static void __init akita_init(void)
+{
+ spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode;
+
+ /* We just pretend the second element of the array doesn't exist */
+ spitz_pcmcia_config.num_devs = 1;
+ platform_scoop_config = &spitz_pcmcia_config;
+ spitz_bl_machinfo.set_bl_intensity = akita_bl_set_intensity;
+
+ platform_device_register(&akitaioexp_device);
+
+ spitzscoop_device.dev.parent = &akitaioexp_device.dev;
+ common_init();
+}
+#endif
+
+
static void __init fixup_spitz(struct machine_desc *desc,
struct tag *tags, char **cmdline, struct meminfo *mi)
{
@@ -452,3 +488,16 @@ MACHINE_START(BORZOI, "SHARP Borzoi")
.timer = &pxa_timer,
MACHINE_END
#endif
+
+#ifdef CONFIG_MACH_AKITA
+MACHINE_START(AKITA, "SHARP Akita")
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_spitz,
+ .map_io = pxa_map_io,
+ .init_irq = pxa_init_irq,
+ .init_machine = akita_init,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
diff --git a/trunk/arch/arm/mach-pxa/spitz_pm.c b/trunk/arch/arm/mach-pxa/spitz_pm.c
new file mode 100644
index 000000000000..3ce7486daa51
--- /dev/null
+++ b/trunk/arch/arm/mach-pxa/spitz_pm.c
@@ -0,0 +1,233 @@
+/*
+ * Battery and Power Management code for the Sharp SL-Cxx00
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include "sharpsl.h"
+
+static int spitz_last_ac_status;
+
+static void spitz_charger_init(void)
+{
+ pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN);
+ pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
+}
+
+static void spitz_charge_led(int val)
+{
+ if (val == SHARPSL_LED_ERROR) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+ } else if (val == SHARPSL_LED_ON) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+ } else {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+ }
+}
+
+static void spitz_measure_temp(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+}
+
+static void spitz_charge(int on)
+{
+ if (on) {
+ if (sharpsl_pm.flags & SHARPSL_SUSPENDED) {
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ } else {
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ }
+ } else {
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ }
+}
+
+static void spitz_discharge(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+}
+
+/* HACK - For unknown reasons, accurate voltage readings are only made with a load
+ on the power bus which the green led on spitz provides */
+static void spitz_discharge1(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+}
+
+static void spitz_presuspend(void)
+{
+ spitz_last_ac_status = STATUS_AC_IN();
+
+ /* GPIO Sleep Register */
+ PGSR0 = 0x00144018;
+ PGSR1 = 0x00EF0000;
+ if (machine_is_akita()) {
+ PGSR2 = 0x2121C000;
+ PGSR3 = 0x00600400;
+ } else {
+ PGSR2 = 0x0121C000;
+ PGSR3 = 0x00600000;
+ }
+
+ PGSR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+ PGSR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+ PGSR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+ PGSR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+ PGSR2 |= GPIO_bit(SPITZ_GPIO_KEY_STROBE0);
+
+ pxa_gpio_mode(GPIO18_RDY|GPIO_OUT | GPIO_DFLT_HIGH);
+
+ PRER = GPIO_bit(SPITZ_GPIO_KEY_INT);
+ PFER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+ PWER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET) | PWER_RTC;
+ PKWR = GPIO_bit(SPITZ_GPIO_SYNC) | GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+ PKSR = 0xffffffff; // clear
+
+ /* nRESET_OUT Disable */
+ PSLR |= PSLR_SL_ROD;
+
+ /* Clear reset status */
+ RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+
+ /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+ PCFR = PCFR_GPR_EN | PCFR_OPDE;
+}
+
+static void spitz_postsuspend(void)
+{
+ pxa_gpio_mode(GPIO18_RDY_MD);
+ pxa_gpio_mode(10 | GPIO_IN);
+}
+
+static int spitz_should_wakeup(unsigned int resume_on_alarm)
+{
+ int is_resume = 0;
+ int acin = STATUS_AC_IN();
+
+ if (spitz_last_ac_status != acin) {
+ if (acin) {
+ /* charge on */
+ sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+ dev_dbg(sharpsl_pm.dev, "AC Inserted\n");
+ } else {
+ /* charge off */
+ dev_dbg(sharpsl_pm.dev, "AC Removed\n");
+ CHARGE_LED_OFF();
+ CHARGE_OFF();
+ sharpsl_pm.charge_mode = CHRG_OFF;
+ }
+ spitz_last_ac_status = acin;
+ /* Return to suspend as this must be what we were woken for */
+ return 0;
+ }
+
+ if (PEDR & GPIO_bit(SPITZ_GPIO_KEY_INT))
+ is_resume |= GPIO_bit(SPITZ_GPIO_KEY_INT);
+
+ if (PKSR & GPIO_bit(SPITZ_GPIO_SYNC))
+ is_resume |= GPIO_bit(SPITZ_GPIO_SYNC);
+
+ if (resume_on_alarm && (PEDR & PWER_RTC))
+ is_resume |= PWER_RTC;
+
+ dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+ return is_resume;
+}
+
+static unsigned long spitz_charger_wakeup(void)
+{
+ return (~GPLR0 & GPIO_bit(SPITZ_GPIO_KEY_INT)) | (GPLR0 & GPIO_bit(SPITZ_GPIO_SYNC));
+}
+
+static int spitz_acin_status(void)
+{
+ return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
+}
+
+struct sharpsl_charger_machinfo spitz_pm_machinfo = {
+ .init = spitz_charger_init,
+ .gpio_batlock = SPITZ_GPIO_BAT_COVER,
+ .gpio_acin = SPITZ_GPIO_AC_IN,
+ .gpio_batfull = SPITZ_GPIO_CHRG_FULL,
+ .gpio_fatal = SPITZ_GPIO_FATAL_BAT,
+ .status_acin = spitz_acin_status,
+ .discharge = spitz_discharge,
+ .discharge1 = spitz_discharge1,
+ .charge = spitz_charge,
+ .chargeled = spitz_charge_led,
+ .measure_temp = spitz_measure_temp,
+ .presuspend = spitz_presuspend,
+ .postsuspend = spitz_postsuspend,
+ .charger_wakeup = spitz_charger_wakeup,
+ .should_wakeup = spitz_should_wakeup,
+ .bat_levels = 40,
+ .bat_levels_noac = spitz_battery_levels_noac,
+ .bat_levels_acin = spitz_battery_levels_acin,
+ .status_high_acin = 188,
+ .status_low_acin = 178,
+ .status_high_noac = 185,
+ .status_low_noac = 175,
+};
+
+static struct platform_device *spitzpm_device;
+
+static int __devinit spitzpm_init(void)
+{
+ int ret;
+
+ spitzpm_device = platform_device_alloc("sharpsl-pm", -1);
+ if (!spitzpm_device)
+ return -ENOMEM;
+
+ spitzpm_device->dev.platform_data = &spitz_pm_machinfo;
+ ret = platform_device_add(spitzpm_device);
+
+ if (ret)
+ platform_device_put(spitzpm_device);
+
+ return ret;
+}
+
+static void spitzpm_exit(void)
+{
+ platform_device_unregister(spitzpm_device);
+}
+
+module_init(spitzpm_init);
+module_exit(spitzpm_exit);
diff --git a/trunk/arch/frv/kernel/pm.c b/trunk/arch/frv/kernel/pm.c
index 1a1e8a119c3d..712c3c24c954 100644
--- a/trunk/arch/frv/kernel/pm.c
+++ b/trunk/arch/frv/kernel/pm.c
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/i386/Kconfig b/trunk/arch/i386/Kconfig
index dbf90ad6eac3..6004bb0795e0 100644
--- a/trunk/arch/i386/Kconfig
+++ b/trunk/arch/i386/Kconfig
@@ -699,7 +699,7 @@ depends on PM && !X86_VISWS
config APM
tristate "APM (Advanced Power Management) BIOS support"
- depends on PM
+ depends on PM && PM_LEGACY
---help---
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
diff --git a/trunk/arch/i386/kernel/apm.c b/trunk/arch/i386/kernel/apm.c
index 003548b8735f..1e60acbed3c1 100644
--- a/trunk/arch/i386/kernel/apm.c
+++ b/trunk/arch/i386/kernel/apm.c
@@ -218,6 +218,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/i386/kernel/cpu/intel.c b/trunk/arch/i386/kernel/cpu/intel.c
index 43601de0f633..c28d26fb5f24 100644
--- a/trunk/arch/i386/kernel/cpu/intel.c
+++ b/trunk/arch/i386/kernel/cpu/intel.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
@@ -264,5 +265,52 @@ __init int intel_cpu_init(void)
return 0;
}
+#ifndef CONFIG_X86_CMPXCHG
+unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
+{
+ u8 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u8 *)ptr;
+ if (prev == old)
+ *(u8 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u8);
+
+unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
+{
+ u16 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u16 *)ptr;
+ if (prev == old)
+ *(u16 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u16);
+
+unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
+{
+ u32 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u32 *)ptr;
+ if (prev == old)
+ *(u32 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u32);
+#endif
+
// arch_initcall(intel_cpu_init);
diff --git a/trunk/arch/i386/kernel/entry.S b/trunk/arch/i386/kernel/entry.S
index 9e24f7b207ee..e50b93155249 100644
--- a/trunk/arch/i386/kernel/entry.S
+++ b/trunk/arch/i386/kernel/entry.S
@@ -560,11 +560,10 @@ nmi_stack_fixup:
nmi_debug_stack_check:
cmpw $__KERNEL_CS,16(%esp)
jne nmi_stack_correct
- cmpl $debug - 1,(%esp)
- jle nmi_stack_correct
+ cmpl $debug,(%esp)
+ jb nmi_stack_correct
cmpl $debug_esp_fix_insn,(%esp)
- jle nmi_debug_stack_fixup
-nmi_debug_stack_fixup:
+ ja nmi_stack_correct
FIX_STACK(24,nmi_stack_correct, 1)
jmp nmi_stack_correct
diff --git a/trunk/arch/i386/kernel/timers/timer_pit.c b/trunk/arch/i386/kernel/timers/timer_pit.c
index e42e46d35159..b9b6bd56b9ba 100644
--- a/trunk/arch/i386/kernel/timers/timer_pit.c
+++ b/trunk/arch/i386/kernel/timers/timer_pit.c
@@ -25,8 +25,9 @@ static int __init init_pit(char* override)
{
/* check clock override */
if (override[0] && strncmp(override,"pit",3))
- printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
-
+ printk(KERN_ERR "Warning: clock= override failed. Defaulting "
+ "to PIT\n");
+ init_cpu_khz();
count_p = LATCH;
return 0;
}
diff --git a/trunk/arch/i386/mm/init.c b/trunk/arch/i386/mm/init.c
index 542d9298da5e..06e26f006238 100644
--- a/trunk/arch/i386/mm/init.c
+++ b/trunk/arch/i386/mm/init.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
@@ -267,7 +268,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-void __devinit free_new_highpage(struct page *page)
+static void __devinit free_new_highpage(struct page *page)
{
set_page_count(page, 1);
__free_page(page);
diff --git a/trunk/arch/m68k/fpsp040/skeleton.S b/trunk/arch/m68k/fpsp040/skeleton.S
index 9571a21d6ad4..a1629194e3fd 100644
--- a/trunk/arch/m68k/fpsp040/skeleton.S
+++ b/trunk/arch/m68k/fpsp040/skeleton.S
@@ -381,10 +381,8 @@ fpsp_done:
.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstb %curptr@(TASK_NEEDRESCHED)
- jne ret_from_exception | deliver signals,
- | reschedule etc..
- RESTORE_ALL
+ | deliver signals, reschedule etc..
+ jra ret_from_exception
|
| mem_write --- write to user or supervisor address space
diff --git a/trunk/arch/m68k/ifpsp060/iskeleton.S b/trunk/arch/m68k/ifpsp060/iskeleton.S
index 4ba2c74da93d..b2dbdf5ee309 100644
--- a/trunk/arch/m68k/ifpsp060/iskeleton.S
+++ b/trunk/arch/m68k/ifpsp060/iskeleton.S
@@ -75,10 +75,8 @@ _060_isp_done:
.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstb %curptr@(TASK_NEEDRESCHED)
- jne ret_from_exception | deliver signals,
- | reschedule etc..
- RESTORE_ALL
+ | deliver signals, reschedule etc..
+ jra ret_from_exception
|
| _060_real_chk():
diff --git a/trunk/arch/m68k/kernel/asm-offsets.c b/trunk/arch/m68k/kernel/asm-offsets.c
index cee3317b8665..c787c5ba9513 100644
--- a/trunk/arch/m68k/kernel/asm-offsets.c
+++ b/trunk/arch/m68k/kernel/asm-offsets.c
@@ -25,12 +25,8 @@ int main(void)
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
- DEFINE(TASK_WORK, offsetof(struct task_struct, thread.work));
- DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, thread.work.need_resched));
- DEFINE(TASK_SYSCALL_TRACE, offsetof(struct task_struct, thread.work.syscall_trace));
- DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, thread.work.sigpending));
- DEFINE(TASK_NOTIFY_RESUME, offsetof(struct task_struct, thread.work.notify_resume));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+ DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
@@ -45,6 +41,10 @@ int main(void)
DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+ /* offsets into the thread_info struct */
+ DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+ DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
/* offsets into the pt_regs */
DEFINE(PT_D0, offsetof(struct pt_regs, d0));
DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
diff --git a/trunk/arch/m68k/kernel/entry.S b/trunk/arch/m68k/kernel/entry.S
index 23ca60a45552..320fde05dc63 100644
--- a/trunk/arch/m68k/kernel/entry.S
+++ b/trunk/arch/m68k/kernel/entry.S
@@ -44,9 +44,7 @@
#include
-.globl system_call, buserr, trap
-.globl resume, ret_from_exception
-.globl ret_from_signal
+.globl system_call, buserr, trap, resume
.globl inthandler, sys_call_table
.globl sys_fork, sys_clone, sys_vfork
.globl ret_from_interrupt, bad_interrupt
@@ -58,7 +56,7 @@ ENTRY(buserr)
movel %sp,%sp@- | stack frame pointer argument
bsrl buserr_c
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
ENTRY(trap)
SAVE_ALL_INT
@@ -66,7 +64,7 @@ ENTRY(trap)
movel %sp,%sp@- | stack frame pointer argument
bsrl trap_c
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
| After a fork we jump here directly from resume,
| so that %d1 contains the previous task
@@ -75,30 +73,31 @@ ENTRY(ret_from_fork)
movel %d1,%sp@-
jsr schedule_tail
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
-badsys:
- movel #-ENOSYS,%sp@(PT_D0)
- jra ret_from_exception
-
-do_trace:
+do_trace_entry:
movel #-ENOSYS,%sp@(PT_D0) | needed for strace
subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
RESTORE_SWITCH_STACK
addql #4,%sp
- movel %sp@(PT_ORIG_D0),%d1
- movel #-ENOSYS,%d0
- cmpl #NR_syscalls,%d1
- jcc 1f
- jbsr @(sys_call_table,%d1:l:4)@(0)
-1: movel %d0,%sp@(PT_D0) | save the return value
- subql #4,%sp | dummy return address
+ movel %sp@(PT_ORIG_D0),%d0
+ cmpl #NR_syscalls,%d0
+ jcs syscall
+badsys:
+ movel #-ENOSYS,%sp@(PT_D0)
+ jra ret_from_syscall
+
+do_trace_exit:
+ subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
+ RESTORE_SWITCH_STACK
+ addql #4,%sp
+ jra .Lret_from_exception
-ret_from_signal:
+ENTRY(ret_from_signal)
RESTORE_SWITCH_STACK
addql #4,%sp
/* on 68040 complete pending writebacks if any */
@@ -111,7 +110,7 @@ ret_from_signal:
addql #4,%sp
1:
#endif
- jra ret_from_exception
+ jra .Lret_from_exception
ENTRY(system_call)
SAVE_ALL_SYS
@@ -120,30 +119,34 @@ ENTRY(system_call)
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
- tstb %curptr@(TASK_SYSCALL_TRACE)
- jne do_trace
+ | syscall trace?
+ tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)
+ jmi do_trace_entry
cmpl #NR_syscalls,%d0
jcc badsys
+syscall:
jbsr @(sys_call_table,%d0:l:4)@(0)
movel %d0,%sp@(PT_D0) | save the return value
-
+ret_from_syscall:
|oriw #0x0700,%sr
- movel %curptr@(TASK_WORK),%d0
+ movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
jne syscall_exit_work
1: RESTORE_ALL
syscall_exit_work:
btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 1b | if so, skip resched, signals
- tstw %d0
- jeq do_signal_return
- tstb %d0
- jne do_delayed_trace
-
+ lslw #1,%d0
+ jcs do_trace_exit
+ jmi do_delayed_trace
+ lslw #8,%d0
+ jmi do_signal_return
pea resume_userspace
- jmp schedule
+ jra schedule
+
-ret_from_exception:
+ENTRY(ret_from_exception)
+.Lret_from_exception:
btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 1f | if so, skip resched, signals
| only allow interrupts when we are really the last one on the
@@ -152,19 +155,18 @@ ret_from_exception:
andw #ALLOWINT,%sr
resume_userspace:
- movel %curptr@(TASK_WORK),%d0
- lsrl #8,%d0
+ moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
jne exit_work
1: RESTORE_ALL
exit_work:
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
- tstb %d0
- jeq do_signal_return
-
+ lslb #1,%d0
+ jmi do_signal_return
pea resume_userspace
- jmp schedule
+ jra schedule
+
do_signal_return:
|andw #ALLOWINT,%sr
@@ -254,7 +256,7 @@ ret_from_interrupt:
/* check if we need to do software interrupts */
tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING
- jeq ret_from_exception
+ jeq .Lret_from_exception
pea ret_from_exception
jra do_softirq
diff --git a/trunk/arch/m68k/kernel/ptrace.c b/trunk/arch/m68k/kernel/ptrace.c
index 7e54422685cf..540638ca81f9 100644
--- a/trunk/arch/m68k/kernel/ptrace.c
+++ b/trunk/arch/m68k/kernel/ptrace.c
@@ -109,7 +109,7 @@ static inline void singlestep_disable(struct task_struct *child)
{
unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 0;
+ clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
}
/*
@@ -118,7 +118,7 @@ static inline void singlestep_disable(struct task_struct *child)
void ptrace_disable(struct task_struct *child)
{
singlestep_disable(child);
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -198,9 +198,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
goto out_eio;
if (request == PTRACE_SYSCALL)
- child->thread.work.syscall_trace = ~0;
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
singlestep_disable(child);
wake_up_process(child);
@@ -223,10 +223,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (!valid_signal(data))
goto out_eio;
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 1;
+ set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
child->exit_code = data;
/* give it a chance to run. */
@@ -288,9 +288,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
asmlinkage void syscall_trace(void)
{
- if (!current->thread.work.delayed_trace &&
- !current->thread.work.syscall_trace)
- return;
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
/*
diff --git a/trunk/arch/mips/au1000/common/power.c b/trunk/arch/mips/au1000/common/power.c
index f85093b8d54d..f4926315fb68 100644
--- a/trunk/arch/mips/au1000/common/power.c
+++ b/trunk/arch/mips/au1000/common/power.c
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/mips/au1000/common/usbdev.c b/trunk/arch/mips/au1000/common/usbdev.c
index 0b21bed7ee55..2cab7629702c 100644
--- a/trunk/arch/mips/au1000/common/usbdev.c
+++ b/trunk/arch/mips/au1000/common/usbdev.c
@@ -348,7 +348,7 @@ endpoint_stall(endpoint_t * ep)
{
u32 cs;
- warn(__FUNCTION__);
+ warn("%s", __FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
@@ -360,7 +360,7 @@ endpoint_unstall(endpoint_t * ep)
{
u32 cs;
- warn(__FUNCTION__);
+ warn("%s", __FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile
index 5bc11bd36c1f..d41ad2e675db 100644
--- a/trunk/arch/powerpc/Makefile
+++ b/trunk/arch/powerpc/Makefile
@@ -187,7 +187,7 @@ archprepare: checkbin
# Temporary hack until we have migrated to asm-powerpc
include/asm: arch/$(ARCH)/include/asm
-arch/$(ARCH)/include/asm:
+arch/$(ARCH)/include/asm: FORCE
$(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi
$(Q)ln -fsn $(srctree)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm
diff --git a/trunk/arch/powerpc/configs/pseries_defconfig b/trunk/arch/powerpc/configs/pseries_defconfig
index 9f09dff9e11a..913962c1dae0 100644
--- a/trunk/arch/powerpc/configs/pseries_defconfig
+++ b/trunk/arch/powerpc/configs/pseries_defconfig
@@ -1,18 +1,33 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc4
-# Thu Oct 20 08:32:17 2005
+# Linux kernel version: 2.6.15-rc1
+# Mon Nov 14 15:27:00 2005
#
+CONFIG_PPC64=y
CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Processor support
+#
+# CONFIG_POWER4_ONLY is not set
+CONFIG_POWER3=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=128
#
# Code maturity level options
@@ -68,75 +83,103 @@ CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-CONFIG_SYSVIPC_COMPAT=y
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Platform support
#
-# CONFIG_PPC_ISERIES is not set
CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
CONFIG_PPC_PSERIES=y
-# CONFIG_PPC_BPA is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
-CONFIG_PPC=y
-CONFIG_PPC64=y
+# CONFIG_PPC_CELL is not set
CONFIG_PPC_OF=y
CONFIG_XICS=y
+# CONFIG_U3_DART is not set
CONFIG_MPIC=y
-CONFIG_ALTIVEC=y
-CONFIG_PPC_SPLPAR=y
-CONFIG_KEXEC=y
+CONFIG_PPC_RTAS=y
+CONFIG_RTAS_ERROR_LOGGING=y
+CONFIG_RTAS_PROC=y
+CONFIG_RTAS_FLASH=m
+# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
-# CONFIG_U3_DART is not set
-# CONFIG_BOOTX_TEXT is not set
-# CONFIG_POWER4_ONLY is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_BKL is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_IOMMU_VMERGE=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=128
+CONFIG_HOTPLUG_CPU=y
+CONFIG_KEXEC=y
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_PPC_SPLPAR=y
+CONFIG_EEH=y
+CONFIG_SCANLOG=m
+CONFIG_LPARCFG=y
+CONFIG_NUMA=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_NODES_SPAN_OTHER_NODES=y
-CONFIG_NUMA=y
+# CONFIG_PPC_64K_PAGES is not set
CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_PREEMPT_BKL is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_EEH=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_PPC_RTAS=y
-CONFIG_RTAS_PROC=y
-CONFIG_RTAS_FLASH=m
-CONFIG_SCANLOG=m
-CONFIG_LPARCFG=y
-CONFIG_SECCOMP=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_HOTPLUG_CPU=y
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
#
-# Bus Options
+# Bus options
#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_INDIRECT_PCI is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_LEGACY_PROC=y
@@ -156,6 +199,7 @@ CONFIG_HOTPLUG_PCI=m
# CONFIG_HOTPLUG_PCI_SHPC is not set
CONFIG_HOTPLUG_PCI_RPA=m
CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
+CONFIG_KERNEL_START=0xc000000000000000
#
# Networking
@@ -197,6 +241,10 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
@@ -299,6 +347,10 @@ CONFIG_LLC=y
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
CONFIG_NET_CLS_ROUTE=y
@@ -368,14 +420,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=65536
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -473,6 +517,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -559,6 +604,7 @@ CONFIG_DM_MULTIPATH_EMC=m
#
# Macintosh device drivers
#
+# CONFIG_WINDFARM is not set
#
# Network device support
@@ -645,7 +691,6 @@ CONFIG_IXGB=m
# CONFIG_IXGB_NAPI is not set
CONFIG_S2IO=m
# CONFIG_S2IO_NAPI is not set
-# CONFIG_2BUFF_MODE is not set
#
# Token Ring devices
@@ -674,6 +719,7 @@ CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
# CONFIG_NET_FC is not set
@@ -784,6 +830,8 @@ CONFIG_HVCS=m
#
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -801,6 +849,7 @@ CONFIG_MAX_RAW_DEVS=1024
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -852,6 +901,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -893,7 +943,6 @@ CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
CONFIG_FB_MACMODES=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
@@ -905,6 +954,7 @@ CONFIG_FB_OF=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
CONFIG_FB_MATROX=y
@@ -927,7 +977,6 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_CYBLA is not set
# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -936,6 +985,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
@@ -990,12 +1040,15 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
#
# USB Device Class drivers
#
-# CONFIG_USB_BLUETOOTH_TTY is not set
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
@@ -1106,6 +1159,7 @@ CONFIG_INFINIBAND_MTHCA=m
# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
CONFIG_INFINIBAND_IPOIB=m
# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+# CONFIG_INFINIBAND_SRP is not set
#
# SN Devices
@@ -1288,10 +1342,25 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
-# Profiling support
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Instrumentation Support
#
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+# CONFIG_KPROBES is not set
#
# Kernel hacking
@@ -1308,14 +1377,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_KPROBES is not set
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
-# CONFIG_PPCDBG is not set
CONFIG_IRQSTACKS=y
+# CONFIG_BOOTX_TEXT is not set
#
# Security options
@@ -1355,17 +1425,3 @@ CONFIG_CRYPTO_TEST=m
#
# Hardware crypto devices
#
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile
index 9a74b7ab03a4..046b4bf1f21e 100644
--- a/trunk/arch/powerpc/kernel/Makefile
+++ b/trunk/arch/powerpc/kernel/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_PPC_OF) += of_device.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64) := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS) += rtas.o $(rtaspci-y)
+obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y)
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c
index 4550eb4f4fbd..91538d2445bf 100644
--- a/trunk/arch/powerpc/kernel/asm-offsets.c
+++ b/trunk/arch/powerpc/kernel/asm-offsets.c
@@ -270,13 +270,15 @@ int main(void)
DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec));
DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec));
DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec));
+ DEFINE(TSPC64_TV_SEC, offsetof(struct timespec, tv_sec));
+ DEFINE(TSPC64_TV_NSEC, offsetof(struct timespec, tv_nsec));
DEFINE(TSPC32_TV_SEC, offsetof(struct compat_timespec, tv_sec));
DEFINE(TSPC32_TV_NSEC, offsetof(struct compat_timespec, tv_nsec));
#else
DEFINE(TVAL32_TV_SEC, offsetof(struct timeval, tv_sec));
DEFINE(TVAL32_TV_USEC, offsetof(struct timeval, tv_usec));
- DEFINE(TSPEC32_TV_SEC, offsetof(struct timespec, tv_sec));
- DEFINE(TSPEC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
+ DEFINE(TSPC32_TV_SEC, offsetof(struct timespec, tv_sec));
+ DEFINE(TSPC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
#endif
/* timeval/timezone offsets for use by vdso */
DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
diff --git a/trunk/arch/powerpc/kernel/head_fsl_booke.S b/trunk/arch/powerpc/kernel/head_fsl_booke.S
index 5063c603fad4..8d60fa99fc4b 100644
--- a/trunk/arch/powerpc/kernel/head_fsl_booke.S
+++ b/trunk/arch/powerpc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
* Copyright 2002-2004 MontaVista Software, Inc.
* PowerPC 44x support, Matt Porter
* Copyright 2004 Freescale Semiconductor, Inc
- * PowerPC e500 modifications, Kumar Gala
+ * PowerPC e500 modifications, Kumar Gala
*
* 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
diff --git a/trunk/arch/powerpc/kernel/rtas-rtc.c b/trunk/arch/powerpc/kernel/rtas-rtc.c
new file mode 100644
index 000000000000..7b948662704c
--- /dev/null
+++ b/trunk/arch/powerpc/kernel/rtas-rtc.c
@@ -0,0 +1,105 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define MAX_RTC_WAIT 5000 /* 5 sec */
+#define RTAS_CLOCK_BUSY (-2)
+unsigned long __init rtas_get_boot_time(void)
+{
+ int ret[8];
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ wait_time = rtas_extended_busy_delay_time(error);
+ /* This is boot time so we spin. */
+ udelay(wait_time*1000);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit()) {
+ printk(KERN_WARNING "error: reading the clock failed (%d)\n",
+ error);
+ return 0;
+ }
+
+ return mktime(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
+}
+
+/* NOTE: get_rtc_time will get an error if executed in interrupt context
+ * and if a delay is needed to read the clock. In this case we just
+ * silently return without updating rtc_tm.
+ */
+void rtas_get_rtc_time(struct rtc_time *rtc_tm)
+{
+ int ret[8];
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ if (in_interrupt() && printk_ratelimit()) {
+ memset(&rtc_tm, 0, sizeof(struct rtc_time));
+ printk(KERN_WARNING "error: reading clock"
+ " would delay interrupt\n");
+ return; /* delay not allowed */
+ }
+ wait_time = rtas_extended_busy_delay_time(error);
+ msleep(wait_time);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit()) {
+ printk(KERN_WARNING "error: reading the clock failed (%d)\n",
+ error);
+ return;
+ }
+
+ rtc_tm->tm_sec = ret[5];
+ rtc_tm->tm_min = ret[4];
+ rtc_tm->tm_hour = ret[3];
+ rtc_tm->tm_mday = ret[2];
+ rtc_tm->tm_mon = ret[1] - 1;
+ rtc_tm->tm_year = ret[0] - 1900;
+}
+
+int rtas_set_rtc_time(struct rtc_time *tm)
+{
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
+ tm->tm_year + 1900, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec, 0);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ if (in_interrupt())
+ return 1; /* probably decrementer */
+ wait_time = rtas_extended_busy_delay_time(error);
+ msleep(wait_time);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit())
+ printk(KERN_WARNING "error: setting the clock failed (%d)\n",
+ error);
+
+ return 0;
+}
diff --git a/trunk/arch/powerpc/kernel/setup_64.c b/trunk/arch/powerpc/kernel/setup_64.c
index fdbd9f9122f2..608fee7c7e20 100644
--- a/trunk/arch/powerpc/kernel/setup_64.c
+++ b/trunk/arch/powerpc/kernel/setup_64.c
@@ -59,6 +59,7 @@
#include
#include
#include
+#include
#include "setup.h"
@@ -415,6 +416,10 @@ void __init setup_system(void)
*/
unflatten_device_tree();
+#ifdef CONFIG_KEXEC
+ kexec_setup(); /* requires unflattened device tree. */
+#endif
+
/*
* Fill the ppc64_caches & systemcfg structures with informations
* retreived from the device-tree. Need to be called before
diff --git a/trunk/arch/powerpc/kernel/vdso32/datapage.S b/trunk/arch/powerpc/kernel/vdso32/datapage.S
index a08c26e87835..f6b38472318d 100644
--- a/trunk/arch/powerpc/kernel/vdso32/datapage.S
+++ b/trunk/arch/powerpc/kernel/vdso32/datapage.S
@@ -77,8 +77,9 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
mflr r12
.cfi_register lr,r12
bl __get_datapage@local
- lwz r3,CFG_TB_TICKS_PER_SEC(r3)
lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3)
+ lwz r3,CFG_TB_TICKS_PER_SEC(r3)
mtlr r12
+ blr
.cfi_endproc
V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/trunk/arch/powerpc/kernel/vdso32/gettimeofday.S b/trunk/arch/powerpc/kernel/vdso32/gettimeofday.S
index aeb5fc9b87b3..0a32a41d50b0 100644
--- a/trunk/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/trunk/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -83,7 +83,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
/* Check for supported clock IDs */
cmpli cr0,r3,CLOCK_REALTIME
cmpli cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
mflr r12 /* r12 saves lr */
@@ -91,7 +91,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
mr r10,r3 /* r10 saves id */
mr r11,r4 /* r11 saves tp */
bl __get_datapage@local /* get data page */
- mr r9, r3 /* datapage ptr in r9 */
+ mr r9,r3 /* datapage ptr in r9 */
beq cr1,50f /* if monotonic -> jump there */
/*
@@ -173,10 +173,14 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
add r4,r4,r7
lis r5,NSEC_PER_SEC@h
ori r5,r5,NSEC_PER_SEC@l
- cmpli cr0,r4,r5
+ cmpl cr0,r4,r5
+ cmpli cr1,r4,0
blt 1f
subf r4,r5,r4
addi r3,r3,1
+1: bge cr1,1f
+ addi r3,r3,-1
+ add r4,r4,r5
1: stw r3,TSPC32_TV_SEC(r11)
stw r4,TSPC32_TV_NSEC(r11)
@@ -210,7 +214,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
li r3,0
diff --git a/trunk/arch/powerpc/kernel/vdso64/datapage.S b/trunk/arch/powerpc/kernel/vdso64/datapage.S
index e67eda0f8cda..6393e4137bc7 100644
--- a/trunk/arch/powerpc/kernel/vdso64/datapage.S
+++ b/trunk/arch/powerpc/kernel/vdso64/datapage.S
@@ -80,5 +80,6 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
bl V_LOCAL_FUNC(__get_datapage)
ld r3,CFG_TB_TICKS_PER_SEC(r3)
mtlr r12
+ blr
.cfi_endproc
V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/trunk/arch/powerpc/kernel/vdso64/gettimeofday.S b/trunk/arch/powerpc/kernel/vdso64/gettimeofday.S
index d371c02a8c0e..1a89094715cc 100644
--- a/trunk/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/trunk/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -1,4 +1,5 @@
-/*
+
+ /*
* Userland implementation of gettimeofday() for 64 bits processes in a
* ppc64 kernel for use in the vDSO
*
@@ -68,7 +69,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
mflr r12 /* r12 saves lr */
@@ -84,16 +85,17 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
- lis r7,0x3b9a /* r7 = 1000000000 = NSEC_PER_SEC */
- ori r7,r7,0xca00
+ lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
+ ori r7,r7,16960
rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
std r5,TSPC64_TV_SEC(r11) /* store sec in tv */
subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
- mulld r0,r0,r7 /* nsec = (xsec * NSEC_PER_SEC) /
+ mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
* XSEC_PER_SEC
*/
rldicl r0,r0,44,20
+ mulli r0,r0,1000 /* nsec = usec * 1000 */
std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */
mtlr r12
@@ -106,15 +108,16 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
- lis r7,0x3b9a /* r7 = 1000000000 = NSEC_PER_SEC */
- ori r7,r7,0xca00
+ lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
+ ori r7,r7,16960
rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
- mulld r0,r0,r7 /* nsec = (xsec * NSEC_PER_SEC) /
+ mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
* XSEC_PER_SEC
*/
rldicl r6,r0,44,20
+ mulli r6,r6,1000 /* nsec = usec * 1000 */
/* now we must fixup using wall to monotonic. We need to snapshot
* that value and do the counter trick again. Fortunately, we still
@@ -123,8 +126,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
* can be used
*/
- lwz r4,WTOM_CLOCK_SEC(r9)
- lwz r7,WTOM_CLOCK_NSEC(r9)
+ lwa r4,WTOM_CLOCK_SEC(r3)
+ lwa r7,WTOM_CLOCK_NSEC(r3)
/* We now have our result in r4,r7. We create a fake dependency
* on that result and re-check the counter
@@ -144,10 +147,14 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
add r7,r7,r6
lis r9,NSEC_PER_SEC@h
ori r9,r9,NSEC_PER_SEC@l
- cmpli cr0,r7,r9
+ cmpl cr0,r7,r9
+ cmpli cr1,r7,0
blt 1f
subf r7,r9,r7
addi r4,r4,1
+1: bge cr1,1f
+ addi r4,r4,-1
+ add r7,r7,r9
1: std r4,TSPC64_TV_SEC(r11)
std r7,TSPC64_TV_NSEC(r11)
@@ -181,7 +188,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
li r3,0
diff --git a/trunk/arch/powerpc/mm/fsl_booke_mmu.c b/trunk/arch/powerpc/mm/fsl_booke_mmu.c
index af9ca0eb6d55..5d581bb3aa12 100644
--- a/trunk/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/trunk/arch/powerpc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
/*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
* E500 Book E processors.
*
* Copyright 2004 Freescale Semiconductor, Inc
diff --git a/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c b/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
index 86124a94c9af..26539cda6023 100644
--- a/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/trunk/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -7,7 +7,7 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/trunk/arch/powerpc/platforms/powermac/time.c b/trunk/arch/powerpc/platforms/powermac/time.c
index 5947b21a8588..b1714f9bd920 100644
--- a/trunk/arch/powerpc/platforms/powermac/time.c
+++ b/trunk/arch/powerpc/platforms/powermac/time.c
@@ -102,7 +102,7 @@ static unsigned long from_rtc_time(struct rtc_time *tm)
static unsigned long cuda_get_time(void)
{
struct adb_request req;
- unsigned long now;
+ unsigned int now;
if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
return 0;
@@ -113,7 +113,7 @@ static unsigned long cuda_get_time(void)
req.reply_len);
now = (req.reply[3] << 24) + (req.reply[4] << 16)
+ (req.reply[5] << 8) + req.reply[6];
- return now - RTC_OFFSET;
+ return ((unsigned long)now) - RTC_OFFSET;
}
#define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm))
@@ -146,7 +146,7 @@ static int cuda_set_rtc_time(struct rtc_time *tm)
static unsigned long pmu_get_time(void)
{
struct adb_request req;
- unsigned long now;
+ unsigned int now;
if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
return 0;
@@ -156,7 +156,7 @@ static unsigned long pmu_get_time(void)
req.reply_len);
now = (req.reply[0] << 24) + (req.reply[1] << 16)
+ (req.reply[2] << 8) + req.reply[3];
- return now - RTC_OFFSET;
+ return ((unsigned long)now) - RTC_OFFSET;
}
#define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm))
@@ -199,7 +199,7 @@ static unsigned long smu_get_time(void)
#define smu_set_rtc_time(tm, spin) 0
#endif
-unsigned long pmac_get_boot_time(void)
+unsigned long __init pmac_get_boot_time(void)
{
/* Get the time from the RTC, used only at boot time */
switch (sys_ctrler) {
diff --git a/trunk/arch/powerpc/platforms/pseries/setup.c b/trunk/arch/powerpc/platforms/pseries/setup.c
index 31990829310c..b9d9732b2e06 100644
--- a/trunk/arch/powerpc/platforms/pseries/setup.c
+++ b/trunk/arch/powerpc/platforms/pseries/setup.c
@@ -200,14 +200,12 @@ static void __init pSeries_setup_arch(void)
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
ppc_md.init_IRQ = pSeries_init_mpic;
ppc_md.get_irq = mpic_get_irq;
- ppc_md.cpu_irq_down = mpic_teardown_this_cpu;
/* Allocate the mpic now, so that find_and_init_phbs() can
* fill the ISUs */
pSeries_setup_mpic();
} else {
ppc_md.init_IRQ = xics_init_IRQ;
ppc_md.get_irq = xics_get_irq;
- ppc_md.cpu_irq_down = xics_teardown_cpu;
}
#ifdef CONFIG_SMP
@@ -595,6 +593,27 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus)
return PCI_PROBE_NORMAL;
}
+#ifdef CONFIG_KEXEC
+static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
+{
+ /* Don't risk a hypervisor call if we're crashing */
+ if (!crash_shutdown) {
+ unsigned long vpa = __pa(&get_paca()->lppaca);
+
+ if (unregister_vpa(hard_smp_processor_id(), vpa)) {
+ printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
+ "failed\n", smp_processor_id(),
+ hard_smp_processor_id());
+ }
+ }
+
+ if (ppc64_interrupt_controller == IC_OPEN_PIC)
+ mpic_teardown_this_cpu(secondary);
+ else
+ xics_teardown_cpu(secondary);
+}
+#endif
+
struct machdep_calls __initdata pSeries_md = {
.probe = pSeries_probe,
.setup_arch = pSeries_setup_arch,
@@ -617,4 +636,7 @@ struct machdep_calls __initdata pSeries_md = {
.check_legacy_ioport = pSeries_check_legacy_ioport,
.system_reset_exception = pSeries_system_reset_exception,
.machine_check_exception = pSeries_machine_check_exception,
+#ifdef CONFIG_KEXEC
+ .kexec_cpu_down = pseries_kexec_cpu_down,
+#endif
};
diff --git a/trunk/arch/powerpc/xmon/xmon.c b/trunk/arch/powerpc/xmon/xmon.c
index ef4356b29a97..c45a6ad5f3b7 100644
--- a/trunk/arch/powerpc/xmon/xmon.c
+++ b/trunk/arch/powerpc/xmon/xmon.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/trunk/arch/ppc/kernel/head_fsl_booke.S b/trunk/arch/ppc/kernel/head_fsl_booke.S
index 5063c603fad4..8d60fa99fc4b 100644
--- a/trunk/arch/ppc/kernel/head_fsl_booke.S
+++ b/trunk/arch/ppc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
* Copyright 2002-2004 MontaVista Software, Inc.
* PowerPC 44x support, Matt Porter
* Copyright 2004 Freescale Semiconductor, Inc
- * PowerPC e500 modifications, Kumar Gala
+ * PowerPC e500 modifications, Kumar Gala
*
* 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
diff --git a/trunk/arch/ppc/mm/fsl_booke_mmu.c b/trunk/arch/ppc/mm/fsl_booke_mmu.c
index af9ca0eb6d55..5d581bb3aa12 100644
--- a/trunk/arch/ppc/mm/fsl_booke_mmu.c
+++ b/trunk/arch/ppc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
/*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
* E500 Book E processors.
*
* Copyright 2004 Freescale Semiconductor, Inc
diff --git a/trunk/arch/ppc/platforms/83xx/mpc834x_sys.c b/trunk/arch/ppc/platforms/83xx/mpc834x_sys.c
index 98edc75f4105..04bdc39bf47b 100644
--- a/trunk/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/trunk/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -3,7 +3,7 @@
*
* MPC834x SYS board specific routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
@@ -73,12 +73,19 @@ mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
* A B C D
*/
{
- {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x11 */
- {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x12 */
- {PIRQD, PIRQA, PIRQB, PIRQC} /* idsel 0x13 */
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x11 */
+ {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x12 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* idsel 0x13 */
+ {0, 0, 0, 0},
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x15 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* idsel 0x16 */
+ {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x17 */
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* idsel 0x18 */
+ {0, 0, 0, 0}, /* idsel 0x19 */
+ {0, 0, 0, 0}, /* idsel 0x20 */
};
- const long min_idsel = 0x11, max_idsel = 0x13, irqs_per_slot = 4;
+ const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
diff --git a/trunk/arch/ppc/platforms/83xx/mpc834x_sys.h b/trunk/arch/ppc/platforms/83xx/mpc834x_sys.h
index 58e44c042535..2e514d316fb8 100644
--- a/trunk/arch/ppc/platforms/83xx/mpc834x_sys.h
+++ b/trunk/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -3,7 +3,7 @@
*
* MPC834X SYS common board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor, Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc8540_ads.c b/trunk/arch/ppc/platforms/85xx/mpc8540_ads.c
index 7e952c1228cb..c5cde97c6ef0 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/trunk/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -3,7 +3,7 @@
*
* MPC8540ADS board specific routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc8540_ads.h b/trunk/arch/ppc/platforms/85xx/mpc8540_ads.h
index 3d05d7c4a938..e48ca3a97397 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc8540_ads.h
+++ b/trunk/arch/ppc/platforms/85xx/mpc8540_ads.h
@@ -3,7 +3,7 @@
*
* MPC8540ADS board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc8555_cds.h b/trunk/arch/ppc/platforms/85xx/mpc8555_cds.h
index e0e75568bc57..1a8e6c67355d 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc8555_cds.h
+++ b/trunk/arch/ppc/platforms/85xx/mpc8555_cds.h
@@ -3,7 +3,7 @@
*
* MPC8555CDS board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc8560_ads.c b/trunk/arch/ppc/platforms/85xx/mpc8560_ads.c
index 208433f1e93a..8e39a5517092 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/trunk/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -3,7 +3,7 @@
*
* MPC8560ADS board specific routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc8560_ads.h b/trunk/arch/ppc/platforms/85xx/mpc8560_ads.h
index 7df885d73e9d..143ae7eefa7c 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc8560_ads.h
+++ b/trunk/arch/ppc/platforms/85xx/mpc8560_ads.h
@@ -3,7 +3,7 @@
*
* MPC8540ADS board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
index 16ad092d8a06..17ce48fe3503 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+++ b/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx ADS board common routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
index 84acf6e8d45e..7b26bcc5d10d 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+++ b/trunk/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
@@ -3,7 +3,7 @@
*
* MPC85XX ADS common board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index a21156967a5e..d8991b88dc9c 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx CDS board specific routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
index 12b292c6ae32..5b588cfd0e41 100644
--- a/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+++ b/trunk/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -3,7 +3,7 @@
*
* MPC85xx CDS board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/trunk/arch/ppc/platforms/85xx/sbc8560.c b/trunk/arch/ppc/platforms/85xx/sbc8560.c
index b4ee1707a836..45a5b81b4ed1 100644
--- a/trunk/arch/ppc/platforms/85xx/sbc8560.c
+++ b/trunk/arch/ppc/platforms/85xx/sbc8560.c
@@ -3,7 +3,7 @@
*
* Wind River SBC8560 board specific routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/platforms/pmac_feature.c b/trunk/arch/ppc/platforms/pmac_feature.c
index 58884a63ebdb..1e69b0593162 100644
--- a/trunk/arch/ppc/platforms/pmac_feature.c
+++ b/trunk/arch/ppc/platforms/pmac_feature.c
@@ -2317,6 +2317,14 @@ static struct pmac_mb_def pmac_mb_defs[] = {
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
},
+ { "PowerBook5,8", "PowerBook G4 15\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,9", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
{ "PowerBook6,1", "PowerBook G4 12\"",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
diff --git a/trunk/arch/ppc/platforms/pq2ads.c b/trunk/arch/ppc/platforms/pq2ads.c
index 6a1475c1e128..71c9fca1fe9b 100644
--- a/trunk/arch/ppc/platforms/pq2ads.c
+++ b/trunk/arch/ppc/platforms/pq2ads.c
@@ -3,7 +3,7 @@
*
* PQ2ADS platform support
*
- * Author: Kumar Gala
+ * Author: Kumar Gala
* Derived from: est8260_setup.c by Allen Curtis
*
* Copyright 2004 Freescale Semiconductor, Inc.
diff --git a/trunk/arch/ppc/syslib/ipic.h b/trunk/arch/ppc/syslib/ipic.h
index 2b56a4fcf373..a7ce7da8785c 100644
--- a/trunk/arch/ppc/syslib/ipic.h
+++ b/trunk/arch/ppc/syslib/ipic.h
@@ -3,7 +3,7 @@
*
* IPIC private definitions and structure.
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor, Inc
*
diff --git a/trunk/arch/ppc/syslib/mpc83xx_devices.c b/trunk/arch/ppc/syslib/mpc83xx_devices.c
index f43fbf9a9389..847df4409982 100644
--- a/trunk/arch/ppc/syslib/mpc83xx_devices.c
+++ b/trunk/arch/ppc/syslib/mpc83xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC83xx Device descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/mpc83xx_sys.c b/trunk/arch/ppc/syslib/mpc83xx_sys.c
index da743446789b..a1523989aff4 100644
--- a/trunk/arch/ppc/syslib/mpc83xx_sys.c
+++ b/trunk/arch/ppc/syslib/mpc83xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC83xx System descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/mpc85xx_devices.c b/trunk/arch/ppc/syslib/mpc85xx_devices.c
index 2ede677a0a53..69949d255658 100644
--- a/trunk/arch/ppc/syslib/mpc85xx_devices.c
+++ b/trunk/arch/ppc/syslib/mpc85xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC85xx Device descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/mpc85xx_sys.c b/trunk/arch/ppc/syslib/mpc85xx_sys.c
index cb68d8c58348..397cfbcce5ea 100644
--- a/trunk/arch/ppc/syslib/mpc85xx_sys.c
+++ b/trunk/arch/ppc/syslib/mpc85xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC85xx System descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/mpc8xx_devices.c b/trunk/arch/ppc/syslib/mpc8xx_devices.c
index 2b5f0e701687..92dc98b36bde 100644
--- a/trunk/arch/ppc/syslib/mpc8xx_devices.c
+++ b/trunk/arch/ppc/syslib/mpc8xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC8xx Device descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug
*
diff --git a/trunk/arch/ppc/syslib/mpc8xx_sys.c b/trunk/arch/ppc/syslib/mpc8xx_sys.c
index 3cc27d29e3af..d3c617521603 100644
--- a/trunk/arch/ppc/syslib/mpc8xx_sys.c
+++ b/trunk/arch/ppc/syslib/mpc8xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC8xx System descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug
*
diff --git a/trunk/arch/ppc/syslib/ppc83xx_setup.c b/trunk/arch/ppc/syslib/ppc83xx_setup.c
index 4da168a6ad03..1b5fe9e398d4 100644
--- a/trunk/arch/ppc/syslib/ppc83xx_setup.c
+++ b/trunk/arch/ppc/syslib/ppc83xx_setup.c
@@ -3,7 +3,7 @@
*
* MPC83XX common board code
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc83xx_setup.h b/trunk/arch/ppc/syslib/ppc83xx_setup.h
index c766c1a5f786..a122a7322e5e 100644
--- a/trunk/arch/ppc/syslib/ppc83xx_setup.h
+++ b/trunk/arch/ppc/syslib/ppc83xx_setup.h
@@ -3,7 +3,7 @@
*
* MPC83XX common board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc85xx_common.c b/trunk/arch/ppc/syslib/ppc85xx_common.c
index da841dacdc13..19ad537225e4 100644
--- a/trunk/arch/ppc/syslib/ppc85xx_common.c
+++ b/trunk/arch/ppc/syslib/ppc85xx_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx support routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc85xx_common.h b/trunk/arch/ppc/syslib/ppc85xx_common.h
index 2c8f304441bf..94edf32151dd 100644
--- a/trunk/arch/ppc/syslib/ppc85xx_common.h
+++ b/trunk/arch/ppc/syslib/ppc85xx_common.h
@@ -3,7 +3,7 @@
*
* MPC85xx support routines
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc85xx_setup.c b/trunk/arch/ppc/syslib/ppc85xx_setup.c
index de2f90576577..1a47ff4b831d 100644
--- a/trunk/arch/ppc/syslib/ppc85xx_setup.c
+++ b/trunk/arch/ppc/syslib/ppc85xx_setup.c
@@ -3,7 +3,7 @@
*
* MPC85XX common board code
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc85xx_setup.h b/trunk/arch/ppc/syslib/ppc85xx_setup.h
index 6e6cfe162faf..e340b0545fb5 100644
--- a/trunk/arch/ppc/syslib/ppc85xx_setup.h
+++ b/trunk/arch/ppc/syslib/ppc85xx_setup.h
@@ -3,7 +3,7 @@
*
* MPC85XX common board definitions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/trunk/arch/ppc/syslib/ppc_sys.c b/trunk/arch/ppc/syslib/ppc_sys.c
index 603f01190816..c0b93c4191ee 100644
--- a/trunk/arch/ppc/syslib/ppc_sys.c
+++ b/trunk/arch/ppc/syslib/ppc_sys.c
@@ -3,7 +3,7 @@
*
* PPC System library functions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
* Copyright 2005 MontaVista, Inc. by Vitaly Bordug
diff --git a/trunk/arch/ppc/syslib/pq2_devices.c b/trunk/arch/ppc/syslib/pq2_devices.c
index e960fe935325..6ff3aab82fc3 100644
--- a/trunk/arch/ppc/syslib/pq2_devices.c
+++ b/trunk/arch/ppc/syslib/pq2_devices.c
@@ -3,7 +3,7 @@
*
* PQ2 Device descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* 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
diff --git a/trunk/arch/ppc/syslib/pq2_sys.c b/trunk/arch/ppc/syslib/pq2_sys.c
index 7b6c9ebdb9e3..36d6e2179940 100644
--- a/trunk/arch/ppc/syslib/pq2_sys.c
+++ b/trunk/arch/ppc/syslib/pq2_sys.c
@@ -3,7 +3,7 @@
*
* PQ2 System descriptions
*
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* 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
diff --git a/trunk/arch/ppc64/kernel/Makefile b/trunk/arch/ppc64/kernel/Makefile
index dac4cc20fa93..d0edea503c49 100644
--- a/trunk/arch/ppc64/kernel/Makefile
+++ b/trunk/arch/ppc64/kernel/Makefile
@@ -13,7 +13,6 @@ endif
obj-y += idle.o dma.o \
align.o \
- rtc.o \
iommu.o
pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o
diff --git a/trunk/arch/ppc64/kernel/machine_kexec.c b/trunk/arch/ppc64/kernel/machine_kexec.c
index 07ea03598c00..97c51e452be7 100644
--- a/trunk/arch/ppc64/kernel/machine_kexec.c
+++ b/trunk/arch/ppc64/kernel/machine_kexec.c
@@ -185,8 +185,8 @@ void kexec_copy_flush(struct kimage *image)
*/
void kexec_smp_down(void *arg)
{
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(1);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 1);
local_irq_disable();
kexec_smp_wait();
@@ -233,8 +233,8 @@ static void kexec_prepare_cpus(void)
}
/* after we tell the others to go down */
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(0);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 0);
put_cpu();
@@ -255,8 +255,8 @@ static void kexec_prepare_cpus(void)
* UP to an SMP kernel.
*/
smp_release_cpus();
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(0);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 0);
local_irq_disable();
}
@@ -305,3 +305,54 @@ void machine_kexec(struct kimage *image)
ppc_md.hpte_clear_all);
/* NOTREACHED */
}
+
+/* Values we need to export to the second kernel via the device tree. */
+static unsigned long htab_base, htab_size, kernel_end;
+
+static struct property htab_base_prop = {
+ .name = "linux,htab-base",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&htab_base,
+};
+
+static struct property htab_size_prop = {
+ .name = "linux,htab-size",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&htab_size,
+};
+
+static struct property kernel_end_prop = {
+ .name = "linux,kernel-end",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&kernel_end,
+};
+
+static void __init export_htab_values(void)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_path("/chosen");
+ if (!node)
+ return;
+
+ kernel_end = __pa(_end);
+ prom_add_property(node, &kernel_end_prop);
+
+ /* On machines with no htab htab_address is NULL */
+ if (NULL == htab_address)
+ goto out;
+
+ htab_base = __pa(htab_address);
+ prom_add_property(node, &htab_base_prop);
+
+ htab_size = 1UL << ppc64_pft_size;
+ prom_add_property(node, &htab_size_prop);
+
+ out:
+ of_node_put(node);
+}
+
+void __init kexec_setup(void)
+{
+ export_htab_values();
+}
diff --git a/trunk/arch/ppc64/kernel/prom.c b/trunk/arch/ppc64/kernel/prom.c
index fbad2c360784..47cc26e78957 100644
--- a/trunk/arch/ppc64/kernel/prom.c
+++ b/trunk/arch/ppc64/kernel/prom.c
@@ -1261,6 +1261,7 @@ prom_n_addr_cells(struct device_node* np)
/* No #address-cells property for the root node, default to 1 */
return 1;
}
+EXPORT_SYMBOL_GPL(prom_n_addr_cells);
int
prom_n_size_cells(struct device_node* np)
@@ -1276,6 +1277,7 @@ prom_n_size_cells(struct device_node* np)
/* No #size-cells property for the root node, default to 1 */
return 1;
}
+EXPORT_SYMBOL_GPL(prom_n_size_cells);
/**
* Work out the sense (active-low level / active-high edge)
diff --git a/trunk/arch/ppc64/kernel/rtc.c b/trunk/arch/ppc64/kernel/rtc.c
deleted file mode 100644
index 79e7ed2858dd..000000000000
--- a/trunk/arch/ppc64/kernel/rtc.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Real Time Clock interface for PPC64.
- *
- * Based on rtc.c by Paul Gortmaker
- *
- * This driver allows use of the real time clock
- * from user space. It exports the /dev/rtc
- * interface supporting various ioctl() and also the
- * /proc/driver/rtc pseudo-file for status information.
- *
- * Interface does not support RTC interrupts nor an alarm.
- *
- * 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.
- *
- * 1.0 Mike Corrigan: IBM iSeries rtc support
- * 1.1 Dave Engebretsen: IBM pSeries rtc support
- */
-
-#define RTC_VERSION "1.1"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-/*
- * We sponge a minor off of the misc major. No need slurping
- * up another valuable major dev number for this. If you add
- * an ioctl, make sure you don't conflict with SPARC's RTC
- * ioctls.
- */
-
-static ssize_t rtc_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos);
-
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-
-/*
- * If this driver ever becomes modularised, it will be really nice
- * to make the epoch retain its value across module reload...
- */
-
-static unsigned long epoch = 1900; /* year corresponding to 0x00 */
-
-static const unsigned char days_in_mo[] =
-{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-/*
- * Now all the various file operations that we export.
- */
-
-static ssize_t rtc_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return -EIO;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct rtc_time wtime;
-
- switch (cmd) {
- case RTC_RD_TIME: /* Read the time/date from RTC */
- {
- memset(&wtime, 0, sizeof(struct rtc_time));
- ppc_md.get_rtc_time(&wtime);
- break;
- }
- case RTC_SET_TIME: /* Set the RTC */
- {
- struct rtc_time rtc_tm;
- unsigned char mon, day, hrs, min, sec, leap_yr;
- unsigned int yrs;
-
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg,
- sizeof(struct rtc_time)))
- return -EFAULT;
-
- yrs = rtc_tm.tm_year;
- mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
- day = rtc_tm.tm_mday;
- hrs = rtc_tm.tm_hour;
- min = rtc_tm.tm_min;
- sec = rtc_tm.tm_sec;
-
- if (yrs < 70)
- return -EINVAL;
-
- leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
-
- if ((mon > 12) || (day == 0))
- return -EINVAL;
-
- if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
- return -EINVAL;
-
- if ((hrs >= 24) || (min >= 60) || (sec >= 60))
- return -EINVAL;
-
- if ( yrs > 169 )
- return -EINVAL;
-
- ppc_md.set_rtc_time(&rtc_tm);
-
- return 0;
- }
- case RTC_EPOCH_READ: /* Read the epoch. */
- {
- return put_user (epoch, (unsigned long __user *)arg);
- }
- case RTC_EPOCH_SET: /* Set the epoch. */
- {
- /*
- * There were no RTC clocks before 1900.
- */
- if (arg < 1900)
- return -EINVAL;
-
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- epoch = arg;
- return 0;
- }
- default:
- return -EINVAL;
- }
- return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
- nonseekable_open(inode, file);
- return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-/*
- * The various file operations we support.
- */
-static struct file_operations rtc_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = rtc_read,
- .ioctl = rtc_ioctl,
- .open = rtc_open,
- .release = rtc_release,
-};
-
-static struct miscdevice rtc_dev = {
- .minor = RTC_MINOR,
- .name = "rtc",
- .fops = &rtc_fops
-};
-
-static int __init rtc_init(void)
-{
- int retval;
-
- retval = misc_register(&rtc_dev);
- if(retval < 0)
- return retval;
-
-#ifdef CONFIG_PROC_FS
- if (create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)
- == NULL) {
- misc_deregister(&rtc_dev);
- return -ENOMEM;
- }
-#endif
-
- printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n");
-
- return 0;
-}
-
-static void __exit rtc_exit (void)
-{
- remove_proc_entry ("driver/rtc", NULL);
- misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_init);
-module_exit(rtc_exit);
-
-/*
- * Info exported via "/proc/driver/rtc".
- */
-
-static int rtc_proc_output (char *buf)
-{
-
- char *p;
- struct rtc_time tm;
-
- p = buf;
-
- ppc_md.get_rtc_time(&tm);
-
- /*
- * There is no way to tell if the luser has the RTC set for local
- * time or for Universal Standard Time (GMT). Probably local though.
- */
- p += sprintf(p,
- "rtc_time\t: %02d:%02d:%02d\n"
- "rtc_date\t: %04d-%02d-%02d\n"
- "rtc_epoch\t: %04lu\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
-
- p += sprintf(p,
- "DST_enable\t: no\n"
- "BCD\t\t: yes\n"
- "24hr\t\t: yes\n" );
-
- return p - buf;
-}
-
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = rtc_proc_output (page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-}
-
-#ifdef CONFIG_PPC_RTAS
-#define MAX_RTC_WAIT 5000 /* 5 sec */
-#define RTAS_CLOCK_BUSY (-2)
-unsigned long rtas_get_boot_time(void)
-{
- int ret[8];
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- wait_time = rtas_extended_busy_delay_time(error);
- /* This is boot time so we spin. */
- udelay(wait_time*1000);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading the clock failed (%d)\n",
- error);
- return 0;
- }
-
- return mktime(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
-}
-
-/* NOTE: get_rtc_time will get an error if executed in interrupt context
- * and if a delay is needed to read the clock. In this case we just
- * silently return without updating rtc_tm.
- */
-void rtas_get_rtc_time(struct rtc_time *rtc_tm)
-{
- int ret[8];
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- if (in_interrupt() && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading clock would delay interrupt\n");
- return; /* delay not allowed */
- }
- wait_time = rtas_extended_busy_delay_time(error);
- msleep_interruptible(wait_time);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading the clock failed (%d)\n",
- error);
- return;
- }
-
- rtc_tm->tm_sec = ret[5];
- rtc_tm->tm_min = ret[4];
- rtc_tm->tm_hour = ret[3];
- rtc_tm->tm_mday = ret[2];
- rtc_tm->tm_mon = ret[1] - 1;
- rtc_tm->tm_year = ret[0] - 1900;
-}
-
-int rtas_set_rtc_time(struct rtc_time *tm)
-{
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
- tm->tm_year + 1900, tm->tm_mon + 1,
- tm->tm_mday, tm->tm_hour, tm->tm_min,
- tm->tm_sec, 0);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- if (in_interrupt())
- return 1; /* probably decrementer */
- wait_time = rtas_extended_busy_delay_time(error);
- msleep_interruptible(wait_time);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit())
- printk(KERN_WARNING "error: setting the clock failed (%d)\n",
- error);
-
- return 0;
-}
-#endif
diff --git a/trunk/arch/sparc/lib/atomic32.c b/trunk/arch/sparc/lib/atomic32.c
index 2e64e8c3e8e5..cb3cf0f22822 100644
--- a/trunk/arch/sparc/lib/atomic32.c
+++ b/trunk/arch/sparc/lib/atomic32.c
@@ -37,17 +37,43 @@ int __atomic_add_return(int i, atomic_t *v)
spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
return ret;
}
+EXPORT_SYMBOL(__atomic_add_return);
-void atomic_set(atomic_t *v, int i)
+int atomic_cmpxchg(atomic_t *v, int old, int new)
{
+ int ret;
unsigned long flags;
+
spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
- v->counter = i;
+ spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+ return ret;
+}
+
+int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+ spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+ return ret != u;
}
-EXPORT_SYMBOL(__atomic_add_return);
-EXPORT_SYMBOL(atomic_set);
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+/* Atomic operations are already serializing */
+void atomic_set(atomic_t *v, int i)
+{
+ unsigned long flags;
+ spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ v->counter = i;
+ spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+}
+EXPORT_SYMBOL(atomic_set);
diff --git a/trunk/arch/sparc/lib/bitext.c b/trunk/arch/sparc/lib/bitext.c
index 94b05e8c906c..2e168d16547f 100644
--- a/trunk/arch/sparc/lib/bitext.c
+++ b/trunk/arch/sparc/lib/bitext.c
@@ -10,6 +10,7 @@
*/
#include
+#include
#include
#include
diff --git a/trunk/arch/um/Kconfig b/trunk/arch/um/Kconfig
index 3b5f47c46907..563301fe5df8 100644
--- a/trunk/arch/um/Kconfig
+++ b/trunk/arch/um/Kconfig
@@ -7,7 +7,6 @@ config UML
bool
default y
-# XXX: does UM have a mmu/swap?
config MMU
bool
default y
@@ -36,12 +35,6 @@ config IRQ_RELEASE_METHOD
bool
default y
-menu "Host processor type and features"
-
-source "arch/i386/Kconfig.cpu"
-
-endmenu
-
menu "UML-specific options"
config MODE_TT
@@ -209,7 +202,8 @@ config MAGIC_SYSRQ
config SMP
bool "Symmetric multi-processing support (EXPERIMENTAL)"
default n
- depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN)
+ #SMP_BROKEN is for x86_64.
+ depends on MODE_TT && EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
help
This option enables UML SMP support.
It is NOT related to having a real SMP box. Not directly, at least.
diff --git a/trunk/arch/um/Kconfig.i386 b/trunk/arch/um/Kconfig.i386
index 5d92cacd56c6..c71b39a677aa 100644
--- a/trunk/arch/um/Kconfig.i386
+++ b/trunk/arch/um/Kconfig.i386
@@ -1,3 +1,9 @@
+menu "Host processor type and features"
+
+source "arch/i386/Kconfig.cpu"
+
+endmenu
+
config UML_X86
bool
default y
@@ -42,7 +48,3 @@ config ARCH_HAS_SC_SIGNALS
config ARCH_REUSE_HOST_VSYSCALL_AREA
bool
default y
-
-config X86_CMPXCHG
- bool
- default y
diff --git a/trunk/arch/um/Makefile-i386 b/trunk/arch/um/Makefile-i386
index 1f7dcb064aee..7a0e04e34bf9 100644
--- a/trunk/arch/um/Makefile-i386
+++ b/trunk/arch/um/Makefile-i386
@@ -35,4 +35,3 @@ cflags-y += $(call cc-option,-mpreferred-stack-boundary=2)
CFLAGS += $(cflags-y)
USER_CFLAGS += $(cflags-y)
-
diff --git a/trunk/arch/um/drivers/chan_kern.c b/trunk/arch/um/drivers/chan_kern.c
index 16e7dc89f61d..5b58fad45290 100644
--- a/trunk/arch/um/drivers/chan_kern.c
+++ b/trunk/arch/um/drivers/chan_kern.c
@@ -89,8 +89,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data)
return(-EIO);
}
-static int not_configged_console_write(int fd, const char *buf, int len,
- void *data)
+static int not_configged_console_write(int fd, const char *buf, int len)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
@@ -299,7 +298,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len)
chan = list_entry(ele, struct chan, list);
if(!chan->output || (chan->ops->console_write == NULL))
continue;
- n = chan->ops->console_write(chan->fd, buf, len, chan->data);
+ n = chan->ops->console_write(chan->fd, buf, len);
if(chan->primary) ret = n;
}
return(ret);
diff --git a/trunk/arch/um/drivers/chan_user.c b/trunk/arch/um/drivers/chan_user.c
index 1c55d5802489..5d50d4a44abf 100644
--- a/trunk/arch/um/drivers/chan_user.c
+++ b/trunk/arch/um/drivers/chan_user.c
@@ -20,7 +20,7 @@
#include "choose-mode.h"
#include "mode.h"
-int generic_console_write(int fd, const char *buf, int n, void *unused)
+int generic_console_write(int fd, const char *buf, int n)
{
struct termios save, new;
int err;
diff --git a/trunk/arch/um/drivers/daemon_user.c b/trunk/arch/um/drivers/daemon_user.c
index c1b03f7c1daa..1bb085b2824d 100644
--- a/trunk/arch/um/drivers/daemon_user.c
+++ b/trunk/arch/um/drivers/daemon_user.c
@@ -98,7 +98,7 @@ static int connect_to_switch(struct daemon_data *pri)
printk("daemon_open : control setup request failed, err = %d\n",
-n);
err = -ENOTCONN;
- goto out;
+ goto out_free;
}
n = os_read_file(pri->control, sun, sizeof(*sun));
@@ -106,12 +106,14 @@ static int connect_to_switch(struct daemon_data *pri)
printk("daemon_open : read of data socket failed, err = %d\n",
-n);
err = -ENOTCONN;
- goto out_close;
+ goto out_free;
}
pri->data_addr = sun;
return(fd);
+ out_free:
+ kfree(sun);
out_close:
os_close_file(fd);
out:
diff --git a/trunk/arch/um/drivers/fd.c b/trunk/arch/um/drivers/fd.c
index f0b888f66e05..3296e86a03a5 100644
--- a/trunk/arch/um/drivers/fd.c
+++ b/trunk/arch/um/drivers/fd.c
@@ -76,13 +76,6 @@ static void fd_close(int fd, void *d)
}
}
-static int fd_console_write(int fd, const char *buf, int n, void *d)
-{
- struct fd_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops fd_ops = {
.type = "fd",
.init = fd_init,
@@ -90,7 +83,7 @@ struct chan_ops fd_ops = {
.close = fd_close,
.read = generic_read,
.write = generic_write,
- .console_write = fd_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 1,
diff --git a/trunk/arch/um/drivers/mcast_user.c b/trunk/arch/um/drivers/mcast_user.c
index 5db136e2651c..afe85bfa66e0 100644
--- a/trunk/arch/um/drivers/mcast_user.c
+++ b/trunk/arch/um/drivers/mcast_user.c
@@ -54,7 +54,7 @@ static int mcast_open(void *data)
struct mcast_data *pri = data;
struct sockaddr_in *sin = pri->mcast_addr;
struct ip_mreq mreq;
- int fd, yes = 1, err = 0;
+ int fd, yes = 1, err = -EINVAL;
if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
@@ -63,40 +63,40 @@ static int mcast_open(void *data)
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0){
+ err = -errno;
printk("mcast_open : data socket failed, errno = %d\n",
errno);
- err = -errno;
goto out;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+ err = -errno;
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* set ttl according to config */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
sizeof(pri->ttl)) < 0) {
+ err = -errno;
printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* set LOOP, so data does get fed back to local sockets */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+ err = -errno;
printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
- printk("mcast_open : data bind failed, errno = %d\n", errno);
err = -errno;
+ printk("mcast_open : data bind failed, errno = %d\n", errno);
goto out_close;
}
@@ -105,22 +105,22 @@ static int mcast_open(void *data)
mreq.imr_interface.s_addr = 0;
if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
+ err = -errno;
printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
errno);
printk("There appears not to be a multicast-capable network "
"interface on the host.\n");
printk("eth0 should be configured in order to use the "
"multicast transport.\n");
- err = -errno;
- goto out_close;
+ goto out_close;
}
return fd;
out_close:
- os_close_file(fd);
+ os_close_file(fd);
out:
- return err;
+ return err;
}
static void mcast_close(int fd, void *data)
diff --git a/trunk/arch/um/drivers/port_user.c b/trunk/arch/um/drivers/port_user.c
index ed4a1a6c5d83..c43e8bb32502 100644
--- a/trunk/arch/um/drivers/port_user.c
+++ b/trunk/arch/um/drivers/port_user.c
@@ -100,13 +100,6 @@ static void port_close(int fd, void *d)
os_close_file(fd);
}
-static int port_console_write(int fd, const char *buf, int n, void *d)
-{
- struct port_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops port_ops = {
.type = "port",
.init = port_init,
@@ -114,7 +107,7 @@ struct chan_ops port_ops = {
.close = port_close,
.read = generic_read,
.write = generic_write,
- .console_write = port_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = port_free,
.winch = 1,
diff --git a/trunk/arch/um/drivers/pty.c b/trunk/arch/um/drivers/pty.c
index 0306a1b215b7..1c555c38de4d 100644
--- a/trunk/arch/um/drivers/pty.c
+++ b/trunk/arch/um/drivers/pty.c
@@ -118,13 +118,6 @@ static int pty_open(int input, int output, int primary, void *d,
return(fd);
}
-static int pty_console_write(int fd, const char *buf, int n, void *d)
-{
- struct pty_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops pty_ops = {
.type = "pty",
.init = pty_chan_init,
@@ -132,7 +125,7 @@ struct chan_ops pty_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = pty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
@@ -145,7 +138,7 @@ struct chan_ops pts_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = pty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
diff --git a/trunk/arch/um/drivers/tty.c b/trunk/arch/um/drivers/tty.c
index 6fbb670ee274..94c9265a4f2c 100644
--- a/trunk/arch/um/drivers/tty.c
+++ b/trunk/arch/um/drivers/tty.c
@@ -60,13 +60,6 @@ static int tty_open(int input, int output, int primary, void *d,
return(fd);
}
-static int tty_console_write(int fd, const char *buf, int n, void *d)
-{
- struct tty_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops tty_ops = {
.type = "tty",
.init = tty_chan_init,
@@ -74,7 +67,7 @@ struct chan_ops tty_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = tty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
diff --git a/trunk/arch/um/drivers/xterm.c b/trunk/arch/um/drivers/xterm.c
index b530f1a6540d..aaa636661043 100644
--- a/trunk/arch/um/drivers/xterm.c
+++ b/trunk/arch/um/drivers/xterm.c
@@ -194,13 +194,6 @@ static void xterm_free(void *d)
free(d);
}
-static int xterm_console_write(int fd, const char *buf, int n, void *d)
-{
- struct xterm_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops xterm_ops = {
.type = "xterm",
.init = xterm_init,
@@ -208,7 +201,7 @@ struct chan_ops xterm_ops = {
.close = xterm_close,
.read = generic_read,
.write = generic_write,
- .console_write = xterm_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = xterm_free,
.winch = 1,
diff --git a/trunk/arch/um/include/chan_user.h b/trunk/arch/um/include/chan_user.h
index f77d9aa4c164..659bb3cac32f 100644
--- a/trunk/arch/um/include/chan_user.h
+++ b/trunk/arch/um/include/chan_user.h
@@ -25,7 +25,7 @@ struct chan_ops {
void (*close)(int, void *);
int (*read)(int, char *, void *);
int (*write)(int, const char *, int, void *);
- int (*console_write)(int, const char *, int, void *);
+ int (*console_write)(int, const char *, int);
int (*window_size)(int, void *, unsigned short *, unsigned short *);
void (*free)(void *);
int winch;
@@ -37,7 +37,7 @@ extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
extern void generic_close(int fd, void *unused);
extern int generic_read(int fd, char *c_out, void *unused);
extern int generic_write(int fd, const char *buf, int n, void *unused);
-extern int generic_console_write(int fd, const char *buf, int n, void *state);
+extern int generic_console_write(int fd, const char *buf, int n);
extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
unsigned short *cols_out);
extern void generic_free(void *data);
diff --git a/trunk/arch/um/include/um_uaccess.h b/trunk/arch/um/include/um_uaccess.h
index 84c0868cd561..f8760a3f43b0 100644
--- a/trunk/arch/um/include/um_uaccess.h
+++ b/trunk/arch/um/include/um_uaccess.h
@@ -17,8 +17,25 @@
#include "uaccess-skas.h"
#endif
+#define __under_task_size(addr, size) \
+ (((unsigned long) (addr) < TASK_SIZE) && \
+ (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define __access_ok_vsyscall(type, addr, size) \
+ ((type == VERIFY_READ) && \
+ ((unsigned long) (addr) >= FIXADDR_USER_START) && \
+ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
+ ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))
+
+#define __addr_range_nowrap(addr, size) \
+ ((unsigned long) (addr) <= ((unsigned long) (addr) + (size)))
+
#define access_ok(type, addr, size) \
- CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
+ (__addr_range_nowrap(addr, size) && \
+ (__under_task_size(addr, size) || \
+ __access_ok_vsyscall(type, addr, size) || \
+ segment_eq(get_fs(), KERNEL_DS) || \
+ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)))
static inline int copy_from_user(void *to, const void __user *from, int n)
{
diff --git a/trunk/arch/um/kernel/skas/include/uaccess-skas.h b/trunk/arch/um/kernel/skas/include/uaccess-skas.h
index 7da0c2def0ef..f611f83ad4ff 100644
--- a/trunk/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/trunk/arch/um/kernel/skas/include/uaccess-skas.h
@@ -9,14 +9,8 @@
#include "asm/errno.h"
#include "asm/fixmap.h"
-#define access_ok_skas(type, addr, size) \
- ((segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) < TASK_SIZE) && \
- ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
- ((type == VERIFY_READ ) && \
- ((unsigned long) (addr) >= FIXADDR_USER_START) && \
- ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
- ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
+/* No SKAS-specific checking. */
+#define access_ok_skas(type, addr, size) 0
extern int copy_from_user_skas(void *to, const void __user *from, int n);
extern int copy_to_user_skas(void __user *to, const void *from, int n);
diff --git a/trunk/arch/um/kernel/skas/uaccess.c b/trunk/arch/um/kernel/skas/uaccess.c
index 75195281081e..a5a47528dec7 100644
--- a/trunk/arch/um/kernel/skas/uaccess.c
+++ b/trunk/arch/um/kernel/skas/uaccess.c
@@ -143,7 +143,7 @@ int copy_from_user_skas(void *to, const void __user *from, int n)
return(0);
}
- return(access_ok_skas(VERIFY_READ, from, n) ?
+ return(access_ok(VERIFY_READ, from, n) ?
buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
n);
}
@@ -164,7 +164,7 @@ int copy_to_user_skas(void __user *to, const void *from, int n)
return(0);
}
- return(access_ok_skas(VERIFY_WRITE, to, n) ?
+ return(access_ok(VERIFY_WRITE, to, n) ?
buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
n);
}
@@ -193,7 +193,7 @@ int strncpy_from_user_skas(char *dst, const char __user *src, int count)
return(strnlen(dst, count));
}
- if(!access_ok_skas(VERIFY_READ, src, 1))
+ if(!access_ok(VERIFY_READ, src, 1))
return(-EFAULT);
n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
@@ -221,7 +221,7 @@ int clear_user_skas(void __user *mem, int len)
return(0);
}
- return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+ return(access_ok(VERIFY_WRITE, mem, len) ?
buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
}
diff --git a/trunk/arch/um/kernel/trap_kern.c b/trunk/arch/um/kernel/trap_kern.c
index 95c8f8733baf..0d4c10a73607 100644
--- a/trunk/arch/um/kernel/trap_kern.c
+++ b/trunk/arch/um/kernel/trap_kern.c
@@ -95,7 +95,16 @@ int handle_page_fault(unsigned long address, unsigned long ip,
pte = pte_offset_kernel(pmd, address);
} while(!pte_present(*pte));
err = 0;
+ /* The below warning was added in place of
+ * pte_mkyoung(); if (is_write) pte_mkdirty();
+ * If it's triggered, we'd see normally a hang here (a clean pte is
+ * marked read-only to emulate the dirty bit).
+ * However, the generic code can mark a PTE writable but clean on a
+ * concurrent read fault, triggering this harmlessly. So comment it out.
+ */
+#if 0
WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
+#endif
flush_tlb_page(vma, address);
out:
up_read(&mm->mmap_sem);
diff --git a/trunk/arch/um/kernel/tt/include/uaccess-tt.h b/trunk/arch/um/kernel/tt/include/uaccess-tt.h
index dc2ebfa8c54f..b9bfe9c481c4 100644
--- a/trunk/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/trunk/arch/um/kernel/tt/include/uaccess-tt.h
@@ -19,19 +19,13 @@
extern unsigned long end_vm;
extern unsigned long uml_physmem;
-#define under_task_size(addr, size) \
- (((unsigned long) (addr) < TASK_SIZE) && \
- (((unsigned long) (addr) + (size)) < TASK_SIZE))
-
#define is_stack(addr, size) \
(((unsigned long) (addr) < STACK_TOP) && \
((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
(((unsigned long) (addr) + (size)) <= STACK_TOP))
#define access_ok_tt(type, addr, size) \
- ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
- (under_task_size(addr, size) || is_stack(addr, size))))
+ (is_stack(addr, size))
extern unsigned long get_fault_addr(void);
diff --git a/trunk/arch/um/kernel/tt/uaccess.c b/trunk/arch/um/kernel/tt/uaccess.c
index a72aa632972f..1cb60726567e 100644
--- a/trunk/arch/um/kernel/tt/uaccess.c
+++ b/trunk/arch/um/kernel/tt/uaccess.c
@@ -8,7 +8,7 @@
int copy_from_user_tt(void *to, const void __user *from, int n)
{
- if(!access_ok_tt(VERIFY_READ, from, n))
+ if(!access_ok(VERIFY_READ, from, n))
return(n);
return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr,
@@ -17,7 +17,7 @@ int copy_from_user_tt(void *to, const void __user *from, int n)
int copy_to_user_tt(void __user *to, const void *from, int n)
{
- if(!access_ok_tt(VERIFY_WRITE, to, n))
+ if(!access_ok(VERIFY_WRITE, to, n))
return(n);
return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr,
@@ -28,7 +28,7 @@ int strncpy_from_user_tt(char *dst, const char __user *src, int count)
{
int n;
- if(!access_ok_tt(VERIFY_READ, src, 1))
+ if(!access_ok(VERIFY_READ, src, 1))
return(-EFAULT);
n = __do_strncpy_from_user(dst, src, count,
@@ -47,7 +47,7 @@ int __clear_user_tt(void __user *mem, int len)
int clear_user_tt(void __user *mem, int len)
{
- if(!access_ok_tt(VERIFY_WRITE, mem, len))
+ if(!access_ok(VERIFY_WRITE, mem, len))
return(len);
return(__do_clear_user(mem, len, ¤t->thread.fault_addr,
diff --git a/trunk/arch/x86_64/kernel/i8259.c b/trunk/arch/x86_64/kernel/i8259.c
index c6c9791d77c1..a9368d4c4aba 100644
--- a/trunk/arch/x86_64/kernel/i8259.c
+++ b/trunk/arch/x86_64/kernel/i8259.c
@@ -515,7 +515,7 @@ void i8254_timer_resume(void)
}
static struct sysdev_class timer_sysclass = {
- set_kset_name("timer"),
+ set_kset_name("timer_pit"),
.resume = timer_resume,
};
diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c
index 6a4da417c16b..606f8733a776 100644
--- a/trunk/drivers/acpi/bus.c
+++ b/trunk/drivers/acpi/bus.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#ifdef CONFIG_X86
@@ -754,7 +755,7 @@ static int __init acpi_init(void)
result = acpi_bus_init();
if (!result) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
if (!PM_IS_ACTIVE())
pm_active = 1;
else {
diff --git a/trunk/drivers/base/firmware_class.c b/trunk/drivers/base/firmware_class.c
index 98f6c02d6790..59dacb6552c0 100644
--- a/trunk/drivers/base/firmware_class.c
+++ b/trunk/drivers/base/firmware_class.c
@@ -526,18 +526,23 @@ request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
+ int ret;
if (!arg) {
WARN_ON(1);
return 0;
}
daemonize("%s/%s", "firmware", fw_work->name);
- _request_firmware(&fw, fw_work->name, fw_work->device,
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->hotplug);
- fw_work->cont(fw, fw_work->context);
- release_firmware(fw);
+ if (ret < 0)
+ fw_work->cont(NULL, fw_work->context);
+ else {
+ fw_work->cont(fw, fw_work->context);
+ release_firmware(fw);
+ }
module_put(fw_work->module);
kfree(fw_work);
- return 0;
+ return ret;
}
/**
@@ -586,6 +591,8 @@ request_firmware_nowait(
if (ret < 0) {
fw_work->cont(NULL, fw_work->context);
+ module_put(fw_work->module);
+ kfree(fw_work);
return ret;
}
return 0;
diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c
index 59e5982a5db3..c0233efabeba 100644
--- a/trunk/drivers/block/pktcdvd.c
+++ b/trunk/drivers/block/pktcdvd.c
@@ -1188,7 +1188,7 @@ static void pkt_count_states(struct pktcdvd_device *pd, int *states)
struct packet_data *pkt;
int i;
- for (i = 0; i <= PACKET_NUM_STATES; i++)
+ for (i = 0; i < PACKET_NUM_STATES; i++)
states[i] = 0;
spin_lock(&pd->cdrw.active_list_lock);
diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig
index fdf4370db994..970f70d498f4 100644
--- a/trunk/drivers/char/Kconfig
+++ b/trunk/drivers/char/Kconfig
@@ -735,7 +735,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC32 && !SPARC64
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/trunk/drivers/char/agp/uninorth-agp.c b/trunk/drivers/char/agp/uninorth-agp.c
index c8255312b8c1..50947e38501a 100644
--- a/trunk/drivers/char/agp/uninorth-agp.c
+++ b/trunk/drivers/char/agp/uninorth-agp.c
@@ -557,6 +557,10 @@ static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
.device_id = PCI_DEVICE_ID_APPLE_U3H_AGP,
.chipset_name = "U3H",
},
+ {
+ .device_id = PCI_DEVICE_ID_APPLE_IPID2_AGP,
+ .chipset_name = "UniNorth/Intrepid2",
+ },
};
static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
diff --git a/trunk/drivers/char/pcmcia/Kconfig b/trunk/drivers/char/pcmcia/Kconfig
index d22bfdc13563..27c1179ee527 100644
--- a/trunk/drivers/char/pcmcia/Kconfig
+++ b/trunk/drivers/char/pcmcia/Kconfig
@@ -18,5 +18,29 @@ config SYNCLINK_CS
The module will be called synclinkmp. If you want to do that, say M
here.
+config CARDMAN_4000
+ tristate "Omnikey Cardman 4000 support"
+ depends on PCMCIA
+ help
+ Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
+ reader.
+
+ This kernel driver requires additional userspace support, either
+ by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
+ or via the cm4000 backend of OpenCT (http://www.opensc.com/).
+
+config CARDMAN_4040
+ tristate "Omnikey CardMan 4040 support"
+ depends on PCMCIA
+ help
+ Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard
+ reader.
+
+ This card is basically a USB CCID device connected to a FIFO
+ in I/O space. To use the kernel driver, you will need either the
+ PC/SC ifdhandler provided from the Omnikey homepage
+ (http://www.omnikey.com/), or a current development version of OpenCT
+ (http://www.opensc.org/).
+
endmenu
diff --git a/trunk/drivers/char/pcmcia/Makefile b/trunk/drivers/char/pcmcia/Makefile
index 1fcd4c591958..0aae20985d57 100644
--- a/trunk/drivers/char/pcmcia/Makefile
+++ b/trunk/drivers/char/pcmcia/Makefile
@@ -5,3 +5,5 @@
#
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
+obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
+obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
diff --git a/trunk/drivers/char/pcmcia/cm4000_cs.c b/trunk/drivers/char/pcmcia/cm4000_cs.c
new file mode 100644
index 000000000000..ef011ef5dc46
--- /dev/null
+++ b/trunk/drivers/char/pcmcia/cm4000_cs.c
@@ -0,0 +1,2078 @@
+ /*
+ * A driver for the PCMCIA Smartcard Reader "Omnikey CardMan Mobile 4000"
+ *
+ * cm4000_cs.c support.linux@omnikey.com
+ *
+ * Tue Oct 23 11:32:43 GMT 2001 herp - cleaned up header files
+ * Sun Jan 20 10:11:15 MET 2002 herp - added modversion header files
+ * Thu Nov 14 16:34:11 GMT 2002 mh - added PPS functionality
+ * Tue Nov 19 16:36:27 GMT 2002 mh - added SUSPEND/RESUME functionailty
+ * Wed Jul 28 12:55:01 CEST 2004 mh - kernel 2.6 adjustments
+ *
+ * current version: 2.4.0gm4
+ *
+ * (C) 2000,2001,2002,2003,2004 Omnikey AG
+ *
+ * (C) 2005 Harald Welte
+ * - Adhere to Kernel CodingStyle
+ * - Port to 2.6.13 "new" style PCMCIA
+ * - Check for copy_{from,to}_user return values
+ * - Use nonseekable_open()
+ *
+ * All rights reserved. Licensed under dual BSD/GPL license.
+ */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+/* #define ATR_CSUM */
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x) (&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { \
+ if (pc_debug >= (n)) \
+ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
+ __FUNCTION__ , ## args); \
+ } while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+static char *version = "cm4000_cs.c v2.4.0gm5 - All bugs added by Harald Welte";
+
+#define T_1SEC (HZ)
+#define T_10MSEC msecs_to_jiffies(10)
+#define T_20MSEC msecs_to_jiffies(20)
+#define T_40MSEC msecs_to_jiffies(40)
+#define T_50MSEC msecs_to_jiffies(50)
+#define T_100MSEC msecs_to_jiffies(100)
+#define T_500MSEC msecs_to_jiffies(500)
+
+static void cm4000_detach(dev_link_t *link);
+static void cm4000_release(dev_link_t *link);
+
+static int major; /* major number we get from the kernel */
+
+/* note: the first state has to have number 0 always */
+
+#define M_FETCH_ATR 0
+#define M_TIMEOUT_WAIT 1
+#define M_READ_ATR_LEN 2
+#define M_READ_ATR 3
+#define M_ATR_PRESENT 4
+#define M_BAD_CARD 5
+#define M_CARDOFF 6
+
+#define LOCK_IO 0
+#define LOCK_MONITOR 1
+
+#define IS_AUTOPPS_ACT 6
+#define IS_PROCBYTE_PRESENT 7
+#define IS_INVREV 8
+#define IS_ANY_T0 9
+#define IS_ANY_T1 10
+#define IS_ATR_PRESENT 11
+#define IS_ATR_VALID 12
+#define IS_CMM_ABSENT 13
+#define IS_BAD_LENGTH 14
+#define IS_BAD_CSUM 15
+#define IS_BAD_CARD 16
+
+#define REG_FLAGS0(x) (x + 0)
+#define REG_FLAGS1(x) (x + 1)
+#define REG_NUM_BYTES(x) (x + 2)
+#define REG_BUF_ADDR(x) (x + 3)
+#define REG_BUF_DATA(x) (x + 4)
+#define REG_NUM_SEND(x) (x + 5)
+#define REG_BAUDRATE(x) (x + 6)
+#define REG_STOPBITS(x) (x + 7)
+
+struct cm4000_dev {
+ dev_link_t link; /* pcmcia link */
+ dev_node_t node; /* OS node (major,minor) */
+
+ unsigned char atr[MAX_ATR];
+ unsigned char rbuf[512];
+ unsigned char sbuf[512];
+
+ wait_queue_head_t devq; /* when removing cardman must not be
+ zeroed! */
+
+ wait_queue_head_t ioq; /* if IO is locked, wait on this Q */
+ wait_queue_head_t atrq; /* wait for ATR valid */
+ wait_queue_head_t readq; /* used by write to wake blk.read */
+
+ /* warning: do not move this fields.
+ * initialising to zero depends on it - see ZERO_DEV below. */
+ unsigned char atr_csum;
+ unsigned char atr_len_retry;
+ unsigned short atr_len;
+ unsigned short rlen; /* bytes avail. after write */
+ unsigned short rpos; /* latest read pos. write zeroes */
+ unsigned char procbyte; /* T=0 procedure byte */
+ unsigned char mstate; /* state of card monitor */
+ unsigned char cwarn; /* slow down warning */
+ unsigned char flags0; /* cardman IO-flags 0 */
+ unsigned char flags1; /* cardman IO-flags 1 */
+ unsigned int mdelay; /* variable monitor speeds, in jiffies */
+
+ unsigned int baudv; /* baud value for speed */
+ unsigned char ta1;
+ unsigned char proto; /* T=0, T=1, ... */
+ unsigned long flags; /* lock+flags (MONITOR,IO,ATR) * for concurrent
+ access */
+
+ unsigned char pts[4];
+
+ struct timer_list timer; /* used to keep monitor running */
+ int monitor_running;
+};
+
+#define ZERO_DEV(dev) \
+ memset(&dev->atr_csum,0, \
+ sizeof(struct cm4000_dev) - \
+ /*link*/ sizeof(dev_link_t) - \
+ /*node*/ sizeof(dev_node_t) - \
+ /*atr*/ MAX_ATR*sizeof(char) - \
+ /*rbuf*/ 512*sizeof(char) - \
+ /*sbuf*/ 512*sizeof(char) - \
+ /*queue*/ 4*sizeof(wait_queue_head_t))
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM4000_MAX_DEV];
+
+/* This table doesn't use spaces after the comma between fields and thus
+ * violates CodingStyle. However, I don't really think wrapping it around will
+ * make it any clearer to read -HW */
+static unsigned char fi_di_table[10][14] = {
+/*FI 00 01 02 03 04 05 06 07 08 09 10 11 12 13 */
+/*DI */
+/* 0 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 1 */ {0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x91,0x11,0x11,0x11,0x11},
+/* 2 */ {0x02,0x12,0x22,0x32,0x11,0x11,0x11,0x11,0x11,0x92,0xA2,0xB2,0x11,0x11},
+/* 3 */ {0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x11,0x11,0x93,0xA3,0xB3,0xC3,0xD3},
+/* 4 */ {0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x11,0x11,0x94,0xA4,0xB4,0xC4,0xD4},
+/* 5 */ {0x00,0x15,0x25,0x35,0x45,0x55,0x65,0x11,0x11,0x95,0xA5,0xB5,0xC5,0xD5},
+/* 6 */ {0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x11,0x11,0x96,0xA6,0xB6,0xC6,0xD6},
+/* 7 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 8 */ {0x08,0x11,0x28,0x38,0x48,0x58,0x68,0x11,0x11,0x98,0xA8,0xB8,0xC8,0xD8},
+/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9}
+};
+
+#ifndef PCMCIA_DEBUG
+#define xoutb outb
+#define xinb inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ outb(val, port);
+}
+static inline unsigned char xinb(unsigned short port)
+{
+ unsigned char val;
+
+ val = inb(port);
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+
+ return val;
+}
+#endif
+
+#define b_0000 15
+#define b_0001 14
+#define b_0010 13
+#define b_0011 12
+#define b_0100 11
+#define b_0101 10
+#define b_0110 9
+#define b_0111 8
+#define b_1000 7
+#define b_1001 6
+#define b_1010 5
+#define b_1011 4
+#define b_1100 3
+#define b_1101 2
+#define b_1110 1
+#define b_1111 0
+
+static unsigned char irtab[16] = {
+ b_0000, b_1000, b_0100, b_1100,
+ b_0010, b_1010, b_0110, b_1110,
+ b_0001, b_1001, b_0101, b_1101,
+ b_0011, b_1011, b_0111, b_1111
+};
+
+static void str_invert_revert(unsigned char *b, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
+}
+
+static unsigned char invert_revert(unsigned char ch)
+{
+ return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+}
+
+#define ATRLENCK(dev,pos) \
+ if (pos>=dev->atr_len || pos>=MAX_ATR) \
+ goto return_0;
+
+static unsigned int calc_baudv(unsigned char fidi)
+{
+ unsigned int wcrcf, wbrcf, fi_rfu, di_rfu;
+
+ fi_rfu = 372;
+ di_rfu = 1;
+
+ /* FI */
+ switch ((fidi >> 4) & 0x0F) {
+ case 0x00:
+ wcrcf = 372;
+ break;
+ case 0x01:
+ wcrcf = 372;
+ break;
+ case 0x02:
+ wcrcf = 558;
+ break;
+ case 0x03:
+ wcrcf = 744;
+ break;
+ case 0x04:
+ wcrcf = 1116;
+ break;
+ case 0x05:
+ wcrcf = 1488;
+ break;
+ case 0x06:
+ wcrcf = 1860;
+ break;
+ case 0x07:
+ wcrcf = fi_rfu;
+ break;
+ case 0x08:
+ wcrcf = fi_rfu;
+ break;
+ case 0x09:
+ wcrcf = 512;
+ break;
+ case 0x0A:
+ wcrcf = 768;
+ break;
+ case 0x0B:
+ wcrcf = 1024;
+ break;
+ case 0x0C:
+ wcrcf = 1536;
+ break;
+ case 0x0D:
+ wcrcf = 2048;
+ break;
+ default:
+ wcrcf = fi_rfu;
+ break;
+ }
+
+ /* DI */
+ switch (fidi & 0x0F) {
+ case 0x00:
+ wbrcf = di_rfu;
+ break;
+ case 0x01:
+ wbrcf = 1;
+ break;
+ case 0x02:
+ wbrcf = 2;
+ break;
+ case 0x03:
+ wbrcf = 4;
+ break;
+ case 0x04:
+ wbrcf = 8;
+ break;
+ case 0x05:
+ wbrcf = 16;
+ break;
+ case 0x06:
+ wbrcf = 32;
+ break;
+ case 0x07:
+ wbrcf = di_rfu;
+ break;
+ case 0x08:
+ wbrcf = 12;
+ break;
+ case 0x09:
+ wbrcf = 20;
+ break;
+ default:
+ wbrcf = di_rfu;
+ break;
+ }
+
+ return (wcrcf / wbrcf);
+}
+
+static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+{
+ unsigned short tmp;
+
+ tmp = *s = 0;
+ do {
+ *s = tmp;
+ tmp = inb(REG_NUM_BYTES(iobase)) |
+ (inb(REG_FLAGS0(iobase)) & 4 ? 0x100 : 0);
+ } while (tmp != *s);
+
+ return *s;
+}
+
+static int parse_atr(struct cm4000_dev *dev)
+{
+ unsigned char any_t1, any_t0;
+ unsigned char ch, ifno;
+ int ix, done;
+
+ DEBUGP(3, dev, "-> parse_atr: dev->atr_len = %i\n", dev->atr_len);
+
+ if (dev->atr_len < 3) {
+ DEBUGP(5, dev, "parse_atr: atr_len < 3\n");
+ return 0;
+ }
+
+ if (dev->atr[0] == 0x3f)
+ set_bit(IS_INVREV, &dev->flags);
+ else
+ clear_bit(IS_INVREV, &dev->flags);
+ ix = 1;
+ ifno = 1;
+ ch = dev->atr[1];
+ dev->proto = 0; /* XXX PROTO */
+ any_t1 = any_t0 = done = 0;
+ dev->ta1 = 0x11; /* defaults to 9600 baud */
+ do {
+ if (ifno == 1 && (ch & 0x10)) {
+ /* read first interface byte and TA1 is present */
+ dev->ta1 = dev->atr[2];
+ DEBUGP(5, dev, "Card says FiDi is 0x%.2x\n", dev->ta1);
+ ifno++;
+ } else if ((ifno == 2) && (ch & 0x10)) { /* TA(2) */
+ dev->ta1 = 0x11;
+ ifno++;
+ }
+
+ DEBUGP(5, dev, "Yi=%.2x\n", ch & 0xf0);
+ ix += ((ch & 0x10) >> 4) /* no of int.face chars */
+ +((ch & 0x20) >> 5)
+ + ((ch & 0x40) >> 6)
+ + ((ch & 0x80) >> 7);
+ /* ATRLENCK(dev,ix); */
+ if (ch & 0x80) { /* TDi */
+ ch = dev->atr[ix];
+ if ((ch & 0x0f)) {
+ any_t1 = 1;
+ DEBUGP(5, dev, "card is capable of T=1\n");
+ } else {
+ any_t0 = 1;
+ DEBUGP(5, dev, "card is capable of T=0\n");
+ }
+ } else
+ done = 1;
+ } while (!done);
+
+ DEBUGP(5, dev, "ix=%d noHist=%d any_t1=%d\n",
+ ix, dev->atr[1] & 15, any_t1);
+ if (ix + 1 + (dev->atr[1] & 0x0f) + any_t1 != dev->atr_len) {
+ DEBUGP(5, dev, "length error\n");
+ return 0;
+ }
+ if (any_t0)
+ set_bit(IS_ANY_T0, &dev->flags);
+
+ if (any_t1) { /* compute csum */
+ dev->atr_csum = 0;
+#ifdef ATR_CSUM
+ for (i = 1; i < dev->atr_len; i++)
+ dev->atr_csum ^= dev->atr[i];
+ if (dev->atr_csum) {
+ set_bit(IS_BAD_CSUM, &dev->flags);
+ DEBUGP(5, dev, "bad checksum\n");
+ goto return_0;
+ }
+#endif
+ if (any_t0 == 0)
+ dev->proto = 1; /* XXX PROTO */
+ set_bit(IS_ANY_T1, &dev->flags);
+ }
+
+ return 1;
+}
+
+struct card_fixup {
+ char atr[12];
+ u_int8_t atr_len;
+ u_int8_t stopbits;
+};
+
+static struct card_fixup card_fixups[] = {
+ { /* ACOS */
+ .atr = { 0x3b, 0xb3, 0x11, 0x00, 0x00, 0x41, 0x01 },
+ .atr_len = 7,
+ .stopbits = 0x03,
+ },
+ { /* Motorola */
+ .atr = {0x3b, 0x76, 0x13, 0x00, 0x00, 0x80, 0x62, 0x07,
+ 0x41, 0x81, 0x81 },
+ .atr_len = 11,
+ .stopbits = 0x04,
+ },
+};
+
+static void set_cardparameter(struct cm4000_dev *dev)
+{
+ int i;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ u_int8_t stopbits = 0x02; /* ISO default */
+
+ DEBUGP(3, dev, "-> set_cardparameter\n");
+
+ dev->flags1 = dev->flags1 | (((dev->baudv - 1) & 0x0100) >> 8);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ DEBUGP(5, dev, "flags1 = 0x%02x\n", dev->flags1);
+
+ /* set baudrate */
+ xoutb((unsigned char)((dev->baudv - 1) & 0xFF), REG_BAUDRATE(iobase));
+
+ DEBUGP(5, dev, "baudv = %i -> write 0x%02x\n", dev->baudv,
+ ((dev->baudv - 1) & 0xFF));
+
+ /* set stopbits */
+ for (i = 0; i < ARRAY_SIZE(card_fixups); i++) {
+ if (!memcmp(dev->atr, card_fixups[i].atr,
+ card_fixups[i].atr_len))
+ stopbits = card_fixups[i].stopbits;
+ }
+ xoutb(stopbits, REG_STOPBITS(iobase));
+
+ DEBUGP(3, dev, "<- set_cardparameter\n");
+}
+
+static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
+{
+
+ unsigned long tmp, i;
+ unsigned short num_bytes_read;
+ unsigned char pts_reply[4];
+ ssize_t rc;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+
+ rc = 0;
+
+ DEBUGP(3, dev, "-> set_protocol\n");
+ DEBUGP(5, dev, "ptsreq->Protocol = 0x%.8x, ptsreq->Flags=0x%.8x, "
+ "ptsreq->pts1=0x%.2x, ptsreq->pts2=0x%.2x, "
+ "ptsreq->pts3=0x%.2x\n", (unsigned int)ptsreq->protocol,
+ (unsigned int)ptsreq->flags, ptsreq->pts1, ptsreq->pts2,
+ ptsreq->pts3);
+
+ /* Fill PTS structure */
+ dev->pts[0] = 0xff;
+ dev->pts[1] = 0x00;
+ tmp = ptsreq->protocol;
+ while ((tmp = (tmp >> 1)) > 0)
+ dev->pts[1]++;
+ dev->proto = dev->pts[1]; /* Set new protocol */
+ dev->pts[1] = (0x01 << 4) | (dev->pts[1]);
+
+ /* Correct Fi/Di according to CM4000 Fi/Di table */
+ DEBUGP(5, dev, "Ta(1) from ATR is 0x%.2x\n", dev->ta1);
+ /* set Fi/Di according to ATR TA(1) */
+ dev->pts[2] = fi_di_table[dev->ta1 & 0x0F][(dev->ta1 >> 4) & 0x0F];
+
+ /* Calculate PCK character */
+ dev->pts[3] = dev->pts[0] ^ dev->pts[1] ^ dev->pts[2];
+
+ DEBUGP(5, dev, "pts0=%.2x, pts1=%.2x, pts2=%.2x, pts3=%.2x\n",
+ dev->pts[0], dev->pts[1], dev->pts[2], dev->pts[3]);
+
+ /* check card convention */
+ if (test_bit(IS_INVREV, &dev->flags))
+ str_invert_revert(dev->pts, 4);
+
+ /* reset SM */
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* Enable access to the message buffer */
+ DEBUGP(5, dev, "Enable access to the messages buffer\n");
+ dev->flags1 = 0x20 /* T_Active */
+ | (test_bit(IS_INVREV, &dev->flags) ? 0x02 : 0x00) /* inv parity */
+ | ((dev->baudv >> 8) & 0x01); /* MSB-baud */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ DEBUGP(5, dev, "Enable message buffer -> flags1 = 0x%.2x\n",
+ dev->flags1);
+
+ /* write challenge to the buffer */
+ DEBUGP(5, dev, "Write challenge to buffer: ");
+ for (i = 0; i < 4; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 5)
+ printk("0x%.2x ", dev->pts[i]);
+ }
+ if (pc_debug >= 5)
+ printk("\n");
+#else
+ }
+#endif
+
+ /* set number of bytes to write */
+ DEBUGP(5, dev, "Set number of bytes to write\n");
+ xoutb(0x04, REG_NUM_SEND(iobase));
+
+ /* Trigger CARDMAN CONTROLLER */
+ xoutb(0x50, REG_FLAGS0(iobase));
+
+ /* Monitor progress */
+ /* wait for xmit done */
+ DEBUGP(5, dev, "Waiting for NumRecBytes getting valid\n");
+
+ for (i = 0; i < 100; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08) {
+ DEBUGP(5, dev, "NumRecBytes is valid\n");
+ break;
+ }
+ mdelay(10);
+ }
+ if (i == 100) {
+ DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting "
+ "valid\n");
+ rc = -EIO;
+ goto exit_setprotocol;
+ }
+
+ DEBUGP(5, dev, "Reading NumRecBytes\n");
+ for (i = 0; i < 100; i++) {
+ io_read_num_rec_bytes(iobase, &num_bytes_read);
+ if (num_bytes_read >= 4) {
+ DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
+ break;
+ }
+ mdelay(10);
+ }
+
+ /* check whether it is a short PTS reply? */
+ if (num_bytes_read == 3)
+ i = 0;
+
+ if (i == 100) {
+ DEBUGP(5, dev, "Timeout reading num_bytes_read\n");
+ rc = -EIO;
+ goto exit_setprotocol;
+ }
+
+ DEBUGP(5, dev, "Reset the CARDMAN CONTROLLER\n");
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* Read PPS reply */
+ DEBUGP(5, dev, "Read PPS reply\n");
+ for (i = 0; i < num_bytes_read; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ pts_reply[i] = inb(REG_BUF_DATA(iobase));
+ }
+
+#ifdef PCMCIA_DEBUG
+ DEBUGP(2, dev, "PTSreply: ");
+ for (i = 0; i < num_bytes_read; i++) {
+ if (pc_debug >= 5)
+ printk("0x%.2x ", pts_reply[i]);
+ }
+ printk("\n");
+#endif /* PCMCIA_DEBUG */
+
+ DEBUGP(5, dev, "Clear Tactive in Flags1\n");
+ xoutb(0x20, REG_FLAGS1(iobase));
+
+ /* Compare ptsreq and ptsreply */
+ if ((dev->pts[0] == pts_reply[0]) &&
+ (dev->pts[1] == pts_reply[1]) &&
+ (dev->pts[2] == pts_reply[2]) && (dev->pts[3] == pts_reply[3])) {
+ /* setcardparameter according to PPS */
+ dev->baudv = calc_baudv(dev->pts[2]);
+ set_cardparameter(dev);
+ } else if ((dev->pts[0] == pts_reply[0]) &&
+ ((dev->pts[1] & 0xef) == pts_reply[1]) &&
+ ((pts_reply[0] ^ pts_reply[1]) == pts_reply[2])) {
+ /* short PTS reply, set card parameter to default values */
+ dev->baudv = calc_baudv(0x11);
+ set_cardparameter(dev);
+ } else
+ rc = -EIO;
+
+exit_setprotocol:
+ DEBUGP(3, dev, "<- set_protocol\n");
+ return rc;
+}
+
+static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+{
+
+ /* note: statemachine is assumed to be reset */
+ if (inb(REG_FLAGS0(iobase)) & 8) {
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ return 0; /* detect CMM = 1 -> failure */
+ }
+ /* xoutb(0x40, REG_FLAGS1(iobase)); detectCMM */
+ xoutb(dev->flags1 | 0x40, REG_FLAGS1(iobase));
+ if ((inb(REG_FLAGS0(iobase)) & 8) == 0) {
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ return 0; /* detect CMM=0 -> failure */
+ }
+ /* clear detectCMM again by restoring original flags1 */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ return 1;
+}
+
+static void terminate_monitor(struct cm4000_dev *dev)
+{
+
+ /* tell the monitor to stop and wait until
+ * it terminates.
+ */
+ DEBUGP(3, dev, "-> terminate_monitor\n");
+ wait_event_interruptible(dev->devq,
+ test_and_set_bit(LOCK_MONITOR,
+ (void *)&dev->flags));
+
+ /* now, LOCK_MONITOR has been set.
+ * allow a last cycle in the monitor.
+ * the monitor will indicate that it has
+ * finished by clearing this bit.
+ */
+ DEBUGP(5, dev, "Now allow last cycle of monitor!\n");
+ while (test_bit(LOCK_MONITOR, (void *)&dev->flags))
+ msleep(25);
+
+ DEBUGP(5, dev, "Delete timer\n");
+ del_timer_sync(&dev->timer);
+#ifdef PCMCIA_DEBUG
+ dev->monitor_running = 0;
+#endif
+
+ DEBUGP(3, dev, "<- terminate_monitor\n");
+}
+
+/*
+ * monitor the card every 50msec. as a side-effect, retrieve the
+ * atr once a card is inserted. another side-effect of retrieving the
+ * atr is that the card will be powered on, so there is no need to
+ * power on the card explictely from the application: the driver
+ * is already doing that for you.
+ */
+
+static void monitor_card(unsigned long p)
+{
+ struct cm4000_dev *dev = (struct cm4000_dev *) p;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ unsigned short s;
+ struct ptsreq ptsreq;
+ int i, atrc;
+
+ DEBUGP(7, dev, "-> monitor_card\n");
+
+ /* if someone has set the lock for us: we're done! */
+ if (test_and_set_bit(LOCK_MONITOR, &dev->flags)) {
+ DEBUGP(4, dev, "About to stop monitor\n");
+ /* no */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+ clear_bit(LOCK_MONITOR, &dev->flags);
+ /* close et al. are sleeping on devq, so wake it */
+ wake_up_interruptible(&dev->devq);
+ DEBUGP(2, dev, "<- monitor_card (we are done now)\n");
+ return;
+ }
+
+ /* try to lock io: if it is already locked, just add another timer */
+ if (test_and_set_bit(LOCK_IO, (void *)&dev->flags)) {
+ DEBUGP(4, dev, "Couldn't get IO lock\n");
+ goto return_with_timer;
+ }
+
+ /* is a card/a reader inserted at all ? */
+ dev->flags0 = xinb(REG_FLAGS0(iobase));
+ DEBUGP(7, dev, "dev->flags0 = 0x%2x\n", dev->flags0);
+ DEBUGP(7, dev, "smartcard present: %s\n",
+ dev->flags0 & 1 ? "yes" : "no");
+ DEBUGP(7, dev, "cardman present: %s\n",
+ dev->flags0 == 0xff ? "no" : "yes");
+
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ /* no */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ dev->flags &= 0x000000ff; /* only keep IO and MONITOR locks */
+
+ if (dev->flags0 == 0xff) {
+ DEBUGP(4, dev, "set IS_CMM_ABSENT bit\n");
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ } else if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ DEBUGP(4, dev, "clear IS_CMM_ABSENT bit "
+ "(card is removed)\n");
+ clear_bit(IS_CMM_ABSENT, &dev->flags);
+ }
+
+ goto release_io;
+ } else if ((dev->flags0 & 1) && test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ /* cardman and card present but cardman was absent before
+ * (after suspend with inserted card) */
+ DEBUGP(4, dev, "clear IS_CMM_ABSENT bit (card is inserted)\n");
+ clear_bit(IS_CMM_ABSENT, &dev->flags);
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+ DEBUGP(7, dev, "believe ATR is already valid (do nothing)\n");
+ goto release_io;
+ }
+
+ switch (dev->mstate) {
+ unsigned char flags0;
+ case M_CARDOFF:
+ DEBUGP(4, dev, "M_CARDOFF\n");
+ flags0 = inb(REG_FLAGS0(iobase));
+ if (flags0 & 0x02) {
+ /* wait until Flags0 indicate power is off */
+ dev->mdelay = T_10MSEC;
+ } else {
+ /* Flags0 indicate power off and no card inserted now;
+ * Reset CARDMAN CONTROLLER */
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* prepare for fetching ATR again: after card off ATR
+ * is read again automatically */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum =
+ dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ /* minimal gap between CARDOFF and read ATR is 50msec */
+ dev->mdelay = T_50MSEC;
+ }
+ break;
+ case M_FETCH_ATR:
+ DEBUGP(4, dev, "M_FETCH_ATR\n");
+ xoutb(0x80, REG_FLAGS0(iobase));
+ DEBUGP(4, dev, "Reset BAUDV to 9600\n");
+ dev->baudv = 0x173; /* 9600 */
+ xoutb(0x02, REG_STOPBITS(iobase)); /* stopbits=2 */
+ xoutb(0x73, REG_BAUDRATE(iobase)); /* baud value */
+ xoutb(0x21, REG_FLAGS1(iobase)); /* T_Active=1, baud
+ value */
+ /* warm start vs. power on: */
+ xoutb(dev->flags0 & 2 ? 0x46 : 0x44, REG_FLAGS0(iobase));
+ dev->mdelay = T_40MSEC;
+ dev->mstate = M_TIMEOUT_WAIT;
+ break;
+ case M_TIMEOUT_WAIT:
+ DEBUGP(4, dev, "M_TIMEOUT_WAIT\n");
+ /* numRecBytes */
+ io_read_num_rec_bytes(iobase, &dev->atr_len);
+ dev->mdelay = T_10MSEC;
+ dev->mstate = M_READ_ATR_LEN;
+ break;
+ case M_READ_ATR_LEN:
+ DEBUGP(4, dev, "M_READ_ATR_LEN\n");
+ /* infinite loop possible, since there is no timeout */
+
+#define MAX_ATR_LEN_RETRY 100
+
+ if (dev->atr_len == io_read_num_rec_bytes(iobase, &s)) {
+ if (dev->atr_len_retry++ >= MAX_ATR_LEN_RETRY) { /* + XX msec */
+ dev->mdelay = T_10MSEC;
+ dev->mstate = M_READ_ATR;
+ }
+ } else {
+ dev->atr_len = s;
+ dev->atr_len_retry = 0; /* set new timeout */
+ }
+
+ DEBUGP(4, dev, "Current ATR_LEN = %i\n", dev->atr_len);
+ break;
+ case M_READ_ATR:
+ DEBUGP(4, dev, "M_READ_ATR\n");
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+ for (i = 0; i < dev->atr_len; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ dev->atr[i] = inb(REG_BUF_DATA(iobase));
+ }
+ /* Deactivate T_Active flags */
+ DEBUGP(4, dev, "Deactivate T_Active flags\n");
+ dev->flags1 = 0x01;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ /* atr is present (which doesnt mean it's valid) */
+ set_bit(IS_ATR_PRESENT, &dev->flags);
+ if (dev->atr[0] == 0x03)
+ str_invert_revert(dev->atr, dev->atr_len);
+ atrc = parse_atr(dev);
+ if (atrc == 0) { /* atr invalid */
+ dev->mdelay = 0;
+ dev->mstate = M_BAD_CARD;
+ } else {
+ dev->mdelay = T_50MSEC;
+ dev->mstate = M_ATR_PRESENT;
+ set_bit(IS_ATR_VALID, &dev->flags);
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+ DEBUGP(4, dev, "monitor_card: ATR valid\n");
+ /* if ta1 == 0x11, no PPS necessary (default values) */
+ /* do not do PPS with multi protocol cards */
+ if ((test_bit(IS_AUTOPPS_ACT, &dev->flags) == 0) &&
+ (dev->ta1 != 0x11) &&
+ !(test_bit(IS_ANY_T0, &dev->flags) &&
+ test_bit(IS_ANY_T1, &dev->flags))) {
+ DEBUGP(4, dev, "Perform AUTOPPS\n");
+ set_bit(IS_AUTOPPS_ACT, &dev->flags);
+ ptsreq.protocol = ptsreq.protocol =
+ (0x01 << dev->proto);
+ ptsreq.flags = 0x01;
+ ptsreq.pts1 = 0x00;
+ ptsreq.pts2 = 0x00;
+ ptsreq.pts3 = 0x00;
+ if (set_protocol(dev, &ptsreq) == 0) {
+ DEBUGP(4, dev, "AUTOPPS ret SUCC\n");
+ clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+ wake_up_interruptible(&dev->atrq);
+ } else {
+ DEBUGP(4, dev, "AUTOPPS failed: "
+ "repower using defaults\n");
+ /* prepare for repowering */
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum =
+ dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ dev->mdelay = T_50MSEC;
+ }
+ } else {
+ /* for cards which use slightly different
+ * params (extra guard time) */
+ set_cardparameter(dev);
+ if (test_bit(IS_AUTOPPS_ACT, &dev->flags) == 1)
+ DEBUGP(4, dev, "AUTOPPS already active "
+ "2nd try:use default values\n");
+ if (dev->ta1 == 0x11)
+ DEBUGP(4, dev, "No AUTOPPS necessary "
+ "TA(1)==0x11\n");
+ if (test_bit(IS_ANY_T0, &dev->flags)
+ && test_bit(IS_ANY_T1, &dev->flags))
+ DEBUGP(4, dev, "Do NOT perform AUTOPPS "
+ "with multiprotocol cards\n");
+ clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+ wake_up_interruptible(&dev->atrq);
+ }
+ } else {
+ DEBUGP(4, dev, "ATR invalid\n");
+ wake_up_interruptible(&dev->atrq);
+ }
+ break;
+ case M_BAD_CARD:
+ DEBUGP(4, dev, "M_BAD_CARD\n");
+ /* slow down warning, but prompt immediately after insertion */
+ if (dev->cwarn == 0 || dev->cwarn == 10) {
+ set_bit(IS_BAD_CARD, &dev->flags);
+ printk(KERN_WARNING MODULE_NAME ": device %s: ",
+ dev->node.dev_name);
+ if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+ DEBUGP(4, dev, "ATR checksum (0x%.2x, should "
+ "be zero) failed\n", dev->atr_csum);
+ }
+#ifdef PCMCIA_DEBUG
+ else if (test_bit(IS_BAD_LENGTH, &dev->flags)) {
+ DEBUGP(4, dev, "ATR length error\n");
+ } else {
+ DEBUGP(4, dev, "card damaged or wrong way "
+ "inserted\n");
+ }
+#endif
+ dev->cwarn = 0;
+ wake_up_interruptible(&dev->atrq); /* wake open */
+ }
+ dev->cwarn++;
+ dev->mdelay = T_100MSEC;
+ dev->mstate = M_FETCH_ATR;
+ break;
+ default:
+ DEBUGP(7, dev, "Unknown action\n");
+ break; /* nothing */
+ }
+
+release_io:
+ DEBUGP(7, dev, "release_io\n");
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq); /* whoever needs IO */
+
+return_with_timer:
+ DEBUGP(7, dev, "<- monitor_card (returns with timer)\n");
+ dev->timer.expires = jiffies + dev->mdelay;
+ add_timer(&dev->timer);
+ clear_bit(LOCK_MONITOR, &dev->flags);
+}
+
+/* Interface to userland (file_operations) */
+
+static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct cm4000_dev *dev = filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ ssize_t rc;
+ int i, j, k;
+
+ DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) /* according to manpage */
+ return 0;
+
+ if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */
+ test_bit(IS_CMM_ABSENT, &dev->flags))
+ return -ENODEV;
+
+ if (test_bit(IS_BAD_CSUM, &dev->flags))
+ return -EIO;
+
+ /* also see the note about this in cmm_write */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0)
+ return -EIO;
+
+ /* this one implements blocking IO */
+ if (wait_event_interruptible
+ (dev->readq,
+ ((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ /* lock io */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ rc = 0;
+ dev->flags0 = inb(REG_FLAGS0(iobase));
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ if (dev->flags0 & 1) {
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ rc = -ENODEV;
+ }
+ rc = -EIO;
+ goto release_io;
+ }
+
+ DEBUGP(4, dev, "begin read answer\n");
+ j = min(count, (size_t)(dev->rlen - dev->rpos));
+ k = dev->rpos;
+ if (k + j > 255)
+ j = 256 - k;
+ DEBUGP(4, dev, "read1 j=%d\n", j);
+ for (i = 0; i < j; i++) {
+ xoutb(k++, REG_BUF_ADDR(iobase));
+ dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+ }
+ j = min(count, (size_t)(dev->rlen - dev->rpos));
+ if (k + j > 255) {
+ DEBUGP(4, dev, "read2 j=%d\n", j);
+ dev->flags1 |= 0x10; /* MSB buf addr set */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ for (; i < j; i++) {
+ xoutb(k++, REG_BUF_ADDR(iobase));
+ dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+ }
+ }
+
+ if (dev->proto == 0 && count > dev->rlen - dev->rpos) {
+ DEBUGP(4, dev, "T=0 and count > buffer\n");
+ dev->rbuf[i] = dev->rbuf[i - 1];
+ dev->rbuf[i - 1] = dev->procbyte;
+ j++;
+ }
+ count = j;
+
+ dev->rpos = dev->rlen + 1;
+
+ /* Clear T1Active */
+ DEBUGP(4, dev, "Clear T1Active\n");
+ dev->flags1 &= 0xdf;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */
+ /* last check before exit */
+ if (!io_detect_cm4000(iobase, dev))
+ count = -ENODEV;
+
+ if (test_bit(IS_INVREV, &dev->flags) && count > 0)
+ str_invert_revert(dev->rbuf, count);
+
+ if (copy_to_user(buf, dev->rbuf, count))
+ return -EFAULT;
+
+release_io:
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ DEBUGP(2, dev, "<- cmm_read returns: rc = %Zi\n",
+ (rc < 0 ? rc : count));
+ return rc < 0 ? rc : count;
+}
+
+static ssize_t cmm_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ unsigned short s;
+ unsigned char tmp;
+ unsigned char infolen;
+ unsigned char sendT0;
+ unsigned short nsend;
+ unsigned short nr;
+ ssize_t rc;
+ int i;
+
+ DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) /* according to manpage */
+ return 0;
+
+ if (dev->proto == 0 && count < 4) {
+ /* T0 must have at least 4 bytes */
+ DEBUGP(4, dev, "T0 short write\n");
+ return -EIO;
+ }
+
+ nr = count & 0x1ff; /* max bytes to write */
+
+ sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0;
+
+ if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */
+ test_bit(IS_CMM_ABSENT, &dev->flags))
+ return -ENODEV;
+
+ if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+ DEBUGP(4, dev, "bad csum\n");
+ return -EIO;
+ }
+
+ /*
+ * wait for atr to become valid.
+ * note: it is important to lock this code. if we dont, the monitor
+ * could be run between test_bit and the the call the sleep on the
+ * atr-queue. if *then* the monitor detects atr valid, it will wake up
+ * any process on the atr-queue, *but* since we have been interrupted,
+ * we do not yet sleep on this queue. this would result in a missed
+ * wake_up and the calling process would sleep forever (until
+ * interrupted). also, do *not* restore_flags before sleep_on, because
+ * this could result in the same situation!
+ */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { /* invalid atr */
+ DEBUGP(4, dev, "invalid ATR\n");
+ return -EIO;
+ }
+
+ /* lock io */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count)))
+ return -EFAULT;
+
+ rc = 0;
+ dev->flags0 = inb(REG_FLAGS0(iobase));
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ if (dev->flags0 & 1) {
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ rc = -ENODEV;
+ } else {
+ DEBUGP(4, dev, "IO error\n");
+ rc = -EIO;
+ }
+ goto release_io;
+ }
+
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+
+ if (!io_detect_cm4000(iobase, dev)) {
+ rc = -ENODEV;
+ goto release_io;
+ }
+
+ /* reflect T=0 send/read mode in flags1 */
+ dev->flags1 |= (sendT0);
+
+ set_cardparameter(dev);
+
+ /* dummy read, reset flag procedure received */
+ tmp = inb(REG_FLAGS1(iobase));
+
+ dev->flags1 = 0x20 /* T_Active */
+ | (sendT0)
+ | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity */
+ | (((dev->baudv - 1) & 0x0100) >> 8); /* MSB-Baud */
+ DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ /* xmit data */
+ DEBUGP(4, dev, "Xmit data\n");
+ for (i = 0; i < nr; i++) {
+ if (i >= 256) {
+ dev->flags1 = 0x20 /* T_Active */
+ | (sendT0) /* SendT0 */
+ /* inverse parity: */
+ | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)
+ | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */
+ | 0x10; /* set address high */
+ DEBUGP(4, dev, "dev->flags = 0x%.2x - set address "
+ "high\n", dev->flags1);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ }
+ if (test_bit(IS_INVREV, &dev->flags)) {
+ DEBUGP(4, dev, "Apply inverse convention for 0x%.2x "
+ "-> 0x%.2x\n", (unsigned char)dev->sbuf[i],
+ invert_revert(dev->sbuf[i]));
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(invert_revert(dev->sbuf[i]),
+ REG_BUF_DATA(iobase));
+ } else {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(dev->sbuf[i], REG_BUF_DATA(iobase));
+ }
+ }
+ DEBUGP(4, dev, "Xmit done\n");
+
+ if (dev->proto == 0) {
+ /* T=0 proto: 0 byte reply */
+ if (nr == 4) {
+ DEBUGP(4, dev, "T=0 assumes 0 byte reply\n");
+ xoutb(i, REG_BUF_ADDR(iobase));
+ if (test_bit(IS_INVREV, &dev->flags))
+ xoutb(0xff, REG_BUF_DATA(iobase));
+ else
+ xoutb(0x00, REG_BUF_DATA(iobase));
+ }
+
+ /* numSendBytes */
+ if (sendT0)
+ nsend = nr;
+ else {
+ if (nr == 4)
+ nsend = 5;
+ else {
+ nsend = 5 + (unsigned char)dev->sbuf[4];
+ if (dev->sbuf[4] == 0)
+ nsend += 0x100;
+ }
+ }
+ } else
+ nsend = nr;
+
+ /* T0: output procedure byte */
+ if (test_bit(IS_INVREV, &dev->flags)) {
+ DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) "
+ "0x%.2x\n", invert_revert(dev->sbuf[1]));
+ xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase));
+ } else {
+ DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]);
+ xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase));
+ }
+
+ DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n",
+ (unsigned char)(nsend & 0xff));
+ xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase));
+
+ DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n",
+ 0x40 /* SM_Active */
+ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */
+ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */
+ |(nsend & 0x100) >> 8 /* MSB numSendBytes */ );
+ xoutb(0x40 /* SM_Active */
+ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */
+ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */
+ |(nsend & 0x100) >> 8, /* MSB numSendBytes */
+ REG_FLAGS0(iobase));
+
+ /* wait for xmit done */
+ if (dev->proto == 1) {
+ DEBUGP(4, dev, "Wait for xmit done\n");
+ for (i = 0; i < 1000; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08)
+ break;
+ msleep_interruptible(10);
+ }
+ if (i == 1000) {
+ DEBUGP(4, dev, "timeout waiting for xmit done\n");
+ rc = -EIO;
+ goto release_io;
+ }
+ }
+
+ /* T=1: wait for infoLen */
+
+ infolen = 0;
+ if (dev->proto) {
+ /* wait until infoLen is valid */
+ for (i = 0; i < 6000; i++) { /* max waiting time of 1 min */
+ io_read_num_rec_bytes(iobase, &s);
+ if (s >= 3) {
+ infolen = inb(REG_FLAGS1(iobase));
+ DEBUGP(4, dev, "infolen=%d\n", infolen);
+ break;
+ }
+ msleep_interruptible(10);
+ }
+ if (i == 6000) {
+ DEBUGP(4, dev, "timeout waiting for infoLen\n");
+ rc = -EIO;
+ goto release_io;
+ }
+ } else
+ clear_bit(IS_PROCBYTE_PRESENT, &dev->flags);
+
+ /* numRecBytes | bit9 of numRecytes */
+ io_read_num_rec_bytes(iobase, &dev->rlen);
+ for (i = 0; i < 600; i++) { /* max waiting time of 2 sec */
+ if (dev->proto) {
+ if (dev->rlen >= infolen + 4)
+ break;
+ }
+ msleep_interruptible(10);
+ /* numRecBytes | bit9 of numRecytes */
+ io_read_num_rec_bytes(iobase, &s);
+ if (s > dev->rlen) {
+ DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n");
+ i = 0; /* reset timeout */
+ dev->rlen = s;
+ }
+ /* T=0: we are done when numRecBytes doesn't
+ * increment any more and NoProcedureByte
+ * is set and numRecBytes == bytes sent + 6
+ * (header bytes + data + 1 for sw2)
+ * except when the card replies an error
+ * which means, no data will be sent back.
+ */
+ else if (dev->proto == 0) {
+ if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) {
+ /* no procedure byte received since last read */
+ DEBUGP(1, dev, "NoProcedure byte set\n");
+ /* i=0; */
+ } else {
+ /* procedure byte received since last read */
+ DEBUGP(1, dev, "NoProcedure byte unset "
+ "(reset timeout)\n");
+ dev->procbyte = inb(REG_FLAGS1(iobase));
+ DEBUGP(1, dev, "Read procedure byte 0x%.2x\n",
+ dev->procbyte);
+ i = 0; /* resettimeout */
+ }
+ if (inb(REG_FLAGS0(iobase)) & 0x08) {
+ DEBUGP(1, dev, "T0Done flag (read reply)\n");
+ break;
+ }
+ }
+ if (dev->proto)
+ infolen = inb(REG_FLAGS1(iobase));
+ }
+ if (i == 600) {
+ DEBUGP(1, dev, "timeout waiting for numRecBytes\n");
+ rc = -EIO;
+ goto release_io;
+ } else {
+ if (dev->proto == 0) {
+ DEBUGP(1, dev, "Wait for T0Done bit to be set\n");
+ for (i = 0; i < 1000; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08)
+ break;
+ msleep_interruptible(10);
+ }
+ if (i == 1000) {
+ DEBUGP(1, dev, "timeout waiting for T0Done\n");
+ rc = -EIO;
+ goto release_io;
+ }
+
+ dev->procbyte = inb(REG_FLAGS1(iobase));
+ DEBUGP(4, dev, "Read procedure byte 0x%.2x\n",
+ dev->procbyte);
+
+ io_read_num_rec_bytes(iobase, &dev->rlen);
+ DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen);
+
+ }
+ }
+ /* T=1: read offset=zero, T=0: read offset=after challenge */
+ dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr;
+ DEBUGP(4, dev, "dev->rlen = %i, dev->rpos = %i, nr = %i\n",
+ dev->rlen, dev->rpos, nr);
+
+release_io:
+ DEBUGP(4, dev, "Reset SM\n");
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+
+ if (rc < 0) {
+ DEBUGP(4, dev, "Write failed but clear T_Active\n");
+ dev->flags1 &= 0xdf;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ }
+
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+ wake_up_interruptible(&dev->readq); /* tell read we have data */
+
+ /* ITSEC E2: clear write buffer */
+ memset((char *)dev->sbuf, 0, 512);
+
+ /* return error or actually written bytes */
+ DEBUGP(2, dev, "<- cmm_write\n");
+ return rc < 0 ? rc : nr;
+}
+
+static void start_monitor(struct cm4000_dev *dev)
+{
+ DEBUGP(3, dev, "-> start_monitor\n");
+ if (!dev->monitor_running) {
+ DEBUGP(5, dev, "create, init and add timer\n");
+ init_timer(&dev->timer);
+ dev->monitor_running = 1;
+ dev->timer.expires = jiffies;
+ dev->timer.data = (unsigned long) dev;
+ dev->timer.function = monitor_card;
+ add_timer(&dev->timer);
+ } else
+ DEBUGP(5, dev, "monitor already running\n");
+ DEBUGP(3, dev, "<- start_monitor\n");
+}
+
+static void stop_monitor(struct cm4000_dev *dev)
+{
+ DEBUGP(3, dev, "-> stop_monitor\n");
+ if (dev->monitor_running) {
+ DEBUGP(5, dev, "stopping monitor\n");
+ terminate_monitor(dev);
+ /* reset monitor SM */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ } else
+ DEBUGP(5, dev, "monitor already stopped\n");
+ DEBUGP(3, dev, "<- stop_monitor\n");
+}
+
+static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cm4000_dev *dev = filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ dev_link_t *link;
+ int size;
+ int rc;
+#ifdef PCMCIA_DEBUG
+ char *ioctl_names[CM_IOC_MAXNR + 1] = {
+ [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS",
+ [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR",
+ [_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF",
+ [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS",
+ [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL",
+ };
+#endif
+ DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
+ iminor(inode), ioctl_names[_IOC_NR(cmd)]);
+
+ link = dev_table[iminor(inode)];
+ if (!(DEV_OK(link))) {
+ DEBUGP(4, dev, "DEV_OK false\n");
+ return -ENODEV;
+ }
+
+ if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ DEBUGP(4, dev, "CMM_ABSENT flag set\n");
+ return -ENODEV;
+ }
+
+ if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) {
+ DEBUGP(4, dev, "ioctype mismatch\n");
+ return -EINVAL;
+ }
+ if (_IOC_NR(cmd) > CM_IOC_MAXNR) {
+ DEBUGP(4, dev, "iocnr mismatch\n");
+ return -EINVAL;
+ }
+ size = _IOC_SIZE(cmd);
+ rc = 0;
+ DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n",
+ _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd);
+
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (!access_ok(VERIFY_WRITE, (void *)arg, size))
+ return -EFAULT;
+ }
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (!access_ok(VERIFY_READ, (void *)arg, size))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case CM_IOCGSTATUS:
+ DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n");
+ {
+ int status;
+
+ /* clear other bits, but leave inserted & powered as
+ * they are */
+ status = dev->flags0 & 3;
+ if (test_bit(IS_ATR_PRESENT, &dev->flags))
+ status |= CM_ATR_PRESENT;
+ if (test_bit(IS_ATR_VALID, &dev->flags))
+ status |= CM_ATR_VALID;
+ if (test_bit(IS_CMM_ABSENT, &dev->flags))
+ status |= CM_NO_READER;
+ if (test_bit(IS_BAD_CARD, &dev->flags))
+ status |= CM_BAD_CARD;
+ if (copy_to_user((int *)arg, &status, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ case CM_IOCGATR:
+ DEBUGP(4, dev, "... in CM_IOCGATR\n");
+ {
+ struct atreq *atreq = (struct atreq *) arg;
+ int tmp;
+ /* allow nonblocking io and being interrupted */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+ != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {
+ tmp = -1;
+ if (copy_to_user(&(atreq->atr_len), &tmp,
+ sizeof(int)))
+ return -EFAULT;
+ } else {
+ if (copy_to_user(atreq->atr, dev->atr,
+ dev->atr_len))
+ return -EFAULT;
+
+ tmp = dev->atr_len;
+ if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case CM_IOCARDOFF:
+
+#ifdef PCMCIA_DEBUG
+ DEBUGP(4, dev, "... in CM_IOCARDOFF\n");
+ if (dev->flags0 & 0x01) {
+ DEBUGP(4, dev, " Card inserted\n");
+ } else {
+ DEBUGP(2, dev, " No card inserted\n");
+ }
+ if (dev->flags0 & 0x02) {
+ DEBUGP(4, dev, " Card powered\n");
+ } else {
+ DEBUGP(2, dev, " Card not powered\n");
+ }
+#endif
+
+ /* is a card inserted and powered? */
+ if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) {
+
+ /* get IO lock */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+ == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ /* Set Flags0 = 0x42 */
+ DEBUGP(4, dev, "Set Flags0=0x42 \n");
+ xoutb(0x42, REG_FLAGS0(iobase));
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ dev->mstate = M_CARDOFF;
+ clear_bit(LOCK_IO, &dev->flags);
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_VALID, (void *)&dev->flags) !=
+ 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ }
+ /* release lock */
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ return 0;
+ case CM_IOCSPTS:
+ {
+ struct ptsreq krnptsreq;
+
+ if (copy_from_user(&krnptsreq, (struct ptsreq *) arg,
+ sizeof(struct ptsreq)))
+ return -EFAULT;
+
+ rc = 0;
+ DEBUGP(4, dev, "... in CM_IOCSPTS\n");
+ /* wait for ATR to get valid */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+ != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ /* get IO lock */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+ == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if ((rc = set_protocol(dev, &krnptsreq)) != 0) {
+ /* auto power_on again */
+ dev->mstate = M_FETCH_ATR;
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ }
+ /* release lock */
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ }
+ return rc;
+#ifdef PCMCIA_DEBUG
+ case CM_IOSDBGLVL: /* set debug log level */
+ {
+ int old_pc_debug = 0;
+
+ old_pc_debug = pc_debug;
+ if (copy_from_user(&pc_debug, (int *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (old_pc_debug != pc_debug)
+ DEBUGP(0, dev, "Changed debug log level "
+ "to %i\n", pc_debug);
+ }
+ return rc;
+#endif
+ default:
+ DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");
+ return -EINVAL;
+ }
+}
+
+static int cmm_open(struct inode *inode, struct file *filp)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ int rc, minor = iminor(inode);
+
+ if (minor >= CM4000_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL || !(DEV_OK(link)))
+ return -ENODEV;
+
+ if (link->open)
+ return -EBUSY;
+
+ dev = link->priv;
+ filp->private_data = dev;
+
+ DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n",
+ imajor(inode), minor, current->comm, current->pid);
+
+ /* init device variables, they may be "polluted" after close
+ * or, the device may never have been closed (i.e. open failed)
+ */
+
+ ZERO_DEV(dev);
+
+ /* opening will always block since the
+ * monitor will be started by open, which
+ * means we have to wait for ATR becoming
+ * vaild = block until valid (or card
+ * inserted)
+ */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ dev->mdelay = T_50MSEC;
+
+ /* start monitoring the cardstatus */
+ start_monitor(dev);
+
+ link->open = 1; /* only one open per device */
+ rc = 0;
+
+ DEBUGP(2, dev, "<- cmm_open\n");
+ return nonseekable_open(inode, filp);
+}
+
+static int cmm_close(struct inode *inode, struct file *filp)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ if (minor >= CM4000_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL)
+ return -ENODEV;
+
+ dev = link->priv;
+
+ DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n",
+ imajor(inode), minor);
+
+ stop_monitor(dev);
+
+ ZERO_DEV(dev);
+
+ link->open = 0; /* only one open per device */
+ wake_up(&dev->devq); /* socket removed? */
+
+ DEBUGP(2, dev, "cmm_close\n");
+ return 0;
+}
+
+static void cmm_cm4000_release(dev_link_t * link)
+{
+ struct cm4000_dev *dev = link->priv;
+
+ /* dont terminate the monitor, rather rely on
+ * close doing that for us.
+ */
+ DEBUGP(3, dev, "-> cmm_cm4000_release\n");
+ while (link->open) {
+ printk(KERN_INFO MODULE_NAME ": delaying release until "
+ "process has terminated\n");
+ /* note: don't interrupt us:
+ * close the applications which own
+ * the devices _first_ !
+ */
+ wait_event(dev->devq, (link->open == 0));
+ }
+ /* dev->devq=NULL; this cannot be zeroed earlier */
+ DEBUGP(3, dev, "<- cmm_cm4000_release\n");
+ return;
+}
+
+/*==== Interface to PCMCIA Layer =======================================*/
+
+static void cm4000_config(dev_link_t * link, int devno)
+{
+ client_handle_t handle = link->handle;
+ struct cm4000_dev *dev;
+ tuple_t tuple;
+ cisparse_t parse;
+ config_info_t conf;
+ u_char buf[64];
+ int fail_fn, fail_rc;
+ int rc;
+
+ /* read the config-tuples */
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetFirstTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetTupleData;
+ goto cs_failed;
+ }
+ if ((fail_rc =
+ pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) {
+ fail_fn = ParseTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc =
+ pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) {
+ fail_fn = GetConfigurationInfo;
+ goto cs_failed;
+ }
+
+ link->state |= DEV_CONFIG;
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+ link->conf.Vcc = conf.Vcc;
+
+ link->io.BasePort2 = 0;
+ link->io.NumPorts2 = 0;
+ link->io.Attributes2 = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ for (rc = pcmcia_get_first_tuple(handle, &tuple);
+ rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) {
+
+ rc = pcmcia_get_tuple_data(handle, &tuple);
+ if (rc != CS_SUCCESS)
+ continue;
+ rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+ if (rc != CS_SUCCESS)
+ continue;
+
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+
+ if (!parse.cftable_entry.io.nwin)
+ continue;
+
+ /* Get the IOaddr */
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = parse.cftable_entry.io.flags
+ & CISTPL_IO_LINES_MASK;
+
+ rc = pcmcia_request_io(handle, &link->io);
+ if (rc == CS_SUCCESS)
+ break; /* we are done */
+ }
+ if (rc != CS_SUCCESS)
+ goto cs_release;
+
+ link->conf.IntType = 00000002;
+
+ if ((fail_rc =
+ pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) {
+ fail_fn = RequestConfiguration;
+ goto cs_release;
+ }
+
+ dev = link->priv;
+ sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+ dev->node.major = major;
+ dev->node.minor = devno;
+ dev->node.next = NULL;
+ link->dev = &dev->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ return;
+
+cs_failed:
+ cs_error(handle, fail_fn, fail_rc);
+cs_release:
+ cm4000_release(link);
+
+ link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int cm4000_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link;
+ struct cm4000_dev *dev;
+ int devno;
+
+ link = args->client_data;
+ dev = link->priv;
+
+ DEBUGP(3, dev, "-> cm4000_event\n");
+ for (devno = 0; devno < CM4000_MAX_DEV; devno++)
+ if (dev_table[devno] == link)
+ break;
+
+ if (devno == CM4000_MAX_DEV)
+ return CS_BAD_ADAPTER;
+
+ switch (event) {
+ case CS_EVENT_CARD_INSERTION:
+ DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ cm4000_config(link, devno);
+ break;
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+ link->state &= ~DEV_PRESENT;
+ stop_monitor(dev);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+ "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+ link->state |= DEV_SUSPEND;
+ /* fall-through */
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "ReleaseConfiguration\n");
+ pcmcia_release_configuration(link->handle);
+ }
+ stop_monitor(dev);
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+ "(fall-through to CS_EVENT_CARD_RESET)\n");
+ link->state &= ~DEV_SUSPEND;
+ /* fall-through */
+ case CS_EVENT_CARD_RESET:
+ DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+ if ((link->state & DEV_CONFIG)) {
+ DEBUGP(5, dev, "RequestConfiguration\n");
+ pcmcia_request_configuration(link->handle, &link->conf);
+ }
+ if (link->open)
+ start_monitor(dev);
+ break;
+ default:
+ DEBUGP(5, dev, "unknown event %.2x\n", event);
+ break;
+ }
+ DEBUGP(3, dev, "<- cm4000_event\n");
+ return CS_SUCCESS;
+}
+
+static void cm4000_release(dev_link_t *link)
+{
+ cmm_cm4000_release(link->priv); /* delay release until device closed */
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *cm4000_attach(void)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int i;
+
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i] == NULL)
+ break;
+
+ if (i == CM4000_MAX_DEV) {
+ printk(KERN_NOTICE MODULE_NAME ": all devices in use\n");
+ return NULL;
+ }
+
+ /* create a new cm4000_cs device */
+ dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL);
+ if (dev == NULL)
+ return NULL;
+
+ link = &dev->link;
+ link->priv = dev;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ dev_table[i] = link;
+
+ /* register with card services */
+ client_reg.dev_info = &dev_info;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+
+ i = pcmcia_register_client(&link->handle, &client_reg);
+ if (i) {
+ cs_error(link->handle, RegisterClient, i);
+ cm4000_detach(link);
+ return NULL;
+ }
+
+ init_waitqueue_head(&dev->devq);
+ init_waitqueue_head(&dev->ioq);
+ init_waitqueue_head(&dev->atrq);
+ init_waitqueue_head(&dev->readq);
+
+ return link;
+}
+
+static void cm4000_detach_by_devno(int devno, dev_link_t * link)
+{
+ struct cm4000_dev *dev = link->priv;
+
+ DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno);
+
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "device still configured (try to release it)\n");
+ cm4000_release(link);
+ }
+
+ if (link->handle) {
+ pcmcia_deregister_client(link->handle);
+ }
+
+ dev_table[devno] = NULL;
+ kfree(dev);
+ return;
+}
+
+static void cm4000_detach(dev_link_t * link)
+{
+ int i;
+
+ /* find device */
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i] == link)
+ break;
+
+ if (i == CM4000_MAX_DEV)
+ return;
+
+ cm4000_detach_by_devno(i, link);
+ return;
+}
+
+static struct file_operations cm4000_fops = {
+ .owner = THIS_MODULE,
+ .read = cmm_read,
+ .write = cmm_write,
+ .ioctl = cmm_ioctl,
+ .open = cmm_open,
+ .release= cmm_close,
+};
+
+static struct pcmcia_device_id cm4000_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
+ PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);
+
+static struct pcmcia_driver cm4000_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "cm4000_cs",
+ },
+ .attach = cm4000_attach,
+ .detach = cm4000_detach,
+ .event = cm4000_event,
+ .id_table = cm4000_ids,
+};
+
+static int __init cmm_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ pcmcia_register_driver(&cm4000_driver);
+ major = register_chrdev(0, DEVICE_NAME, &cm4000_fops);
+ if (major < 0) {
+ printk(KERN_WARNING MODULE_NAME
+ ": could not get major number\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit cmm_exit(void)
+{
+ int i;
+
+ printk(KERN_INFO MODULE_NAME ": unloading\n");
+ pcmcia_unregister_driver(&cm4000_driver);
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i])
+ cm4000_detach_by_devno(i, dev_table[i]);
+ unregister_chrdev(major, DEVICE_NAME);
+};
+
+module_init(cmm_init);
+module_exit(cmm_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/trunk/drivers/char/pcmcia/cm4040_cs.c b/trunk/drivers/char/pcmcia/cm4040_cs.c
new file mode 100644
index 000000000000..4c698d908ffa
--- /dev/null
+++ b/trunk/drivers/char/pcmcia/cm4040_cs.c
@@ -0,0 +1,841 @@
+/*
+ * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040
+ *
+ * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/)
+ *
+ * (C) 2005 Harald Welte
+ * - add support for poll()
+ * - driver cleanup
+ * - add waitqueues
+ * - adhere to linux kernel coding style and policies
+ * - support 2.6.13 "new style" pcmcia interface
+ *
+ * The device basically is a USB CCID compliant device that has been
+ * attached to an I/O-Mapped FIFO.
+ *
+ * All rights reserved, Dual BSD/GPL Licensed.
+ */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cm4040_cs.h"
+
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x) (&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { \
+ if (pc_debug >= (n)) \
+ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
+ __FUNCTION__ , ##args); \
+ } while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+
+static char *version =
+"OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte";
+
+#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ)
+#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ)
+#define CCID_DRIVER_MINIMUM_TIMEOUT (3*HZ)
+#define READ_WRITE_BUFFER_SIZE 512
+#define POLL_LOOP_COUNT 1000
+
+/* how often to poll for fifo status change */
+#define POLL_PERIOD msecs_to_jiffies(10)
+
+static void reader_release(dev_link_t *link);
+static void reader_detach(dev_link_t *link);
+
+static int major;
+
+#define BS_READABLE 0x01
+#define BS_WRITABLE 0x02
+
+struct reader_dev {
+ dev_link_t link;
+ dev_node_t node;
+ wait_queue_head_t devq;
+ wait_queue_head_t poll_wait;
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+ unsigned long buffer_status;
+ unsigned long timeout;
+ unsigned char s_buf[READ_WRITE_BUFFER_SIZE];
+ unsigned char r_buf[READ_WRITE_BUFFER_SIZE];
+ struct timer_list poll_timer;
+};
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM_MAX_DEV];
+
+#ifndef PCMCIA_DEBUG
+#define xoutb outb
+#define xinb inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ outb(val, port);
+}
+
+static inline unsigned char xinb(unsigned short port)
+{
+ unsigned char val;
+
+ val = inb(port);
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+ return val;
+}
+#endif
+
+/* poll the device fifo status register. not to be confused with
+ * the poll syscall. */
+static void cm4040_do_poll(unsigned long dummy)
+{
+ struct reader_dev *dev = (struct reader_dev *) dummy;
+ unsigned int obs = xinb(dev->link.io.BasePort1
+ + REG_OFFSET_BUFFER_STATUS);
+
+ if ((obs & BSR_BULK_IN_FULL)) {
+ set_bit(BS_READABLE, &dev->buffer_status);
+ DEBUGP(4, dev, "waking up read_wait\n");
+ wake_up_interruptible(&dev->read_wait);
+ } else
+ clear_bit(BS_READABLE, &dev->buffer_status);
+
+ if (!(obs & BSR_BULK_OUT_FULL)) {
+ set_bit(BS_WRITABLE, &dev->buffer_status);
+ DEBUGP(4, dev, "waking up write_wait\n");
+ wake_up_interruptible(&dev->write_wait);
+ } else
+ clear_bit(BS_WRITABLE, &dev->buffer_status);
+
+ if (dev->buffer_status)
+ wake_up_interruptible(&dev->poll_wait);
+
+ mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+}
+
+static void cm4040_stop_poll(struct reader_dev *dev)
+{
+ del_timer_sync(&dev->poll_timer);
+}
+
+static int wait_for_bulk_out_ready(struct reader_dev *dev)
+{
+ int i, rc;
+ int iobase = dev->link.io.BasePort1;
+
+ for (i = 0; i < POLL_LOOP_COUNT; i++) {
+ if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+ & BSR_BULK_OUT_FULL) == 0) {
+ DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i);
+ return 1;
+ }
+ }
+
+ DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+ dev->timeout);
+ rc = wait_event_interruptible_timeout(dev->write_wait,
+ test_and_clear_bit(BS_WRITABLE,
+ &dev->buffer_status),
+ dev->timeout);
+
+ if (rc > 0)
+ DEBUGP(4, dev, "woke up: BulkOut empty\n");
+ else if (rc == 0)
+ DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n");
+ else if (rc < 0)
+ DEBUGP(4, dev, "woke up: signal arrived\n");
+
+ return rc;
+}
+
+/* Write to Sync Control Register */
+static int write_sync_reg(unsigned char val, struct reader_dev *dev)
+{
+ int iobase = dev->link.io.BasePort1;
+ int rc;
+
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0)
+ return rc;
+
+ xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL);
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+static int wait_for_bulk_in_ready(struct reader_dev *dev)
+{
+ int i, rc;
+ int iobase = dev->link.io.BasePort1;
+
+ for (i = 0; i < POLL_LOOP_COUNT; i++) {
+ if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+ & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) {
+ DEBUGP(3, dev, "BulkIn full (i=%d)\n", i);
+ return 1;
+ }
+ }
+
+ DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+ dev->timeout);
+ rc = wait_event_interruptible_timeout(dev->read_wait,
+ test_and_clear_bit(BS_READABLE,
+ &dev->buffer_status),
+ dev->timeout);
+ if (rc > 0)
+ DEBUGP(4, dev, "woke up: BulkIn full\n");
+ else if (rc == 0)
+ DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n");
+ else if (rc < 0)
+ DEBUGP(4, dev, "woke up: signal arrived\n");
+
+ return rc;
+}
+
+static ssize_t cm4040_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct reader_dev *dev = filp->private_data;
+ int iobase = dev->link.io.BasePort1;
+ size_t bytes_to_read;
+ unsigned long i;
+ size_t min_bytes_to_read;
+ int rc;
+ unsigned char uc;
+
+ DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0)
+ return 0;
+
+ if (count < 10)
+ return -EFAULT;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ DEBUGP(2, dev, "<- cm4040_read (failure)\n");
+ return -EAGAIN;
+ }
+
+ if ((dev->link.state & DEV_PRESENT)==0)
+ return -ENODEV;
+
+ for (i = 0; i < 5; i++) {
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+ dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 6)
+ printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+ }
+ printk("\n");
+#else
+ }
+#endif
+
+ bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);
+
+ DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);
+
+ min_bytes_to_read = min(count, bytes_to_read + 5);
+
+ DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);
+
+ for (i = 0; i < (min_bytes_to_read-5); i++) {
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+ dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 6)
+ printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+ }
+ printk("\n");
+#else
+ }
+#endif
+
+ *ppos = min_bytes_to_read;
+ if (copy_to_user(buf, dev->r_buf, min_bytes_to_read))
+ return -EFAULT;
+
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+
+ rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ uc = xinb(iobase + REG_OFFSET_BULK_IN);
+
+ DEBUGP(2, dev, "<- cm4040_read (successfully)\n");
+ return min_bytes_to_read;
+}
+
+static ssize_t cm4040_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct reader_dev *dev = filp->private_data;
+ int iobase = dev->link.io.BasePort1;
+ ssize_t rc;
+ int i;
+ unsigned int bytes_to_write;
+
+ DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) {
+ DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n");
+ return 0;
+ }
+
+ if (count < 5) {
+ DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count);
+ return -EIO;
+ }
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ DEBUGP(4, dev, "<- cm4040_write (failure)\n");
+ return -EAGAIN;
+ }
+
+ if ((dev->link.state & DEV_PRESENT) == 0)
+ return -ENODEV;
+
+ bytes_to_write = count;
+ if (copy_from_user(dev->s_buf, buf, bytes_to_write))
+ return -EFAULT;
+
+ switch (dev->s_buf[0]) {
+ case CMD_PC_TO_RDR_XFRBLOCK:
+ case CMD_PC_TO_RDR_SECURE:
+ case CMD_PC_TO_RDR_TEST_SECURE:
+ case CMD_PC_TO_RDR_OK_SECURE:
+ dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
+ break;
+
+ case CMD_PC_TO_RDR_ICCPOWERON:
+ dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
+ break;
+
+ case CMD_PC_TO_RDR_GETSLOTSTATUS:
+ case CMD_PC_TO_RDR_ICCPOWEROFF:
+ case CMD_PC_TO_RDR_GETPARAMETERS:
+ case CMD_PC_TO_RDR_RESETPARAMETERS:
+ case CMD_PC_TO_RDR_SETPARAMETERS:
+ case CMD_PC_TO_RDR_ESCAPE:
+ case CMD_PC_TO_RDR_ICCCLOCK:
+ default:
+ dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+ break;
+ }
+
+ rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ DEBUGP(4, dev, "start \n");
+
+ for (i = 0; i < bytes_to_write; i++) {
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
+ rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT);
+ }
+ DEBUGP(4, dev, "end\n");
+
+ rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
+
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ DEBUGP(2, dev, "<- cm4040_write (successfully)\n");
+ return count;
+}
+
+static unsigned int cm4040_poll(struct file *filp, poll_table *wait)
+{
+ struct reader_dev *dev = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &dev->poll_wait, wait);
+
+ if (test_and_clear_bit(BS_READABLE, &dev->buffer_status))
+ mask |= POLLIN | POLLRDNORM;
+ if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status))
+ mask |= POLLOUT | POLLWRNORM;
+
+ DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask);
+
+ return mask;
+}
+
+static int cm4040_open(struct inode *inode, struct file *filp)
+{
+ struct reader_dev *dev;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ if (minor >= CM_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL || !(DEV_OK(link)))
+ return -ENODEV;
+
+ if (link->open)
+ return -EBUSY;
+
+ dev = link->priv;
+ filp->private_data = dev;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ return -EAGAIN;
+ }
+
+ link->open = 1;
+
+ dev->poll_timer.data = (unsigned long) dev;
+ mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+
+ DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
+ return nonseekable_open(inode, filp);
+}
+
+static int cm4040_close(struct inode *inode, struct file *filp)
+{
+ struct reader_dev *dev = filp->private_data;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode),
+ iminor(inode));
+
+ if (minor >= CM_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL)
+ return -ENODEV;
+
+ cm4040_stop_poll(dev);
+
+ link->open = 0;
+ wake_up(&dev->devq);
+
+ DEBUGP(2, dev, "<- cm4040_close\n");
+ return 0;
+}
+
+static void cm4040_reader_release(dev_link_t *link)
+{
+ struct reader_dev *dev = link->priv;
+
+ DEBUGP(3, dev, "-> cm4040_reader_release\n");
+ while (link->open) {
+ DEBUGP(3, dev, KERN_INFO MODULE_NAME ": delaying release "
+ "until process has terminated\n");
+ wait_event(dev->devq, (link->open == 0));
+ }
+ DEBUGP(3, dev, "<- cm4040_reader_release\n");
+ return;
+}
+
+static void reader_config(dev_link_t *link, int devno)
+{
+ client_handle_t handle;
+ struct reader_dev *dev;
+ tuple_t tuple;
+ cisparse_t parse;
+ config_info_t conf;
+ u_char buf[64];
+ int fail_fn, fail_rc;
+ int rc;
+
+ handle = link->handle;
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetFirstTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetTupleData;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse))
+ != CS_SUCCESS) {
+ fail_fn = ParseTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_configuration_info(handle, &conf))
+ != CS_SUCCESS) {
+ fail_fn = GetConfigurationInfo;
+ goto cs_failed;
+ }
+
+ link->state |= DEV_CONFIG;
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+ link->conf.Vcc = conf.Vcc;
+
+ link->io.BasePort2 = 0;
+ link->io.NumPorts2 = 0;
+ link->io.Attributes2 = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ for (rc = pcmcia_get_first_tuple(handle, &tuple);
+ rc == CS_SUCCESS;
+ rc = pcmcia_get_next_tuple(handle, &tuple)) {
+ rc = pcmcia_get_tuple_data(handle, &tuple);
+ if (rc != CS_SUCCESS)
+ continue;
+ rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+ if (rc != CS_SUCCESS)
+ continue;
+
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+
+ if (!parse.cftable_entry.io.nwin)
+ continue;
+
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = parse.cftable_entry.io.flags
+ & CISTPL_IO_LINES_MASK;
+ rc = pcmcia_request_io(handle, &link->io);
+
+ dev_printk(KERN_INFO, &handle_to_dev(handle), "foo");
+ if (rc == CS_SUCCESS)
+ break;
+ else
+ dev_printk(KERN_INFO, &handle_to_dev(handle),
+ "pcmcia_request_io failed 0x%x\n", rc);
+ }
+ if (rc != CS_SUCCESS)
+ goto cs_release;
+
+ link->conf.IntType = 00000002;
+
+ if ((fail_rc = pcmcia_request_configuration(handle,&link->conf))
+ !=CS_SUCCESS) {
+ fail_fn = RequestConfiguration;
+ dev_printk(KERN_INFO, &handle_to_dev(handle),
+ "pcmcia_request_configuration failed 0x%x\n",
+ fail_rc);
+ goto cs_release;
+ }
+
+ dev = link->priv;
+ sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+ dev->node.major = major;
+ dev->node.minor = devno;
+ dev->node.next = NULL;
+ link->dev = &dev->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
+ link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
+ DEBUGP(2, dev, "<- reader_config (succ)\n");
+
+ return;
+
+cs_failed:
+ cs_error(handle, fail_fn, fail_rc);
+cs_release:
+ reader_release(link);
+ link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int reader_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link;
+ struct reader_dev *dev;
+ int devno;
+
+ link = args->client_data;
+ dev = link->priv;
+ DEBUGP(3, dev, "-> reader_event\n");
+ for (devno = 0; devno < CM_MAX_DEV; devno++) {
+ if (dev_table[devno] == link)
+ break;
+ }
+ if (devno == CM_MAX_DEV)
+ return CS_BAD_ADAPTER;
+
+ switch (event) {
+ case CS_EVENT_CARD_INSERTION:
+ DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ reader_config(link, devno);
+ break;
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+ link->state &= ~DEV_PRESENT;
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+ "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+ link->state |= DEV_SUSPEND;
+
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "ReleaseConfiguration\n");
+ pcmcia_release_configuration(link->handle);
+ }
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+ "(fall-through to CS_EVENT_CARD_RESET)\n");
+ link->state &= ~DEV_SUSPEND;
+
+ case CS_EVENT_CARD_RESET:
+ DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+ if ((link->state & DEV_CONFIG)) {
+ DEBUGP(5, dev, "RequestConfiguration\n");
+ pcmcia_request_configuration(link->handle,
+ &link->conf);
+ }
+ break;
+ default:
+ DEBUGP(5, dev, "reader_event: unknown event %.2x\n",
+ event);
+ break;
+ }
+ DEBUGP(3, dev, "<- reader_event\n");
+ return CS_SUCCESS;
+}
+
+static void reader_release(dev_link_t *link)
+{
+ cm4040_reader_release(link->priv);
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *reader_attach(void)
+{
+ struct reader_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int i;
+
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i] == NULL)
+ break;
+ }
+
+ if (i == CM_MAX_DEV)
+ return NULL;
+
+ dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL);
+ if (dev == NULL)
+ return NULL;
+
+ dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+ dev->buffer_status = 0;
+
+ link = &dev->link;
+ link->priv = dev;
+
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ dev_table[i] = link;
+
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask=
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ i = pcmcia_register_client(&link->handle, &client_reg);
+ if (i) {
+ cs_error(link->handle, RegisterClient, i);
+ reader_detach(link);
+ return NULL;
+ }
+ init_waitqueue_head(&dev->devq);
+ init_waitqueue_head(&dev->poll_wait);
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+ init_timer(&dev->poll_timer);
+ dev->poll_timer.function = &cm4040_do_poll;
+
+ return link;
+}
+
+static void reader_detach_by_devno(int devno, dev_link_t *link)
+{
+ struct reader_dev *dev = link->priv;
+
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "device still configured (try to release it)\n");
+ reader_release(link);
+ }
+
+ pcmcia_deregister_client(link->handle);
+ dev_table[devno] = NULL;
+ DEBUGP(5, dev, "freeing dev=%p\n", dev);
+ cm4040_stop_poll(dev);
+ kfree(dev);
+ return;
+}
+
+static void reader_detach(dev_link_t *link)
+{
+ int i;
+
+ /* find device */
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i] == link)
+ break;
+ }
+ if (i == CM_MAX_DEV)
+ return;
+
+ reader_detach_by_devno(i, link);
+ return;
+}
+
+static struct file_operations reader_fops = {
+ .owner = THIS_MODULE,
+ .read = cm4040_read,
+ .write = cm4040_write,
+ .open = cm4040_open,
+ .release = cm4040_close,
+ .poll = cm4040_poll,
+};
+
+static struct pcmcia_device_id cm4040_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
+ PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
+ 0xE32CDD8C, 0x8F23318B),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4040_ids);
+
+static struct pcmcia_driver reader_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "cm4040_cs",
+ },
+ .attach = reader_attach,
+ .detach = reader_detach,
+ .event = reader_event,
+ .id_table = cm4040_ids,
+};
+
+static int __init cm4040_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ pcmcia_register_driver(&reader_driver);
+ major = register_chrdev(0, DEVICE_NAME, &reader_fops);
+ if (major < 0) {
+ printk(KERN_WARNING MODULE_NAME
+ ": could not get major number\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void __exit cm4040_exit(void)
+{
+ int i;
+
+ printk(KERN_INFO MODULE_NAME ": unloading\n");
+ pcmcia_unregister_driver(&reader_driver);
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i])
+ reader_detach_by_devno(i, dev_table[i]);
+ }
+ unregister_chrdev(major, DEVICE_NAME);
+}
+
+module_init(cm4040_init);
+module_exit(cm4040_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/trunk/drivers/char/pcmcia/cm4040_cs.h b/trunk/drivers/char/pcmcia/cm4040_cs.h
new file mode 100644
index 000000000000..9a8b805c5095
--- /dev/null
+++ b/trunk/drivers/char/pcmcia/cm4040_cs.h
@@ -0,0 +1,47 @@
+#ifndef _CM4040_H_
+#define _CM4040_H_
+
+#define CM_MAX_DEV 4
+
+#define DEVICE_NAME "cmx"
+#define MODULE_NAME "cm4040_cs"
+
+#define REG_OFFSET_BULK_OUT 0
+#define REG_OFFSET_BULK_IN 0
+#define REG_OFFSET_BUFFER_STATUS 1
+#define REG_OFFSET_SYNC_CONTROL 2
+
+#define BSR_BULK_IN_FULL 0x02
+#define BSR_BULK_OUT_FULL 0x01
+
+#define SCR_HOST_TO_READER_START 0x80
+#define SCR_ABORT 0x40
+#define SCR_EN_NOTIFY 0x20
+#define SCR_ACK_NOTIFY 0x10
+#define SCR_READER_TO_HOST_DONE 0x08
+#define SCR_HOST_TO_READER_DONE 0x04
+#define SCR_PULSE_INTERRUPT 0x02
+#define SCR_POWER_DOWN 0x01
+
+
+#define CMD_PC_TO_RDR_ICCPOWERON 0x62
+#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65
+#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63
+#define CMD_PC_TO_RDR_SECURE 0x69
+#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C
+#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D
+#define CMD_PC_TO_RDR_SETPARAMETERS 0x61
+#define CMD_PC_TO_RDR_XFRBLOCK 0x6F
+#define CMD_PC_TO_RDR_ESCAPE 0x6B
+#define CMD_PC_TO_RDR_ICCCLOCK 0x6E
+#define CMD_PC_TO_RDR_TEST_SECURE 0x74
+#define CMD_PC_TO_RDR_OK_SECURE 0x89
+
+
+#define CMD_RDR_TO_PC_SLOTSTATUS 0x81
+#define CMD_RDR_TO_PC_DATABLOCK 0x80
+#define CMD_RDR_TO_PC_PARAMETERS 0x82
+#define CMD_RDR_TO_PC_ESCAPE 0x83
+#define CMD_RDR_TO_PC_OK_SECURE 0x89
+
+#endif /* _CM4040_H_ */
diff --git a/trunk/drivers/char/synclink.c b/trunk/drivers/char/synclink.c
index 82c6abde68df..62aa0e534a6d 100644
--- a/trunk/drivers/char/synclink.c
+++ b/trunk/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $
+ * $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -101,6 +101,7 @@
#include
#include
#include
+#include
#ifdef CONFIG_HDLC_MODULE
#define CONFIG_HDLC 1
@@ -148,6 +149,7 @@ typedef struct _DMABUFFERENTRY
u32 link; /* 32-bit flat link to next buffer entry */
char *virt_addr; /* virtual address of data buffer */
u32 phys_entry; /* physical address of this buffer entry */
+ dma_addr_t dma_addr;
} DMABUFFERENTRY, *DMAPBUFFERENTRY;
/* The queue of BH actions to be performed */
@@ -233,7 +235,8 @@ struct mgsl_struct {
int ri_chkcount;
char *buffer_list; /* virtual address of Rx & Tx buffer lists */
- unsigned long buffer_list_phys;
+ u32 buffer_list_phys;
+ dma_addr_t buffer_list_dma_addr;
unsigned int rx_buffer_count; /* count of total allocated Rx buffers */
DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */
@@ -896,7 +899,7 @@ module_param_array(txdmabufs, int, NULL, 0);
module_param_array(txholdbufs, int, NULL, 0);
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.37 $";
+static char *driver_version = "$Revision: 4.38 $";
static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
@@ -3811,11 +3814,10 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
/* inspect portions of the buffer while other portions are being */
/* updated by the adapter using Bus Master DMA. */
- info->buffer_list = kmalloc(BUFFERLISTSIZE, GFP_KERNEL | GFP_DMA);
- if ( info->buffer_list == NULL )
+ info->buffer_list = dma_alloc_coherent(NULL, BUFFERLISTSIZE, &info->buffer_list_dma_addr, GFP_KERNEL);
+ if (info->buffer_list == NULL)
return -ENOMEM;
-
- info->buffer_list_phys = isa_virt_to_bus(info->buffer_list);
+ info->buffer_list_phys = (u32)(info->buffer_list_dma_addr);
}
/* We got the memory for the buffer entry lists. */
@@ -3882,8 +3884,8 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
*/
static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
{
- if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree(info->buffer_list);
+ if (info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI)
+ dma_free_coherent(NULL, BUFFERLISTSIZE, info->buffer_list, info->buffer_list_dma_addr);
info->buffer_list = NULL;
info->rx_buffer_list = NULL;
@@ -3910,7 +3912,7 @@ static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount)
{
int i;
- unsigned long phys_addr;
+ u32 phys_addr;
/* Allocate page sized buffers for the receive buffer list */
@@ -3922,11 +3924,10 @@ static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *Buff
info->last_mem_alloc += DMABUFFERSIZE;
} else {
/* ISA adapter uses system memory. */
- BufferList[i].virt_addr =
- kmalloc(DMABUFFERSIZE, GFP_KERNEL | GFP_DMA);
- if ( BufferList[i].virt_addr == NULL )
+ BufferList[i].virt_addr = dma_alloc_coherent(NULL, DMABUFFERSIZE, &BufferList[i].dma_addr, GFP_KERNEL);
+ if (BufferList[i].virt_addr == NULL)
return -ENOMEM;
- phys_addr = isa_virt_to_bus(BufferList[i].virt_addr);
+ phys_addr = (u32)(BufferList[i].dma_addr);
}
BufferList[i].phys_addr = phys_addr;
}
@@ -3957,7 +3958,7 @@ static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *Buf
for ( i = 0 ; i < Buffercount ; i++ ) {
if ( BufferList[i].virt_addr ) {
if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree(BufferList[i].virt_addr);
+ dma_free_coherent(NULL, DMABUFFERSIZE, BufferList[i].virt_addr, BufferList[i].dma_addr);
BufferList[i].virt_addr = NULL;
}
}
diff --git a/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c
index 303f15880466..0b283d246730 100644
--- a/trunk/drivers/char/tpm/tpm.c
+++ b/trunk/drivers/char/tpm/tpm.c
@@ -43,6 +43,13 @@ static void user_reader_timeout(unsigned long ptr)
{
struct tpm_chip *chip = (struct tpm_chip *) ptr;
+ schedule_work(&chip->work);
+}
+
+static void timeout_work(void * ptr)
+{
+ struct tpm_chip *chip = ptr;
+
down(&chip->buffer_mutex);
atomic_set(&chip->data_pending, 0);
memset(chip->data_buffer, 0, TPM_BUFSIZE);
@@ -428,8 +435,7 @@ ssize_t tpm_read(struct file * file, char __user *buf,
ret_size = size;
down(&chip->buffer_mutex);
- if (copy_to_user
- ((void __user *) buf, chip->data_buffer, ret_size))
+ if (copy_to_user(buf, chip->data_buffer, ret_size))
ret_size = -EFAULT;
up(&chip->buffer_mutex);
}
@@ -460,7 +466,7 @@ void tpm_remove_hardware(struct device *dev)
sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
- !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
+ ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
kfree(chip);
@@ -528,6 +534,8 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry)
init_MUTEX(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
+ INIT_WORK(&chip->work, timeout_work, chip);
+
init_timer(&chip->user_read_timer);
chip->user_read_timer.function = user_reader_timeout;
chip->user_read_timer.data = (unsigned long) chip;
diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h
index 9293bcc4dc62..159882ca69dd 100644
--- a/trunk/drivers/char/tpm/tpm.h
+++ b/trunk/drivers/char/tpm/tpm.h
@@ -50,7 +50,11 @@ struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
u8 req_canceled;
- u16 base; /* TPM base address */
+ void __iomem *iobase; /* ioremapped address */
+ unsigned long base; /* TPM base address */
+
+ int region_size;
+ int have_region;
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
@@ -73,6 +77,7 @@ struct tpm_chip {
struct semaphore buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
+ struct work_struct work;
struct semaphore tpm_mutex; /* tpm is processing */
struct tpm_vendor_specific *vendor;
diff --git a/trunk/drivers/char/tpm/tpm_atmel.c b/trunk/drivers/char/tpm/tpm_atmel.c
index 32e01450c425..deb4b5c80914 100644
--- a/trunk/drivers/char/tpm/tpm_atmel.c
+++ b/trunk/drivers/char/tpm/tpm_atmel.c
@@ -19,14 +19,8 @@
*
*/
-#include
#include "tpm.h"
-
-/* Atmel definitions */
-enum tpm_atmel_addr {
- TPM_ATMEL_BASE_ADDR_LO = 0x08,
- TPM_ATMEL_BASE_ADDR_HI = 0x09
-};
+#include "tpm_atmel.h"
/* write status bits */
enum tpm_atmel_write_status {
@@ -53,13 +47,13 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO;
for (i = 0; i < 6; i++) {
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading header\n");
return -EIO;
}
- *buf++ = inb(chip->vendor->base);
+ *buf++ = atmel_getb(chip, 0);
}
/* size of the data received */
@@ -70,7 +64,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
dev_err(chip->dev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading data\n");
@@ -82,17 +76,17 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read all the data available */
for (; i < size; i++) {
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading data\n");
return -EIO;
}
- *buf++ = inb(chip->vendor->base);
+ *buf++ = atmel_getb(chip, 0);
}
/* make sure data available is gone */
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if (status & ATML_STATUS_DATA_AVAIL) {
dev_err(chip->dev, "data available is stuck\n");
return -EIO;
@@ -108,7 +102,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
dev_dbg(chip->dev, "tpm_atml_send:\n");
for (i = 0; i < count; i++) {
dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
- outb(buf[i], chip->vendor->base);
+ atmel_putb(buf[i], chip, 0);
}
return count;
@@ -116,12 +110,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
static void tpm_atml_cancel(struct tpm_chip *chip)
{
- outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+ atmel_putb(ATML_STATUS_ABORT, chip, 1);
}
static u8 tpm_atml_status(struct tpm_chip *chip)
{
- return inb(chip->vendor->base + 1);
+ return atmel_getb(chip, 1);
}
static struct file_operations atmel_ops = {
@@ -162,12 +156,16 @@ static struct tpm_vendor_specific tpm_atmel = {
static struct platform_device *pdev;
-static void __devexit tpm_atml_remove(struct device *dev)
+static void atml_plat_remove(void)
{
- struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
if (chip) {
- release_region(chip->vendor->base, 2);
+ if (chip->vendor->have_region)
+ atmel_release_region(chip->vendor->base, chip->vendor->region_size);
+ atmel_put_base_addr(chip->vendor);
tpm_remove_hardware(chip->dev);
+ platform_device_unregister(pdev);
}
}
@@ -182,72 +180,40 @@ static struct device_driver atml_drv = {
static int __init init_atmel(void)
{
int rc = 0;
- int lo, hi;
driver_register(&atml_drv);
- lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
- hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
-
- tpm_atmel.base = (hi<<8)|lo;
-
- /* verify that it is an Atmel part */
- if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
- || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
- return -ENODEV;
- }
-
- /* verify chip version number is 1.1 */
- if ( (tpm_read_index(TPM_ADDR, 0x00) != 0x01) ||
- (tpm_read_index(TPM_ADDR, 0x01) != 0x01 ))
- return -ENODEV;
-
- pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
- if ( !pdev )
- return -ENOMEM;
-
- pdev->name = "tpm_atmel0";
- pdev->id = -1;
- pdev->num_resources = 0;
- pdev->dev.release = tpm_atml_remove;
- pdev->dev.driver = &atml_drv;
-
- if ((rc = platform_device_register(pdev)) < 0) {
- kfree(pdev);
- pdev = NULL;
- return rc;
+ if (atmel_get_base_addr(&tpm_atmel) != 0) {
+ rc = -ENODEV;
+ goto err_unreg_drv;
}
- if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) {
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- return -EBUSY;
- }
+ tpm_atmel.have_region = (atmel_request_region( tpm_atmel.base, tpm_atmel.region_size, "tpm_atmel0") == NULL) ? 0 : 1;
- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) {
- release_region(tpm_atmel.base, 2);
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- return rc;
+ if (IS_ERR(pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0 ))) {
+ rc = PTR_ERR(pdev);
+ goto err_rel_reg;
}
- dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n",
- tpm_atmel.base);
+ if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0)
+ goto err_unreg_dev;
return 0;
+
+err_unreg_dev:
+ platform_device_unregister(pdev);
+err_rel_reg:
+ if (tpm_atmel.have_region)
+ atmel_release_region(tpm_atmel.base, tpm_atmel.region_size);
+ atmel_put_base_addr(&tpm_atmel);
+err_unreg_drv:
+ driver_unregister(&atml_drv);
+ return rc;
}
static void __exit cleanup_atmel(void)
{
- if (pdev) {
- tpm_atml_remove(&pdev->dev);
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- }
-
driver_unregister(&atml_drv);
+ atml_plat_remove();
}
module_init(init_atmel);
diff --git a/trunk/drivers/char/tpm/tpm_atmel.h b/trunk/drivers/char/tpm/tpm_atmel.h
new file mode 100644
index 000000000000..3c5b9a8d1c49
--- /dev/null
+++ b/trunk/drivers/char/tpm/tpm_atmel.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall
+ *
+ * Maintained by:
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * 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.
+ *
+ * These difference are required on power because the device must be
+ * discovered through the device tree and iomap must be used to get
+ * around the need for holes in the io_page_mask. This does not happen
+ * automatically because the tpm is not a normal pci device and lives
+ * under the root node.
+ *
+ */
+
+#ifdef CONFIG_PPC64
+#define atmel_getb(chip, offset) readb(chip->vendor->iobase + offset);
+#define atmel_putb(val, chip, offset) writeb(val, chip->vendor->iobase + offset)
+#define atmel_request_region request_mem_region
+#define atmel_release_region release_mem_region
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+ iounmap(vendor->iobase);
+}
+
+static int atmel_get_base_addr(struct tpm_vendor_specific *vendor)
+{
+ struct device_node *dn;
+ unsigned long address, size;
+ unsigned int *reg;
+ int reglen;
+ int naddrc;
+ int nsizec;
+
+ dn = of_find_node_by_name(NULL, "tpm");
+
+ if (!dn)
+ return 1;
+
+ if (!device_is_compatible(dn, "AT97SC3201")) {
+ of_node_put(dn);
+ return 1;
+ }
+
+ reg = (unsigned int *) get_property(dn, "reg", ®len);
+ naddrc = prom_n_addr_cells(dn);
+ nsizec = prom_n_size_cells(dn);
+
+ of_node_put(dn);
+
+
+ if (naddrc == 2)
+ address = ((unsigned long) reg[0] << 32) | reg[1];
+ else
+ address = reg[0];
+
+ if (nsizec == 2)
+ size =
+ ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1];
+ else
+ size = reg[naddrc];
+
+ vendor->base = address;
+ vendor->region_size = size;
+ vendor->iobase = ioremap(address, size);
+ return 0;
+}
+#else
+#define atmel_getb(chip, offset) inb(chip->vendor->base + offset)
+#define atmel_putb(val, chip, offset) outb(val, chip->vendor->base + offset)
+#define atmel_request_region request_region
+#define atmel_release_region release_region
+/* Atmel definitions */
+enum tpm_atmel_addr {
+ TPM_ATMEL_BASE_ADDR_LO = 0x08,
+ TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
+
+/* Verify this is a 1.1 Atmel TPM */
+static int atmel_verify_tpm11(void)
+{
+
+ /* verify that it is an Atmel part */
+ if (tpm_read_index(TPM_ADDR, 4) != 'A' ||
+ tpm_read_index(TPM_ADDR, 5) != 'T' ||
+ tpm_read_index(TPM_ADDR, 6) != 'M' ||
+ tpm_read_index(TPM_ADDR, 7) != 'L')
+ return 1;
+
+ /* query chip for its version number */
+ if (tpm_read_index(TPM_ADDR, 0x00) != 1 ||
+ tpm_read_index(TPM_ADDR, 0x01) != 1)
+ return 1;
+
+ /* This is an atmel supported part */
+ return 0;
+}
+
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+}
+
+/* Determine where to talk to device */
+static unsigned long atmel_get_base_addr(struct tpm_vendor_specific
+ *vendor)
+{
+ int lo, hi;
+
+ if (atmel_verify_tpm11() != 0)
+ return 1;
+
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+ vendor->base = (hi << 8) | lo;
+ vendor->region_size = 2;
+
+ return 0;
+}
+#endif
diff --git a/trunk/drivers/char/watchdog/booke_wdt.c b/trunk/drivers/char/watchdog/booke_wdt.c
index abc30cca6645..65830ec71042 100644
--- a/trunk/drivers/char/watchdog/booke_wdt.c
+++ b/trunk/drivers/char/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
* Watchdog timer for PowerPC Book-E systems
*
* Author: Matthew McClintock
- * Maintainer: Kumar Gala
+ * Maintainer: Kumar Gala
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/trunk/drivers/ide/pci/sl82c105.c b/trunk/drivers/ide/pci/sl82c105.c
index ea0806c82be0..8a5c7b286b2b 100644
--- a/trunk/drivers/ide/pci/sl82c105.c
+++ b/trunk/drivers/ide/pci/sl82c105.c
@@ -399,34 +399,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
return dev->irq;
}
-static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
- unsigned int rev;
- u8 dma_state;
-
- DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
-
- hwif->autodma = 0;
-
- if (!dma_base)
- return;
-
- dma_state = hwif->INB(dma_base + 2);
- rev = sl82c105_bridge_revision(hwif->pci_dev);
- if (rev <= 5) {
- printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
- hwif->name, rev);
- dma_state &= ~0x60;
- } else {
- dma_state |= 0x60;
- if (!noautodma)
- hwif->autodma = 1;
- }
- hwif->OUTB(dma_state, dma_base + 2);
-
- ide_setup_dma(hwif, dma_base, 8);
-}
-
/*
* Initialise the chip
*/
@@ -434,6 +406,8 @@ static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
+ unsigned int rev;
+ u8 dma_state;
u32 val;
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
@@ -455,33 +429,54 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
pci_read_config_dword(dev, 0x40, &val);
*((u32 *)&hwif->hwif_data) = val;
+ hwif->atapi_dma = 0;
+ hwif->mwdma_mask = 0;
+ hwif->swdma_mask = 0;
+ hwif->autodma = 0;
+
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
+ dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60;
+ rev = sl82c105_bridge_revision(hwif->pci_dev);
+ if (rev <= 5) {
+ /*
+ * Never ever EVER under any circumstances enable
+ * DMA when the bridge is this old.
+ */
+ printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+ hwif->name, rev);
+ } else {
#ifdef CONFIG_BLK_DEV_IDEDMA
- hwif->ide_dma_check = &sl82c105_check_drive;
- hwif->ide_dma_on = &sl82c105_ide_dma_on;
- hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
- hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
- hwif->dma_start = &sl82c105_ide_dma_start;
- hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ dma_state |= 0x60;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &sl82c105_check_drive;
+ hwif->ide_dma_on = &sl82c105_ide_dma_on;
+ hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+ hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+ hwif->dma_start = &sl82c105_ide_dma_start;
+ hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
#endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
+ hwif->OUTB(dma_state, hwif->dma_base + 2);
}
static ide_pci_device_t sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
.init_hwif = init_hwif_sl82c105,
- .init_dma = init_dma_sl82c105,
.channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
diff --git a/trunk/drivers/ide/ppc/pmac.c b/trunk/drivers/ide/ppc/pmac.c
index b3e65a65d202..136911a86e84 100644
--- a/trunk/drivers/ide/ppc/pmac.c
+++ b/trunk/drivers/ide/ppc/pmac.c
@@ -1667,11 +1667,16 @@ static struct macio_driver pmac_ide_macio_driver =
};
static struct pci_device_id pmac_ide_pci_match[] = {
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
};
static struct pci_driver pmac_ide_pci_driver = {
diff --git a/trunk/drivers/media/common/ir-common.c b/trunk/drivers/media/common/ir-common.c
index 4b71fd6f7aed..7972c73bc14e 100644
--- a/trunk/drivers/media/common/ir-common.c
+++ b/trunk/drivers/media/common/ir-common.c
@@ -126,6 +126,66 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+ [ 0x59 ] = KEY_MUTE,
+ [ 0x4a ] = KEY_POWER,
+
+ [ 0x18 ] = KEY_TEXT,
+ [ 0x26 ] = KEY_TV,
+ [ 0x3d ] = KEY_PRINT,
+
+ [ 0x48 ] = KEY_RED,
+ [ 0x04 ] = KEY_GREEN,
+ [ 0x11 ] = KEY_YELLOW,
+ [ 0x00 ] = KEY_BLUE,
+
+ [ 0x2d ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+
+ [ 0x49 ] = KEY_MENU,
+
+ [ 0x16 ] = KEY_CHANNELUP,
+ [ 0x17 ] = KEY_CHANNELDOWN,
+
+ [ 0x20 ] = KEY_UP,
+ [ 0x21 ] = KEY_DOWN,
+ [ 0x22 ] = KEY_LEFT,
+ [ 0x23 ] = KEY_RIGHT,
+ [ 0x0d ] = KEY_SELECT,
+
+
+
+ [ 0x08 ] = KEY_BACK,
+ [ 0x07 ] = KEY_REFRESH,
+
+ [ 0x2f ] = KEY_ZOOM,
+ [ 0x29 ] = KEY_RECORD,
+
+ [ 0x4b ] = KEY_PAUSE,
+ [ 0x4d ] = KEY_REWIND,
+ [ 0x2e ] = KEY_PLAY,
+ [ 0x4e ] = KEY_FORWARD,
+ [ 0x53 ] = KEY_PREVIOUS,
+ [ 0x4c ] = KEY_STOP,
+ [ 0x54 ] = KEY_NEXT,
+
+ [ 0x69 ] = KEY_KP0,
+ [ 0x6a ] = KEY_KP1,
+ [ 0x6b ] = KEY_KP2,
+ [ 0x6c ] = KEY_KP3,
+ [ 0x6d ] = KEY_KP4,
+ [ 0x6e ] = KEY_KP5,
+ [ 0x6f ] = KEY_KP6,
+ [ 0x70 ] = KEY_KP7,
+ [ 0x71 ] = KEY_KP8,
+ [ 0x72 ] = KEY_KP9,
+
+ [ 0x74 ] = KEY_CHANNEL,
+ [ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
/* empty keytable, can be used as placeholder for not-yet created keytables */
IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
[ 42 ] = KEY_COFFEE,
diff --git a/trunk/drivers/media/video/Kconfig b/trunk/drivers/media/video/Kconfig
index 199b01188858..1a3b3c7e5e99 100644
--- a/trunk/drivers/media/video/Kconfig
+++ b/trunk/drivers/media/video/Kconfig
@@ -333,4 +333,18 @@ config VIDEO_M32R_AR_M64278
Say Y here to use the Renesas M64278E-800 camera module,
which supports VGA(640x480 pixcels) size of images.
+config VIDEO_AUDIO_DECODER
+ tristate "Add support for additional audio chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for WM8775 and CS53L32A audio
+ decoders.
+
+config VIDEO_DECODER
+ tristate "Add support for additional video chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
+ video decoders.
+
endmenu
diff --git a/trunk/drivers/media/video/Makefile b/trunk/drivers/media/video/Makefile
index 3ac465992400..82060f9909d8 100644
--- a/trunk/drivers/media/video/Makefile
+++ b/trunk/drivers/media/video/Makefile
@@ -36,10 +36,11 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
+obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -55,4 +56,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o
+
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/trunk/drivers/media/video/bttv-cards.c b/trunk/drivers/media/video/bttv-cards.c
index 3413bace443a..e31ebb11c468 100644
--- a/trunk/drivers/media/video/bttv-cards.c
+++ b/trunk/drivers/media/video/bttv-cards.c
@@ -2133,7 +2133,10 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
+ .has_remote = 1,
+ .gpiomask = 0x1b,
.no_gpioirq = 1,
+ .any_irq = 1,
},
[BTTV_BOARD_PV143] = {
/* Jorge Boncompte - DTI2 */
@@ -2796,7 +2799,24 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
-
+ /* ---- card 0x8e ---------------------------------- */
+ [BTTV_BOARD_SABRENT_TVFM] = {
+ .name = "Sabrent TV-FM (bttv version)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x108007,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 100000, 100002, 100002, 100000},
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TNF_5335MF,
+ .tuner_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3367,6 +3387,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_remote=1;
if (!bttv_tvcards[btv->c.type].no_gpioirq)
btv->gpioirq=1;
+ if (bttv_tvcards[btv->c.type].any_irq)
+ btv->any_irq = 1;
if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
diff --git a/trunk/drivers/media/video/bttv-driver.c b/trunk/drivers/media/video/bttv-driver.c
index 0005741d5514..709099f03bd2 100644
--- a/trunk/drivers/media/video/bttv-driver.c
+++ b/trunk/drivers/media/video/bttv-driver.c
@@ -3667,6 +3667,10 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
int handled = 0;
btv=(struct bttv *)dev_id;
+
+ if (btv->any_irq)
+ handled = bttv_any_irq(&btv->c);
+
count=0;
while (1) {
/* get/clear interrupt status bits */
diff --git a/trunk/drivers/media/video/bttv-gpio.c b/trunk/drivers/media/video/bttv-gpio.c
index 575ce8b8e714..616a5b7e510c 100644
--- a/trunk/drivers/media/video/bttv-gpio.c
+++ b/trunk/drivers/media/video/bttv-gpio.c
@@ -113,6 +113,24 @@ void bttv_gpio_irq(struct bttv_core *core)
}
}
+int bttv_any_irq(struct bttv_core *core)
+{
+ struct bttv_sub_driver *drv;
+ struct bttv_sub_device *dev;
+ struct list_head *item;
+ int handled = 0;
+
+ list_for_each(item,&core->subs) {
+ dev = list_entry(item,struct bttv_sub_device,list);
+ drv = to_bttv_sub_drv(dev->dev.driver);
+ if (drv && drv->any_irq) {
+ if (drv->any_irq(dev))
+ handled = 1;
+ }
+ }
+ return handled;
+}
+
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/trunk/drivers/media/video/bttv.h b/trunk/drivers/media/video/bttv.h
index 124ea41dada4..93298f06e019 100644
--- a/trunk/drivers/media/video/bttv.h
+++ b/trunk/drivers/media/video/bttv.h
@@ -162,6 +162,7 @@
#define BTTV_BOARD_PV_M4900 0x8b
#define BTTV_BOARD_OSPREY440 0x8c
#define BTTV_BOARD_ASOUND_SKYEYE 0x8d
+#define BTTV_BOARD_SABRENT_TVFM 0x8e
/* i2c address list */
#define I2C_TSA5522 0xc2
@@ -234,6 +235,7 @@ struct tvcard
unsigned int has_dvb:1;
unsigned int has_remote:1;
unsigned int no_gpioirq:1;
+ unsigned int any_irq:1;
/* other settings */
unsigned int pll;
@@ -333,6 +335,7 @@ struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub);
+ int (*any_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/trunk/drivers/media/video/bttvp.h b/trunk/drivers/media/video/bttvp.h
index 386f546f7d11..3aa9c6e4fc33 100644
--- a/trunk/drivers/media/video/bttvp.h
+++ b/trunk/drivers/media/video/bttvp.h
@@ -208,6 +208,7 @@ extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core);
+int bttv_any_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
@@ -273,6 +274,7 @@ struct bttv {
struct bttv_pll_info pll;
int triton1;
int gpioirq;
+ int any_irq;
int use_i2c_hw;
/* old gpio interface */
diff --git a/trunk/drivers/media/video/cx25840/Makefile b/trunk/drivers/media/video/cx25840/Makefile
new file mode 100644
index 000000000000..543ebacdc9d7
--- /dev/null
+++ b/trunk/drivers/media/video/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+ cx25840-vbi.o
+
+obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/trunk/drivers/media/video/cx25840/cx25840-audio.c b/trunk/drivers/media/video/cx25840/cx25840-audio.c
new file mode 100644
index 000000000000..740908f8027d
--- /dev/null
+++ b/trunk/drivers/media/video/cx25840/cx25840-audio.c
@@ -0,0 +1,368 @@
+/* cx25840 audio functions
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include
+#include
+#include