diff -wur linux-2.6.10/MAINTAINERS linux-2.6.10-lab/MAINTAINERS
--- linux-2.6.10/MAINTAINERS 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/MAINTAINERS 2007-10-04 19:10:40.000000000 -0400
@@ -937,6 +937,13 @@
L: iss_storagedev@hp.com
S: Supported
+HOST AP DRIVER
+P: Jouni Malinen
+M: jkmaline@cc.hut.fi
+L: hostap@shmoo.com
+W: http://hostap.epitest.fi/
+S: Maintained
+
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
P: Jaroslav Kysela
M: perex@suse.cz
diff -wur linux-2.6.10/Makefile linux-2.6.10-lab/Makefile
--- linux-2.6.10/Makefile 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -4,6 +4,19 @@
EXTRAVERSION =
NAME=Woozy Numbat
+#
+# The following six lines makes this make default to
+# a cross-compiled arm version of Linux. This makes
+# it easier to drive make directly (without all the extra params
+# each time or the requirement of a separate script).
+#
+ifndef ARCH
+ARCH=arm
+endif
+ifndef CROSS_COMPILE
+CROSS_COMPILE=arm-linux-
+endif
+
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
# More info can be located in ./README
@@ -203,7 +216,8 @@
HOSTCC = gcc
HOSTCXX = g++
-HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -idirafter "`$(CC) -print-file-name=include`/../../../../../include/"
+
HOSTCXXFLAGS = -O2
# Decide whether to build built-in, modular, or both.
@@ -866,11 +880,11 @@
.PHONY: _modinst_
_modinst_:
- @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
- echo "Warning: you may need to install module-init-tools"; \
- echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
- sleep 1; \
- fi
+## @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
+## echo "Warning: you may need to install module-init-tools"; \
+## echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
+## sleep 1; \
+## fi
@rm -rf $(MODLIB)/kernel
@rm -f $(MODLIB)/source
@mkdir -p $(MODLIB)/kernel
@@ -893,7 +907,9 @@
endif
.PHONY: _modinst_post
_modinst_post: _modinst_
- if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+## if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+ @rm -f $(MODLIB)/build
+ @rm -f $(MODLIB)/source
else # CONFIG_MODULES
@@ -970,7 +986,8 @@
#
mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS))
mrproper: rm-files := $(wildcard $(MRPROPER_FILES))
-mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts)
+# mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts)
+mrproper-dirs := $(addprefix _mrproper_,scripts)
.PHONY: $(mrproper-dirs) mrproper archmrproper
$(mrproper-dirs):
@@ -1063,8 +1080,8 @@
# Documentation targets
# ---------------------------------------------------------------------------
-%docs: scripts_basic FORCE
- $(Q)$(MAKE) $(build)=Documentation/DocBook $@
+# %docs: scripts_basic FORCE
+# $(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # KBUILD_EXTMOD
diff -wur linux-2.6.10/arch/arm/Kconfig linux-2.6.10-lab/arch/arm/Kconfig
--- linux-2.6.10/arch/arm/Kconfig 2004-12-24 16:34:57.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Kconfig 2007-10-04 19:13:12.000000000 -0400
@@ -83,8 +83,8 @@
config ARCH_CO285
bool "Co-EBSA285"
- select FOOTBRIDGE
- select FOOTBRIDGE_ADDIN
+# select FOOTBRIDGE
+# select FOOTBRIDGE_ADDIN
config ARCH_EBSA110
bool "EBSA-110"
@@ -103,7 +103,7 @@
config ARCH_FOOTBRIDGE
bool "FootBridge"
- select FOOTBRIDGE
+# select FOOTBRIDGE
config ARCH_INTEGRATOR
bool "Integrator"
@@ -177,35 +177,35 @@
endchoice
-source "arch/arm/mach-clps711x/Kconfig"
+# source "arch/arm/mach-clps711x/Kconfig"
-source "arch/arm/mach-epxa10db/Kconfig"
+# source "arch/arm/mach-epxa10db/Kconfig"
-source "arch/arm/mach-footbridge/Kconfig"
+# source "arch/arm/mach-footbridge/Kconfig"
-source "arch/arm/mach-integrator/Kconfig"
+# source "arch/arm/mach-integrator/Kconfig"
-source "arch/arm/mach-iop3xx/Kconfig"
+# source "arch/arm/mach-iop3xx/Kconfig"
-source "arch/arm/mach-ixp4xx/Kconfig"
+# source "arch/arm/mach-ixp4xx/Kconfig"
-source "arch/arm/mach-ixp2000/Kconfig"
+# source "arch/arm/mach-ixp2000/Kconfig"
source "arch/arm/mach-pxa/Kconfig"
-source "arch/arm/mach-sa1100/Kconfig"
+# source "arch/arm/mach-sa1100/Kconfig"
-source "arch/arm/mach-omap/Kconfig"
+# source "arch/arm/mach-omap/Kconfig"
-source "arch/arm/mach-s3c2410/Kconfig"
+# source "arch/arm/mach-s3c2410/Kconfig"
-source "arch/arm/mach-lh7a40x/Kconfig"
+# source "arch/arm/mach-lh7a40x/Kconfig"
-source "arch/arm/mach-imx/Kconfig"
+# source "arch/arm/mach-imx/Kconfig"
-source "arch/arm/mach-h720x/Kconfig"
+# source "arch/arm/mach-h720x/Kconfig"
-source "arch/arm/mach-versatile/Kconfig"
+# source "arch/arm/mach-versatile/Kconfig"
# Definitions to make life easier
config ARCH_ACORN
@@ -396,7 +396,7 @@
In any case, make sure that MTD support is configured out for
the first attempt.
-if (ARCH_SA1100 || ARCH_INTEGRATOR)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA)
source "drivers/cpufreq/Kconfig"
@@ -421,9 +421,22 @@
If in doubt, say Y.
+config CPU_FREQ_PXA
+ bool
+ depends on CPU_FREQ && ARCH_PXA
+ default y
+ select CPU_FREQ_DEFAULT_GOV_USERSPACE
+
+config CPU_FREQ_TABLE
+ tristate
+ depends on CPU_FREQ
+ default y
+
endif
-source "drivers/pci/Kconfig"
+source "drivers/gpio/Kconfig"
+
+# source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
@@ -482,25 +495,7 @@
source "drivers/base/Kconfig"
-config PM
- bool "Power Management support"
- ---help---
- "Power Management" means that parts of your computer are shut
- off or put into a power conserving "sleep" mode if they are not
- being used. There are two competing standards for doing this: APM
- and ACPI. If you want to use either one, say Y here and then also
- to the requisite support below.
-
- Power Management is most important for battery powered laptop
- computers; if you have a laptop, check out the Linux Laptop home
- page on the WWW at or
- Tuxmobil - Linux on Mobile Computers at
- and the Battery Powered Linux mini-HOWTO, available from
- .
-
- Note that, even if you say N here, Linux on the x86 architecture
- will issue the hlt instruction if nothing is to be done, thereby
- sending the processor to sleep and saving power.
+source "kernel/power/Kconfig"
config PREEMPT
bool "Preemptible Kernel (EXPERIMENTAL)"
@@ -650,35 +645,35 @@
endmenu
-source "drivers/parport/Kconfig"
+# source "drivers/parport/Kconfig"
if ALIGNMENT_TRAP
source "drivers/mtd/Kconfig"
endif
-source "drivers/pnp/Kconfig"
+# source "drivers/pnp/Kconfig"
source "drivers/block/Kconfig"
-source "drivers/md/Kconfig"
+# source "drivers/md/Kconfig"
-source "drivers/acorn/block/Kconfig"
+# source "drivers/acorn/block/Kconfig"
source "net/Kconfig"
if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE
-source "drivers/ide/Kconfig"
+# source "drivers/ide/Kconfig"
endif
source "drivers/scsi/Kconfig"
-source "drivers/message/fusion/Kconfig"
+# source "drivers/message/fusion/Kconfig"
-source "drivers/ieee1394/Kconfig"
+# source "drivers/ieee1394/Kconfig"
-source "drivers/message/i2o/Kconfig"
+# source "drivers/message/i2o/Kconfig"
-source "drivers/isdn/Kconfig"
+# source "drivers/isdn/Kconfig"
#
# input before char - char/joystick depends on it. As does USB.
@@ -691,7 +686,7 @@
#source "drivers/l3/Kconfig"
-source "drivers/media/Kconfig"
+# source "drivers/media/Kconfig"
source "fs/Kconfig"
@@ -714,3 +709,4 @@
source "crypto/Kconfig"
source "lib/Kconfig"
+
diff -wur linux-2.6.10/arch/arm/Kconfig.debug linux-2.6.10-lab/arch/arm/Kconfig.debug
--- linux-2.6.10/arch/arm/Kconfig.debug 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Kconfig.debug 2007-10-04 19:10:15.000000000 -0400
@@ -115,4 +115,5 @@
The uncompressor code port configuration is now handled
by CONFIG_S3C2410_LOWLEVEL_UART_PORT.
+source "drivers/char/ppoke/Kconfig"
endmenu
diff -wur linux-2.6.10/arch/arm/Makefile linux-2.6.10-lab/arch/arm/Makefile
--- linux-2.6.10/arch/arm/Makefile 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Makefile 2007-10-04 19:10:15.000000000 -0400
@@ -144,8 +144,8 @@
core-$(CONFIG_VFP) += arch/arm/vfp/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
-drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
-drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
+# drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
+# drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
libs-y += arch/arm/lib/
diff -wur linux-2.6.10/arch/arm/kernel/compat.c linux-2.6.10-lab/arch/arm/kernel/compat.c
--- linux-2.6.10/arch/arm/kernel/compat.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/compat.c 2007-10-04 19:10:14.000000000 -0400
@@ -64,8 +64,12 @@
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
+#ifdef CONFIG_ARCH_FIONA
+ unsigned char system_serial_data[BOARD_SERIALNUM_SIZE];
+#else
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
+#endif
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
@@ -143,8 +147,12 @@
tag = tag_next(tag);
tag->hdr.tag = ATAG_SERIAL;
tag->hdr.size = tag_size(tag_serialnr);
+#ifdef CONFIG_ARCH_FIONA
+ memcpy(tag->u.serialnr.data, params->u1.s.system_serial_data, BOARD_SERIALNUM_SIZE);
+#else
tag->u.serialnr.low = params->u1.s.system_serial_low;
tag->u.serialnr.high = params->u1.s.system_serial_high;
+#endif
tag = tag_next(tag);
tag->hdr.tag = ATAG_REVISION;
diff -wur linux-2.6.10/arch/arm/kernel/process.c linux-2.6.10-lab/arch/arm/kernel/process.c
--- linux-2.6.10/arch/arm/kernel/process.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/process.c 2007-10-04 19:10:14.000000000 -0400
@@ -33,6 +33,10 @@
#include
#include
+#ifdef CONFIG_ARCH_FIONA
+#include
+#endif
+
extern const char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
@@ -152,6 +156,14 @@
*/
setup_mm_for_reboot(reboot_mode);
+#ifdef CONFIG_ARCH_FIONA
+ // set the OneNAND back into async read mode so bootloader can fetch page zero
+ fiona_set_onenand_async();
+
+ // reset the OneNAND DBS bit to ensure the proper page zero is present
+ fiona_reset_onenand_dbs_bit();
+#endif
+
/*
* Now call the architecture specific reboot code.
*/
diff -wur linux-2.6.10/arch/arm/kernel/setup.c linux-2.6.10-lab/arch/arm/kernel/setup.c
--- linux-2.6.10/arch/arm/kernel/setup.c 2004-12-24 16:34:57.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/setup.c 2007-10-04 19:10:14.000000000 -0400
@@ -67,12 +67,19 @@
unsigned int system_rev;
EXPORT_SYMBOL(system_rev);
+unsigned int board_resistance = 0;
+EXPORT_SYMBOL(board_resistance);
+#ifdef CONFIG_ARCH_FIONA
+unsigned char system_serial_data[BOARD_SERIALNUM_SIZE];
+EXPORT_SYMBOL(system_serial_data);
+#else
unsigned int system_serial_low;
EXPORT_SYMBOL(system_serial_low);
unsigned int system_serial_high;
EXPORT_SYMBOL(system_serial_high);
+#endif
unsigned int elf_hwcap;
EXPORT_SYMBOL(elf_hwcap);
@@ -595,8 +602,12 @@
static int __init parse_tag_serialnr(const struct tag *tag)
{
+#ifdef CONFIG_ARCH_FIONA
+ memcpy(system_serial_data, tag->u.serialnr.data, BOARD_SERIALNUM_SIZE);
+#else
system_serial_low = tag->u.serialnr.low;
system_serial_high = tag->u.serialnr.high;
+#endif
return 0;
}
@@ -610,6 +621,16 @@
__tagtable(ATAG_REVISION, parse_tag_revision);
+
+static int __init parse_tag_board_resistance(const struct tag *tag)
+{
+ board_resistance = tag->u.board_resistance.mohms;
+ printk("Fiona Board Resistance : %d mOhms\n",board_resistance);
+ return 0;
+}
+
+__tagtable(ATAG_BOARD_RESISTANCE, parse_tag_board_resistance);
+
static int __init parse_tag_cmdline(const struct tag *tag)
{
strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
@@ -780,6 +801,9 @@
static int c_show(struct seq_file *m, void *v)
{
int i;
+#ifdef CONFIG_ARCH_FIONA
+ char serial_num[BOARD_SERIALNUM_SIZE + 1];
+#endif
seq_printf(m, "Processor\t: %s rev %d (%s)\n",
cpu_name, (int)processor_id & 15, elf_platform);
@@ -841,8 +865,15 @@
seq_printf(m, "Hardware\t: %s\n", machine_name);
seq_printf(m, "Revision\t: %04x\n", system_rev);
+
+#ifdef CONFIG_ARCH_FIONA
+ memset(serial_num, '\0', sizeof(serial_num));
+ strncpy(serial_num, system_serial_data, BOARD_SERIALNUM_SIZE);
+ seq_printf(m, "Serial\t\t: \"%s\"\n", serial_num);
+#else
seq_printf(m, "Serial\t\t: %08x%08x\n",
system_serial_high, system_serial_low);
+#endif
return 0;
}
diff -wur linux-2.6.10/arch/arm/mach-pxa/Kconfig linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig
--- linux-2.6.10/arch/arm/mach-pxa/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig 2007-10-04 19:10:15.000000000 -0400
@@ -1,10 +1,26 @@
if ARCH_PXA
+config ARCH_LAB126
+ bool
+ default n
+
menu "Intel PXA2xx Implementations"
choice
prompt "Select target board"
+config ARCH_GUMSTIX
+ bool "Gumstix Platform"
+ depends on ARCH_PXA
+
+config ARCH_FIONA
+ bool "Fiona Platform"
+ select PXA25x
+ select PXA_SSP
+ select ARCH_LAB126
+ select ZLIB_DEFLATE
+ depends on ARCH_PXA
+
config ARCH_LUBBOCK
bool "Intel DBPXA250 Development Platform"
select PXA25x
@@ -22,6 +38,28 @@
endmenu
+
+choice
+ depends on ARCH_GUMSTIX
+ prompt "Gumstix Platform Version"
+ default ARCH_GUMSTIX_F
+
+config ARCH_GUMSTIX_ORIG
+ bool "Original Gumstix"
+ select PXA25x
+ help
+ The original gumstix platform, including the gs-200x and gs-400x and the waysmall
+ systems using these boards.
+
+config ARCH_GUMSTIX_F
+ bool "Gumstix-F"
+ select PXA25x
+ help
+ The updated Gumstix boards with 60-pin connector, including gs-200f, gs-400f and the
+ waysmall systems using these boards, including ws-200ax and ws-400ax.
+
+endchoice
+
config PXA25x
bool
help
@@ -37,4 +75,10 @@
help
Enable support for iWMMXt
+config PXA_SSP
+ tristate
+ help
+ Enable PXA ssp support
+
endif
+
diff -wur linux-2.6.10/arch/arm/mach-pxa/Makefile linux-2.6.10-lab/arch/arm/mach-pxa/Makefile
--- linux-2.6.10/arch/arm/mach-pxa/Makefile 2004-12-24 16:34:49.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/Makefile 2007-10-04 19:10:15.000000000 -0400
@@ -8,6 +8,9 @@
obj-$(CONFIG_PXA27x) += pxa27x.o
# Specific board support
+obj-$(CONFIG_ARCH_FIONA) += fiona.o
+obj-$(CONFIG_ARCH_FIONA) += boot_globals.o
+obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
@@ -22,3 +25,5 @@
# Misc features
obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
+obj-$(CONFIG_PXA_SSP) += ssp.o
diff -wur linux-2.6.10/arch/arm/mach-pxa/generic.c linux-2.6.10-lab/arch/arm/mach-pxa/generic.c
--- linux-2.6.10/arch/arm/mach-pxa/generic.c 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/generic.c 2007-10-04 19:10:15.000000000 -0400
@@ -219,6 +219,10 @@
.name = "pxa2xx-uart",
.id = 2,
};
+static struct platform_device hwuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 3,
+};
static struct platform_device *devices[] __initdata = {
&pxamci_device,
@@ -227,6 +231,7 @@
&ffuart_device,
&btuart_device,
&stuart_device,
+ &hwuart_device,
};
static int __init pxa_init(void)
diff -wur linux-2.6.10/arch/arm/mach-pxa/irq.c linux-2.6.10-lab/arch/arm/mach-pxa/irq.c
--- linux-2.6.10/arch/arm/mach-pxa/irq.c 2004-12-24 16:35:27.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/irq.c 2007-10-04 19:10:15.000000000 -0400
@@ -97,23 +97,31 @@
type = __IRQT_RISEDGE | __IRQT_FALEDGE;
}
+#ifdef DEBUG
printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio);
+#endif
pxa_gpio_mode(gpio | GPIO_IN);
if (type & __IRQT_RISEDGE) {
+#ifdef DEBUG
printk("rising ");
+#endif
__set_bit (gpio, GPIO_IRQ_rising_edge);
} else
__clear_bit (gpio, GPIO_IRQ_rising_edge);
if (type & __IRQT_FALEDGE) {
+#ifdef DEBUG
printk("falling ");
+#endif
__set_bit (gpio, GPIO_IRQ_falling_edge);
} else
__clear_bit (gpio, GPIO_IRQ_falling_edge);
+#ifdef DEBUG
printk("edges\n");
+#endif
GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
diff -wur linux-2.6.10/arch/arm/mach-pxa/mainstone.c linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c
--- linux-2.6.10/arch/arm/mach-pxa/mainstone.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c 2007-10-04 19:10:15.000000000 -0400
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
@@ -33,6 +34,7 @@
#include
#include
+#include
#include
#include
@@ -120,6 +122,44 @@
.resource = smc91x_resources,
};
+static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+ return 0;
+}
+
+static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static long mst_audio_suspend_mask;
+
+static void mst_audio_suspend(void *priv)
+{
+ mst_audio_suspend_mask = MST_MSCWR2;
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static void mst_audio_resume(void *priv)
+{
+ MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+}
+
+static pxa2xx_audio_ops_t mst_audio_ops = {
+ .startup = mst_audio_startup,
+ .shutdown = mst_audio_shutdown,
+ .suspend = mst_audio_suspend,
+ .resume = mst_audio_resume,
+};
+
+static struct platform_device mst_audio_device = {
+ .name = "pxa2xx-ac97",
+ .id = -1,
+ .dev = { .platform_data = &mst_audio_ops },
+};
static void mainstone_backlight_power(int on)
{
@@ -228,7 +268,14 @@
static void __init mainstone_init(void)
{
+ /*
+ * On Mainstone, we route AC97_SYSCLK via GPIO45 to
+ * the audio daughter card
+ */
+ pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD);
+
platform_device_register(&smc91x_device);
+ platform_device_register(&mst_audio_device);
/* reading Mainstone's "Virtual Configuration Register"
might be handy to select LCD type here */
diff -wur linux-2.6.10/arch/arm/mach-pxa/pm.c linux-2.6.10-lab/arch/arm/mach-pxa/pm.c
--- linux-2.6.10/arch/arm/mach-pxa/pm.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/pm.c 2007-10-04 19:10:15.000000000 -0400
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
@@ -23,11 +24,15 @@
#include
#include
+#ifdef CONFIG_ARCH_FIONA
+#include
+#endif
+
/*
* Debug macros
*/
-#undef DEBUG
+#define DEBUG
extern void pxa_cpu_suspend(void);
extern void pxa_cpu_resume(void);
@@ -63,6 +68,80 @@
};
+#ifdef CONFIG_PM_DEBUG
+
+static void blink_led(int count, int cadence)
+{
+ int x;
+ for (x=0; x
@@ -34,6 +37,31 @@
#include
#include
+#define PXA_SSP_PORTS 3
+
+struct ssp_info_ {
+ int irq;
+ u32 clock;
+};
+
+/*
+ * SSP port clock and IRQ settings
+ */
+static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
+#if defined (CONFIG_PXA27x)
+ {IRQ_SSP, CKEN23_SSP1},
+ {IRQ_SSP2, CKEN3_SSP2},
+ {IRQ_SSP3, CKEN4_SSP3},
+#else
+ {IRQ_SSP, CKEN3_SSP},
+ {IRQ_NSSP, CKEN9_NSSP},
+ {IRQ_ASSP, CKEN10_ASSP},
+#endif
+};
+
+static DECLARE_MUTEX(sem);
+static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
+
static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct ssp_dev *dev = (struct ssp_dev*) dev_id;
@@ -171,6 +199,30 @@
}
/**
+ * ssp_config - configure SSP port settings
+ * @mode: port operating mode
+ * @flags: port config flags
+ * @psp_flags: port PSP config flags
+ * @speed: port speed
+ *
+ * Port MUST be disabled by ssp_disable before making any config changes.
+ */
+int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
+{
+ dev->mode = mode;
+ dev->flags = flags;
+ dev->psp_flags = psp_flags;
+ dev->speed = speed;
+
+ /* set up port type, speed, port settings */
+ SSCR0_P(dev->port) = (dev->speed | dev->mode);
+ SSCR1_P(dev->port) = dev->flags;
+ SSPSP_P(dev->port) = dev->psp_flags;
+
+ return 0;
+}
+
+/**
* ssp_init - setup the SSP port
*
* initialise and claim resources for the SSP port.
@@ -180,82 +232,46 @@
* %-EBUSY if the resources are already in use
* %0 on success
*/
-int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
- u32 speed)
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
{
- int ret, irq;
+ int ret;
- if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+ if (port > PXA_SSP_PORTS || port == 0)
+ return -ENODEV;
+
+ down(&sem);
+ if (use_count[port - 1]) {
+ up(&sem);
return -EBUSY;
}
+ use_count[port - 1]++;
- switch (port) {
- case 1:
- irq = IRQ_SSP;
- break;
-#if defined (CONFIG_PXA27x)
- case 2:
- irq = IRQ_SSP2;
- break;
- case 3:
- irq = IRQ_SSP3;
- break;
-#else
- case 2:
- irq = IRQ_NSSP;
- break;
- case 3:
- irq = IRQ_ASSP;
- break;
-#endif
- default:
- return -ENODEV;
+ if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+ use_count[port - 1]--;
+ up(&sem);
+ return -EBUSY;
}
-
dev->port = port;
- dev->mode = mode;
- dev->flags = flags;
- dev->psp_flags = psp_flags;
- dev->speed = speed;
- /* set up port type, speed, port settings */
- SSCR0_P(dev->port) = (dev->speed | dev->mode);
- SSCR1_P(dev->port) = dev->flags;
- SSPSP_P(dev->port) = dev->psp_flags;
-
- ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
+ /* do we need to get irq */
+ if (!(init_flags & SSP_NO_IRQ)) {
+ ret = request_irq(ssp_info[port-1].irq, ssp_interrupt,
+ 0, "SSP", dev);
if (ret)
goto out_region;
+ dev->irq = ssp_info[port-1].irq;
+ } else
+ dev->irq = 0;
/* turn on SSP port clock */
- switch (dev->port) {
-#if defined (CONFIG_PXA27x)
- case 1:
- pxa_set_cken(CKEN23_SSP1, 1);
- break;
- case 2:
- pxa_set_cken(CKEN3_SSP2, 1);
- break;
- case 3:
- pxa_set_cken(CKEN4_SSP3, 1);
- break;
-#else
- case 1:
- pxa_set_cken(CKEN3_SSP, 1);
- break;
- case 2:
- pxa_set_cken(CKEN9_NSSP, 1);
- break;
- case 3:
- pxa_set_cken(CKEN10_ASSP, 1);
- break;
-#endif
- }
-
+ pxa_set_cken(ssp_info[port-1].clock, 1);
+ up(&sem);
return 0;
out_region:
- release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
+ use_count[port - 1]--;
+ up(&sem);
return ret;
}
@@ -266,46 +282,20 @@
*/
void ssp_exit(struct ssp_dev *dev)
{
- int irq;
-
+ down(&sem);
SSCR0_P(dev->port) &= ~SSCR0_SSE;
- /* find irq, save power and turn off SSP port clock */
- switch (dev->port) {
-#if defined (CONFIG_PXA27x)
- case 1:
- irq = IRQ_SSP;
- pxa_set_cken(CKEN23_SSP1, 0);
- break;
- case 2:
- irq = IRQ_SSP2;
- pxa_set_cken(CKEN3_SSP2, 0);
- break;
- case 3:
- irq = IRQ_SSP3;
- pxa_set_cken(CKEN4_SSP3, 0);
- break;
-#else
- case 1:
- irq = IRQ_SSP;
- pxa_set_cken(CKEN3_SSP, 0);
- break;
- case 2:
- irq = IRQ_NSSP;
- pxa_set_cken(CKEN9_NSSP, 0);
- break;
- case 3:
- irq = IRQ_ASSP;
- pxa_set_cken(CKEN10_ASSP, 0);
- break;
-#endif
- default:
+ if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
printk(KERN_WARNING "SSP: tried to close invalid port\n");
return;
}
- free_irq(irq, dev);
+ pxa_set_cken(ssp_info[dev->port-1].clock, 0);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ use_count[dev->port - 1]--;
+ up(&sem);
}
EXPORT_SYMBOL(ssp_write_word);
@@ -317,3 +307,9 @@
EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit);
+EXPORT_SYMBOL(ssp_config);
+
+MODULE_DESCRIPTION("PXA SSP driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+
diff -wur linux-2.6.10/arch/arm/mach-pxa/time.c linux-2.6.10-lab/arch/arm/mach-pxa/time.c
--- linux-2.6.10/arch/arm/mach-pxa/time.c 2004-12-24 16:34:44.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/time.c 2007-10-04 19:10:15.000000000 -0400
@@ -29,6 +29,9 @@
#include
#include
+#if defined(CONFIG_ARCH_FIONA)
+#include
+#endif
static inline unsigned long pxa_get_rtc_time(void)
{
@@ -75,6 +78,10 @@
{
int next_match;
+#if defined(CONFIG_ARCH_FIONA)
+ boot_globals_t *bg;
+#endif
+
write_seqlock(&xtime_lock);
/* Loop until we get ahead of the free running timer.
@@ -98,6 +105,16 @@
next_match = (OSMR0 += LATCH);
} while( (signed long)(next_match - OSCR) <= 8 );
+#if defined(CONFIG_ARCH_FIONA)
+ bg = get_boot_globals();
+ if (bg != NULL) {
+ bg_in_use_t *bd = &bg->globals;
+
+ bd->saved_rtc = RCNR;
+ bd->saved_rtc_checksum = ~bd->saved_rtc;
+ }
+#endif
+
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
diff -wur linux-2.6.10/arch/arm/mm/consistent.c linux-2.6.10-lab/arch/arm/mm/consistent.c
--- linux-2.6.10/arch/arm/mm/consistent.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mm/consistent.c 2007-10-04 19:10:15.000000000 -0400
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/mm/consistent.c
*
- * Copyright (C) 2000-2002 Russell King
+ * Copyright (C) 2000-2004 Russell King
*
* 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
@@ -65,6 +65,7 @@
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
+ struct page *vm_pages;
};
static struct vm_region consistent_head = {
@@ -206,6 +207,8 @@
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order);
+ c->vm_pages = page;
+
/*
* Set the "dma handle"
*/
@@ -215,6 +218,9 @@
BUG_ON(!pte_none(*pte));
set_page_count(page, 1);
+ /*
+ * x86 does not mark the pages reserved...
+ */
SetPageReserved(page);
set_pte(pte, mk_pte(page, prot));
page++;
@@ -264,6 +270,53 @@
}
EXPORT_SYMBOL(dma_alloc_writecombine);
+static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ unsigned long flags, user_size, kern_size;
+ struct vm_region *c;
+ int ret = -ENXIO;
+
+ user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ spin_lock_irqsave(&consistent_lock, flags);
+ c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+ spin_unlock_irqrestore(&consistent_lock, flags);
+
+ if (c) {
+ unsigned long off = vma->vm_pgoff;
+
+ kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
+
+ if (off < kern_size &&
+ user_size <= (kern_size - off)) {
+ vma->vm_flags |= VM_RESERVED;
+ ret = remap_pfn_range(vma, vma->vm_start,
+ page_to_pfn(c->vm_pages) + off,
+ user_size << PAGE_SHIFT,
+ vma->vm_page_prot);
+ }
+ }
+
+ return ret;
+}
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_coherent);
+
+int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_writecombine);
+
/*
* free a page as defined by the above mapping.
*/
@@ -300,6 +353,10 @@
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
+
+ /*
+ * x86 does not mark the pages reserved...
+ */
ClearPageReserved(page);
__free_page(page);
diff -wur linux-2.6.10/arch/arm/mm/proc-xscale.S linux-2.6.10-lab/arch/arm/mm/proc-xscale.S
--- linux-2.6.10/arch/arm/mm/proc-xscale.S 2004-12-24 16:35:25.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mm/proc-xscale.S 2007-10-04 19:10:15.000000000 -0400
@@ -580,11 +580,62 @@
movne r2, #0 @ no -> fault
str r2, [r0] @ hardware version
+
+ @ We try to map 64K page entries when possible.
+ @ We do that for kernel space only since the usage pattern from
+ @ the setting of VM area is quite simple. User space is not worth
+ @ the implied complexity because of ever randomly changing PTEs
+ @ (page aging, swapout, etc) requiring constant coherency checks.
+ @ Since PTEs are usually set in increasing order, we test the
+ @ possibility for a large page only when given the last PTE of a
+ @ 64K boundary.
+ tsteq r1, #L_PTE_USER
+ andeq r1, r0, #(15 << 2)
+ teqeq r1, #(15 << 2)
+ beq 1f
+
mov ip, #0
mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
mov pc, lr
+ @ See if we have 16 identical PTEs but with consecutive base addresses
+1: bic r3, r2, #0x0000f000
+ mov r1, #0x0000f000
+2: eor r2, r2, r3
+ teq r2, r1
+ bne 4f
+ subs r1, r1, #0x00001000
+ ldr r2, [r0, #-4]!
+ bne 2b
+ eors r2, r2, r3
+ bne 4f
+
+ @ Now create our LARGE PTE from the current EXT one.
+ bic r3, r3, #PTE_TYPE_MASK
+ orr r3, r3, #PTE_TYPE_LARGE
+ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0
+ orr r2, r2, r2, lsl #2 @ add LARGE_AP1
+ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2
+ and r1, r3, #0x3c0 @ EXT_TEX
+ bic r3, r3, #0x3c0
+ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX
+ orr r2, r2, r3 @ add remaining bits
+
+ @ then put it in the pagetable
+ mov r3, r2
+3: strd r2, [r0], #8
+ tst r0, #(15 << 2)
+ bne 3b
+
+ @ Then sync the 2 corresponding cache lines
+ sub r0, r0, #(16 << 2)
+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
+4: orr r0, r0, #(15 << 2)
+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
+ mov ip, #0
+ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
+ mov pc, lr
.ltorg
diff -wur linux-2.6.10/arch/arm/tools/mach-types linux-2.6.10-lab/arch/arm/tools/mach-types
--- linux-2.6.10/arch/arm/tools/mach-types 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/tools/mach-types 2007-10-04 19:10:14.000000000 -0400
@@ -381,7 +381,7 @@
spearhead ARCH_SPEARHEAD SPEARHEAD 370
pantera ARCH_PANTERA PANTERA 371
prayoglite ARCH_PRAYOGLITE PRAYOGLITE 372
-gumstik ARCH_GUMSTIK GUMSTIK 373
+gumstix ARCH_GUMSTIX GUMSTIX 373
rcube ARCH_RCUBE RCUBE 374
rea_olv ARCH_REA_OLV REA_OLV 375
pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376
@@ -634,3 +634,4 @@
cm4008 MACH_CM4008 CM4008 624
p2001 MACH_P2001 P2001 625
twister MACH_TWISTER TWISTER 626
+fiona ARCH_FIONA FIONA 627
diff -wur linux-2.6.10/drivers/Makefile linux-2.6.10-lab/drivers/Makefile
--- linux-2.6.10/drivers/Makefile 2004-12-24 16:36:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -5,17 +5,17 @@
# Rewritten to use lists instead of if-statements.
#
-obj-$(CONFIG_PCI) += pci/
-obj-$(CONFIG_PARISC) += parisc/
+# obj-$(CONFIG_PCI) += pci/
+# obj-$(CONFIG_PARISC) += parisc/
obj-y += video/
-obj-$(CONFIG_ACPI_BOOT) += acpi/
+# obj-$(CONFIG_ACPI_BOOT) += acpi/
# PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so
-obj-$(CONFIG_PNP) += pnp/
+# obj-$(CONFIG_PNP) += pnp/
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
-obj-y += char/
+obj-y += char/ char/ppoke/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
@@ -25,38 +25,41 @@
# serial drivers start registering their serio ports
obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
-obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ net/ media/
-obj-$(CONFIG_NUBUS) += nubus/
-obj-$(CONFIG_ATM) += atm/
-obj-$(CONFIG_PPC_PMAC) += macintosh/
-obj-$(CONFIG_IDE) += ide/
-obj-$(CONFIG_FC4) += fc4/
+# obj-$(CONFIG_PARPORT) += parport/
+# obj-y += base/ block/ misc/ net/ media/
+obj-y += base/ block/ misc/ net/
+# obj-$(CONFIG_NUBUS) += nubus/
+# obj-$(CONFIG_ATM) += atm/
+# obj-$(CONFIG_PPC_PMAC) += macintosh/
+# obj-$(CONFIG_IDE) += ide/
+# obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
-obj-$(CONFIG_FUSION) += message/
-obj-$(CONFIG_IEEE1394) += ieee1394/
+# obj-$(CONFIG_FUSION) += message/
+# obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
obj-$(CONFIG_MTD) += mtd/
+obj-$(CONFIG_RFS_XSR) += xsr/
obj-$(CONFIG_PCCARD) += pcmcia/
-obj-$(CONFIG_DIO) += dio/
-obj-$(CONFIG_SBUS) += sbus/
-obj-$(CONFIG_ZORRO) += zorro/
-obj-$(CONFIG_MAC) += macintosh/
+# obj-$(CONFIG_DIO) += dio/
+# obj-$(CONFIG_SBUS) += sbus/
+# obj-$(CONFIG_ZORRO) += zorro/
+# obj-$(CONFIG_MAC) += macintosh/
obj-$(CONFIG_PARIDE) += block/paride/
-obj-$(CONFIG_TC) += tc/
+# obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_GAMEPORT) += input/gameport/
-obj-$(CONFIG_I2O) += message/
+# obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/
-obj-$(CONFIG_W1) += w1/
-obj-$(CONFIG_PHONE) += telephony/
-obj-$(CONFIG_MD) += md/
-obj-$(CONFIG_BT) += bluetooth/
-obj-$(CONFIG_ISDN) += isdn/
-obj-$(CONFIG_MCA) += mca/
-obj-$(CONFIG_EISA) += eisa/
+# obj-$(CONFIG_W1) += w1/
+# obj-$(CONFIG_PHONE) += telephony/
+# obj-$(CONFIG_MD) += md/
+# obj-$(CONFIG_BT) += bluetooth/
+# obj-$(CONFIG_ISDN) += isdn/
+# obj-$(CONFIG_MCA) += mca/
+# obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
+obj-$(CONFIG_PROC_GPIO) += gpio/
obj-y += firmware/
diff -wur linux-2.6.10/drivers/base/power/resume.c linux-2.6.10-lab/drivers/base/power/resume.c
--- linux-2.6.10/drivers/base/power/resume.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/base/power/resume.c 2007-10-04 19:10:37.000000000 -0400
@@ -9,8 +9,10 @@
*/
#include
+#include
#include "power.h"
+
extern int sysdev_resume(void);
@@ -27,10 +29,45 @@
return 0;
}
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+
+#include
+#include
+static void fdputs(char *s)
+{
+ int size = 0;
+ int x = 0, wait = 0;
+ char *cur = s;
+
+ //return;
+ if (s == NULL)
+ return;
+ size = strlen(s);
+
+ // Print the string, waiting for each character to shift out before
+ // writing the next one...
+ for (x=0; x 10) {
+ STTHR = '^';
+ return;
+ }
+ }
+ }
+}
+#endif
void dpm_resume(void)
{
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ char theStr[255];
+ theStr[0] = '\0';
+#endif
+
down(&dpm_list_sem);
while(!list_empty(&dpm_off)) {
struct list_head * entry = dpm_off.next;
@@ -42,7 +79,25 @@
up(&dpm_list_sem);
if (!dev->power.prev_state)
+ {
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ if ((dev->driver) && (dev->driver->name)) {
+ sprintf(theStr,"Resuming device: %s\n",dev->driver->name);
+ fdputs(theStr);
+ }
+ else {
+ sprintf(theStr,"Resuming device no-name...\n");
+ fdputs(theStr);
+ }
+#endif
resume_device(dev);
+ }
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ else {
+ sprintf(theStr,"Did not resume device %s - power.prev_state (%d) not zero\n",dev->driver->name,dev->power.prev_state);
+ fdputs(theStr);
+ }
+#endif
down(&dpm_list_sem);
put_device(dev);
}
diff -wur linux-2.6.10/drivers/block/Kconfig linux-2.6.10-lab/drivers/block/Kconfig
--- linux-2.6.10/drivers/block/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/block/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -425,7 +425,7 @@
this option is dangerous unless the CD-RW media is known good, as we
don't do deferred write error handling yet.
-source "drivers/s390/block/Kconfig"
+# source "drivers/s390/block/Kconfig"
source "drivers/block/Kconfig.iosched"
diff -wur linux-2.6.10/drivers/char/Kconfig linux-2.6.10-lab/drivers/char/Kconfig
--- linux-2.6.10/drivers/char/Kconfig 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/Kconfig 2007-10-04 19:10:40.000000000 -0400
@@ -600,6 +600,8 @@
source "drivers/char/watchdog/Kconfig"
+source "drivers/char/ioc/Kconfig"
+
config DS1620
tristate "NetWinder thermometer support"
depends on ARCH_NETWINDER
@@ -730,6 +732,8 @@
To compile this driver as a module, choose M here: the
module will be called rtc.
+
+
config SGI_DS1286
tristate "SGI DS1286 RTC support"
depends on SGI_IP22
@@ -805,6 +809,10 @@
This option enables support for the LCD display and buttons found
on Cobalt systems through a misc device.
+config SA1100_RTC
+ tristate "SA1100/PXA2xx Real Time Clock"
+ depends on ARCH_SA1100 || ARCH_PXA
+
config DTLK
tristate "Double Talk PC internal speech card support"
help
diff -wur linux-2.6.10/drivers/char/Makefile linux-2.6.10-lab/drivers/char/Makefile
--- linux-2.6.10/drivers/char/Makefile 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -53,6 +53,8 @@
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
+obj-$(CONFIG_IOC) += ioc/
+
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
@@ -61,6 +63,7 @@
obj-$(CONFIG_HPET) += hpet.o
obj-$(CONFIG_GEN_RTC) += genrtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
+obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
diff -wur linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c
--- linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c 2007-10-04 19:10:38.000000000 -0400
@@ -16,8 +16,11 @@
* (c) Copyright 2000 Oleg Drokin
*
* 27/11/2000 Initial release
+ *
+ *
+ * Lab126 changes copyright (C) 2007 Lab126, Inc.
*/
-#include
+
#include
#include
#include
@@ -35,17 +38,73 @@
#include
#include
-#define OSCR_FREQ 3686400
-#define SA1100_CLOSE_MAGIC (0x5afc4453)
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+#include
+#endif
+
+#define OSCR_FREQ CLOCK_TICK_RATE
static unsigned long sa1100wdt_users;
-static int expect_close;
static int pre_margin;
static int boot_status;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-static int nowayout = 1;
-#else
-static int nowayout = 0;
+
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+static wait_queue_head_t pm_event_wq;
+static pid_t pm_handler_thread_pid = 0;
+static DECLARE_COMPLETION(pm_handler_thread_exited);
+
+static void init_wdt(void)
+{
+ OSMR3 = OSCR + pre_margin;
+ OSSR = OSSR_M3;
+ OWER = OWER_WME;
+ OIER |= OIER_E3;
+}
+
+static int pm_handler_thread(void *unused)
+{
+ daemonize("wdtpmd");
+ allow_signal(SIGKILL);
+
+ while (1) {
+ wait_event_interruptible(pm_event_wq, 0);
+
+ if (current->flags & PF_FREEZE) {
+ refrigerator(PF_FREEZE);
+
+ init_wdt();
+ }
+
+ if (signal_pending(current)) {
+ break;
+ }
+ }
+
+ complete_and_exit(&pm_handler_thread_exited, 0);
+
+ return 0;
+}
+
+static void start_pm_thread(void)
+{
+ init_waitqueue_head(&pm_event_wq);
+
+ pm_handler_thread_pid = kernel_thread(pm_handler_thread, NULL, CLONE_KERNEL);
+}
+
+static void
+stop_pm_thread(
+ void)
+{
+ int ret;
+
+ if (pm_handler_thread_pid > 0) {
+ ret = kill_proc(pm_handler_thread_pid, SIGKILL, 1);
+ if (ret == 0) {
+ wait_for_completion(&pm_handler_thread_exited);
+ }
+ }
+}
#endif
/*
@@ -58,63 +117,46 @@
return -EBUSY;
/* Activate SA1100 Watchdog timer */
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ init_wdt();
+#else
OSMR3 = OSCR + pre_margin;
OSSR = OSSR_M3;
OWER = OWER_WME;
OIER |= OIER_E3;
+#endif
+
return 0;
}
/*
- * Shut off the timer.
- * Lock it in if it's a module and we defined ...NOWAYOUT
- * Oddly, the watchdog can only be enabled, but we can turn off
- * the interrupt, which appears to prevent the watchdog timing out.
+ * The watchdog cannot be disabled.
+ *
+ * Previous comments suggested that turning off the interrupt by
+ * clearing OIER[E3] would prevent the watchdog timing out but this
+ * does not appear to be true (at least on the PXA255).
*/
static int sa1100dog_release(struct inode *inode, struct file *file)
{
- OSMR3 = OSCR + pre_margin;
-
- if (expect_close == SA1100_CLOSE_MAGIC) {
- OIER &= ~OIER_E3;
- } else {
- printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
- }
+ printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
clear_bit(1, &sa1100wdt_users);
- expect_close = 0;
return 0;
}
-static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = SA1100_CLOSE_MAGIC;
- }
- }
+ if (len)
/* Refresh OSMR3 timer. */
OSMR3 = OSCR + pre_margin;
- }
return len;
}
static struct watchdog_info ident = {
- .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
- WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
- .identity = "SA1100 Watchdog",
+ .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "SA1100/PXA255 Watchdog",
};
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
@@ -122,23 +164,25 @@
{
int ret = -ENOIOCTLCMD;
int time;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
switch (cmd) {
case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ ret = copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
- ret = put_user(0, (int *)arg);
+ ret = put_user(0, p);
break;
case WDIOC_GETBOOTSTATUS:
- ret = put_user(boot_status, (int *)arg);
+ ret = put_user(boot_status, p);
break;
case WDIOC_SETTIMEOUT:
- ret = get_user(time, (int *)arg);
+ ret = get_user(time, p);
if (ret)
break;
@@ -152,7 +196,7 @@
/*fall through*/
case WDIOC_GETTIMEOUT:
- ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
+ ret = put_user(pre_margin / OSCR_FREQ, p);
break;
case WDIOC_KEEPALIVE:
@@ -163,7 +207,7 @@
return ret;
}
-static struct file_operations sa1100dog_fops =
+static const struct file_operations sa1100dog_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -176,8 +220,8 @@
static struct miscdevice sa1100dog_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "SA1100/PXA2xx watchdog",
- .fops = &sa1100dog_fops,
+ .name = "watchdog",
+ .fops = (struct file_operations *)&sa1100dog_fops,
};
static int margin __initdata = 60; /* (secs) Default is 1 minute */
@@ -186,6 +230,10 @@
{
int ret;
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ start_pm_thread();
+#endif
+
/*
* Read the reset status, and save it for later. If
* we suspend, RCSR will be cleared, and the watchdog
@@ -198,12 +246,15 @@
if (ret == 0)
printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
margin);
-
return ret;
}
static void __exit sa1100dog_exit(void)
{
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ stop_pm_thread();
+#endif
+
misc_deregister(&sa1100dog_miscdev);
}
@@ -216,8 +267,5 @@
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -wur linux-2.6.10/drivers/cpufreq/Kconfig linux-2.6.10-lab/drivers/cpufreq/Kconfig
--- linux-2.6.10/drivers/cpufreq/Kconfig 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/Kconfig 2007-10-04 19:10:37.000000000 -0400
@@ -13,9 +13,13 @@
If in doubt, say N.
+if CPU_FREQ
+
+config CPU_FREQ_TABLE
+ def_tristate y
+
config CPU_FREQ_DEBUG
bool "Enable CPUfreq debugging"
- depends on CPU_FREQ
help
Say Y here to enable CPUfreq subsystem (including drivers)
debugging. You will need to activate it via the kernel
@@ -27,23 +31,29 @@
2 to activate CPUfreq drivers debugging, and
4 to activate CPUfreq governor debugging
-config CPU_FREQ_PROC_INTF
- tristate "/proc/cpufreq interface (deprecated)"
- depends on CPU_FREQ && PROC_FS
- help
- This enables the /proc/cpufreq interface for controlling
- CPUFreq. Please note that it is recommended to use the sysfs
- interface instead (which is built automatically).
-
- For details, take a look at .
-
- If in doubt, say N.
+config CPU_FREQ_STAT
+ tristate "CPU frequency translation statistics"
+ select CPU_FREQ_TABLE
+ default y
+ help
+ This driver exports CPU frequency statistics information through sysfs
+ file system
+
+config CPU_FREQ_STAT_DETAILS
+ bool "CPU frequency translation statistics details"
+ depends on CPU_FREQ_STAT
+ help
+ This will show detail CPU frequency translation table in sysfs file
+ system
+
+# Note that it is not currently possible to set the other governors (such as ondemand)
+# as the default, since if they fail to initialise, cpufreq will be
+# left in an undefined state.
choice
prompt "Default CPUFreq governor"
- depends on CPU_FREQ
- default CPU_FREQ_DEFAULT_GOV_PERFORMANCE if !CPU_FREQ_SA1100 && !CPU_FREQ_SA1110
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
+ default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help
This option sets which CPUFreq governor shall be loaded at
startup. If in doubt, select 'performance'.
@@ -69,7 +79,6 @@
config CPU_FREQ_GOV_PERFORMANCE
tristate "'performance' governor"
- depends on CPU_FREQ
help
This cpufreq governor sets the frequency statically to the
highest available CPU frequency.
@@ -78,7 +87,6 @@
config CPU_FREQ_GOV_POWERSAVE
tristate "'powersave' governor"
- depends on CPU_FREQ
help
This cpufreq governor sets the frequency statically to the
lowest available CPU frequency.
@@ -87,7 +95,6 @@
config CPU_FREQ_GOV_USERSPACE
tristate "'userspace' governor for userspace frequency scaling"
- depends on CPU_FREQ
help
Enable this cpufreq governor when you either want to set the
CPU frequency manually or when an userspace program shall
@@ -98,24 +105,8 @@
If in doubt, say Y.
-config CPU_FREQ_24_API
- bool "/proc/sys/cpu/ interface (2.4. / OLD)"
- depends on CPU_FREQ_GOV_USERSPACE
- depends on SYSCTL
- help
- This enables the /proc/sys/cpu/ sysctl interface for controlling
- the CPUFreq,"userspace" governor. This is the same interface
- as known from the 2.4.-kernel patches for CPUFreq, and offers
- the same functionality as long as "userspace" is the
- selected governor for the specified CPU.
-
- For details, take a look at .
-
- If in doubt, say N.
-
config CPU_FREQ_GOV_ONDEMAND
tristate "'ondemand' cpufreq policy governor"
- depends on CPU_FREQ
help
'ondemand' - This driver adds a dynamic cpufreq policy governor.
The governor does a periodic polling and
@@ -127,3 +118,25 @@
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
+
+config CPU_FREQ_GOV_CONSERVATIVE
+ tristate "'conservative' cpufreq governor"
+ depends on CPU_FREQ
+ help
+ 'conservative' - this driver is rather similar to the 'ondemand'
+ governor both in its source code and its purpose, the difference is
+ its optimisation for better suitability in a battery powered
+ environment. The frequency is gracefully increased and decreased
+ rather than jumping to 100% when speed is required.
+
+ If you have a desktop machine then you should really be considering
+ the 'ondemand' governor instead, however if you are using a laptop,
+ PDA or even an AMD64 based computer (due to the unacceptable
+ step-by-step latency issues between the minimum and maximum frequency
+ transitions in the CPU) you will probably want to use this governor.
+
+ For details, take a look at linux/Documentation/cpu-freq.
+
+ If in doubt, say N.
+
+endif # CPU_FREQ
diff -wur linux-2.6.10/drivers/cpufreq/Makefile linux-2.6.10-lab/drivers/cpufreq/Makefile
--- linux-2.6.10/drivers/cpufreq/Makefile 2004-12-24 16:35:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/Makefile 2007-10-04 19:10:37.000000000 -0400
@@ -1,13 +1,15 @@
# CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+# CPUfreq stats
+obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
# CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
+obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
-obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq.c linux-2.6.10-lab/drivers/cpufreq/cpufreq.c
--- linux-2.6.10/drivers/cpufreq/cpufreq.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq.c 2007-10-04 19:10:37.000000000 -0400
@@ -33,7 +33,7 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
-static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
/* we keep a copy of all ->add'ed CPU's struct sys_device here;
@@ -63,7 +63,7 @@
static LIST_HEAD(cpufreq_governor_list);
static DECLARE_MUTEX (cpufreq_governor_sem);
-static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
+struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
{
struct cpufreq_policy *data;
unsigned long flags;
@@ -102,12 +102,14 @@
err_out:
return NULL;
}
+EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
-static void cpufreq_cpu_put(struct cpufreq_policy *data)
+void cpufreq_cpu_put(struct cpufreq_policy *data)
{
kobject_put(&data->kobj);
module_put(cpufreq_driver->owner);
}
+EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
/*********************************************************************
@@ -128,7 +130,7 @@
* is set, and disabled upon cpufreq driver removal
*/
static unsigned int disable_ratelimit = 1;
-static spinlock_t disable_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(disable_ratelimit_lock);
static inline void cpufreq_debug_enable_ratelimit(void)
{
@@ -221,7 +223,7 @@
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new);
}
@@ -256,7 +258,7 @@
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
- printk(KERN_WARNING "Warning: CPU frequency is %u, "
+ dprintk(KERN_WARNING "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
}
@@ -285,7 +287,7 @@
/**
* cpufreq_parse_governor - parse a governor string
*/
-int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
+static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
{
if (!cpufreq_driver)
@@ -519,7 +521,7 @@
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->show ? fattr->show(policy,buf) : 0;
+ ret = fattr->show ? fattr->show(policy,buf) : -EIO;
cpufreq_cpu_put(policy);
return ret;
}
@@ -533,7 +535,7 @@
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->store ? fattr->store(policy,buf,count) : 0;
+ ret = fattr->store ? fattr->store(policy,buf,count) : -EIO;
cpufreq_cpu_put(policy);
return ret;
}
@@ -625,7 +627,7 @@
ret = kobject_register(&policy->kobj);
if (ret)
- goto err_out;
+ goto err_out_driver_exit;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
@@ -671,6 +673,10 @@
kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
+err_out_driver_exit:
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+
err_out:
kfree(policy);
@@ -763,8 +769,11 @@
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
+ down(&data->lock);
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ cpufreq_driver->target = NULL;
+ up(&data->lock);
kobject_unregister(&data->kobj);
@@ -809,7 +818,7 @@
{
struct cpufreq_freqs freqs;
- printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
+ dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
freqs.cpu = cpu;
@@ -861,11 +870,92 @@
/**
+ * cpufreq_suspend - let the low level driver prepare for suspend
+ */
+
+static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+{
+ int cpu = sysdev->id;
+ unsigned int ret = 0;
+ unsigned int cur_freq = 0;
+ struct cpufreq_policy *cpu_policy;
+
+ dprintk("resuming cpu %u\n", cpu);
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ /* we may be lax here as interrupts are off. Nonetheless
+ * we need to grab the correct cpu policy, as to check
+ * whether we really run on this CPU.
+ */
+
+ cpu_policy = cpufreq_cpu_get(cpu);
+ if (!cpu_policy)
+ return -EINVAL;
+
+ /* only handle each CPU group once */
+ if (unlikely(cpu_policy->cpu != cpu)) {
+ cpufreq_cpu_put(cpu_policy);
+ return 0;
+ }
+
+ if (cpufreq_driver->suspend) {
+ ret = cpufreq_driver->suspend(cpu_policy, state);
+ if (ret) {
+ printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
+ "step on CPU %u\n", cpu_policy->cpu);
+ cpufreq_cpu_put(cpu_policy);
+ return ret;
+ }
+ }
+
+
+ if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
+ goto out;
+
+ if (cpufreq_driver->get)
+ cur_freq = cpufreq_driver->get(cpu_policy->cpu);
+
+ if (!cur_freq || !cpu_policy->cur) {
+#ifdef CPUFREQ_PM_ERR
+ printk(KERN_ERR "cpufreq: suspend failed to assert current "
+ "frequency is what timing core thinks it is.\n");
+#endif
+ goto out;
+ }
+
+ if (unlikely(cur_freq != cpu_policy->cur)) {
+ struct cpufreq_freqs freqs;
+
+ if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+ dprintk(KERN_DEBUG "Warning: CPU frequency is %u, "
+ "cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
+
+ freqs.cpu = cpu;
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
+
+ notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_SUSPENDCHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
+
+ cpu_policy->cur = cur_freq;
+ }
+
+ out:
+ cpufreq_cpu_put(cpu_policy);
+ return 0;
+}
+
+/**
* cpufreq_resume - restore proper CPU frequency handling after resume
*
* 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
* 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
- * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
+ * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are
+ * restored.
*/
static int cpufreq_resume(struct sys_device * sysdev)
{
@@ -893,6 +983,16 @@
return 0;
}
+ if (cpufreq_driver->resume) {
+ ret = cpufreq_driver->resume(cpu_policy);
+ if (ret) {
+ printk(KERN_ERR "cpufreq: resume failed in ->resume "
+ "step on CPU %u\n", cpu_policy->cpu);
+ cpufreq_cpu_put(cpu_policy);
+ return ret;
+ }
+ }
+
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0;
@@ -900,21 +1000,28 @@
cur_freq = cpufreq_driver->get(cpu_policy->cpu);
if (!cur_freq || !cpu_policy->cur) {
- printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
+#ifdef CPUFREQ_PM_ERR
+ printk(KERN_ERR "cpufreq: resume failed to assert "
+ "current frequency is what timing core "
+ "thinks it is.\n");
+#endif
goto out;
}
if (unlikely(cur_freq != cpu_policy->cur)) {
struct cpufreq_freqs freqs;
- printk(KERN_WARNING "Warning: CPU frequency is %u, "
- "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur);
+ if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+ dprintk(KERN_WARNING "Warning: CPU frequency"
+ "is %u, cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
freqs.cpu = cpu;
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
+ notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
cpu_policy->cur = cur_freq;
@@ -930,6 +1037,7 @@
static struct sysdev_driver cpufreq_sysdev_driver = {
.add = cpufreq_add_dev,
.remove = cpufreq_remove_dev,
+ .suspend = cpufreq_suspend,
.resume = cpufreq_resume,
};
@@ -1018,7 +1126,7 @@
lock_cpu_hotplug();
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
- if (cpu_online(policy->cpu))
+ if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
unlock_cpu_hotplug();
return retval;
@@ -1030,7 +1138,7 @@
unsigned int target_freq,
unsigned int relation)
{
- unsigned int ret;
+ int ret;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
@@ -1051,7 +1159,7 @@
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
{
- int ret = -EINVAL;
+ int ret;
if (!try_module_get(policy->governor->owner))
return -EINVAL;
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c
--- linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c 2007-10-04 19:10:37.000000000 -0400
@@ -34,13 +34,9 @@
*/
#define DEF_FREQUENCY_UP_THRESHOLD (80)
-#define MIN_FREQUENCY_UP_THRESHOLD (0)
+#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
-#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
-#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
-#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
-
/*
* The polling frequency of this governor depends on the capability of
* the processor. Default polling frequency is 1000 times the transition
@@ -55,9 +51,9 @@
#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define DEF_SAMPLING_DOWN_FACTOR (10)
+#define DEF_SAMPLING_DOWN_FACTOR (1)
+#define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
-#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000)))
static void do_dbs_timer(void *data);
@@ -78,15 +74,23 @@
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
- unsigned int down_threshold;
+ unsigned int ignore_nice;
};
static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
};
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+ return kstat_cpu(cpu).cpustat.idle +
+ kstat_cpu(cpu).cpustat.iowait +
+ ( !dbs_tuners_ins.ignore_nice ?
+ kstat_cpu(cpu).cpustat.nice :
+ 0);
+}
+
/************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{
@@ -115,7 +119,7 @@
show_one(sampling_rate, sampling_rate);
show_one(sampling_down_factor, sampling_down_factor);
show_one(up_threshold, up_threshold);
-show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
const char *buf, size_t count)
@@ -126,6 +130,9 @@
if (ret != 1 )
return -EINVAL;
+ if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+ return -EINVAL;
+
down(&dbs_sem);
dbs_tuners_ins.sampling_down_factor = input;
up(&dbs_sem);
@@ -161,8 +168,7 @@
down(&dbs_sem);
if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
- input < MIN_FREQUENCY_UP_THRESHOLD ||
- input <= dbs_tuners_ins.down_threshold) {
+ input < MIN_FREQUENCY_UP_THRESHOLD) {
up(&dbs_sem);
return -EINVAL;
}
@@ -173,22 +179,35 @@
return count;
}
-static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
unsigned int input;
int ret;
+
+ unsigned int j;
+
ret = sscanf (buf, "%u", &input);
+ if ( ret != 1 )
+ return -EINVAL;
+
+ if ( input > 1 )
+ input = 1;
down(&dbs_sem);
- if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
- input < MIN_FREQUENCY_DOWN_THRESHOLD ||
- input >= dbs_tuners_ins.up_threshold) {
+ if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
up(&dbs_sem);
- return -EINVAL;
+ return count;
}
+ dbs_tuners_ins.ignore_nice = input;
- dbs_tuners_ins.down_threshold = input;
+ /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+ }
up(&dbs_sem);
return count;
@@ -201,7 +220,7 @@
define_one_rw(sampling_rate);
define_one_rw(sampling_down_factor);
define_one_rw(up_threshold);
-define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
static struct attribute * dbs_attributes[] = {
&sampling_rate_max.attr,
@@ -209,7 +228,7 @@
&sampling_rate.attr,
&sampling_down_factor.attr,
&up_threshold.attr,
- &down_threshold.attr,
+ &ignore_nice.attr,
NULL
};
@@ -222,48 +241,68 @@
static void dbs_check_cpu(int cpu)
{
- unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
- unsigned int total_idle_ticks;
- unsigned int freq_down_step;
+ unsigned int idle_ticks, up_idle_ticks, total_ticks;
+ unsigned int freq_next;
unsigned int freq_down_sampling_rate;
static int down_skip[NR_CPUS];
struct cpu_dbs_info_s *this_dbs_info;
+ struct cpufreq_policy *policy;
+ unsigned int j;
+
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable)
return;
+ policy = this_dbs_info->cur_policy;
/*
- * The default safe range is 20% to 80%
- * Every sampling_rate, we check
- * - If current idle time is less than 20%, then we try to
- * increase frequency
- * Every sampling_rate*sampling_down_factor, we check
- * - If current idle time is more than 80%, then we try to
- * decrease frequency
+ * Every sampling_rate, we check, if current idle time is less
+ * than 20% (default), then we try to increase frequency
+ * Every sampling_rate*sampling_down_factor, we look for a the lowest
+ * frequency which can sustain the load while keeping idle time over
+ * 30%. If such a frequency exist, we try to decrease to this frequency.
*
* Any frequency increase takes it to the maximum frequency.
* Frequency reduction happens at minimum steps of
- * 5% of max_frequency
+ * 5% (default) of current frequency
*/
+
/* Check for frequency increase */
- total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_up;
- this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ total_idle_ticks = get_cpu_idle_time(j);
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_up;
+ j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) {
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- this_dbs_info->cur_policy->max,
- CPUFREQ_RELATION_H);
down_skip[cpu] = 0;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_down =
+ j_dbs_info->prev_cpu_idle_up;
+ }
+ /* if we are already at full speed then break out early */
+ if (policy->cur == policy->max)
+ return;
+
+ __cpufreq_driver_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
return;
}
@@ -272,48 +311,61 @@
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
return;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_down;
- /* Scale idle ticks by 100 and compare with up and down ticks */
- idle_ticks *= 100;
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ /* Check for frequency decrease */
+ total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_down;
+ j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
+
down_skip[cpu] = 0;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+ /* if we cannot reduce the frequency anymore, break out early */
+ if (policy->cur == policy->min)
+ return;
+ /* Compute how many ticks there are between two measurements */
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
- down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
- sampling_rate_in_HZ(freq_down_sampling_rate);
-
- if (idle_ticks > down_idle_ticks ) {
- freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100;
+ total_ticks = usecs_to_jiffies(freq_down_sampling_rate);
- /* max freq cannot be less than 100. But who knows.... */
- if (unlikely(freq_down_step == 0))
- freq_down_step = 5;
+ /*
+ * The optimal frequency is the frequency that is the lowest that
+ * can support the current CPU usage without triggering the up
+ * policy. To be safe, we focus 10 points under the threshold.
+ */
+ freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks;
+ freq_next = (freq_next * policy->cur) /
+ (dbs_tuners_ins.up_threshold - 10);
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- this_dbs_info->cur_policy->cur - freq_down_step,
- CPUFREQ_RELATION_H);
- return;
- }
+ if (freq_next <= ((policy->cur * 95) / 100))
+ __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
}
static void do_dbs_timer(void *data)
{
int i;
down(&dbs_sem);
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_online(i))
+ for_each_online_cpu(i)
dbs_check_cpu(i);
schedule_delayed_work(&dbs_work,
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
up(&dbs_sem);
}
static inline void dbs_timer_init(void)
{
INIT_WORK(&dbs_work, do_dbs_timer, NULL);
- schedule_work(&dbs_work);
+ schedule_delayed_work(&dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
return;
}
@@ -328,6 +380,7 @@
{
unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info;
+ unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
@@ -344,14 +397,15 @@
break;
down(&dbs_sem);
- this_dbs_info->cur_policy = policy;
-
- this_dbs_info->prev_cpu_idle_up =
- kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- this_dbs_info->prev_cpu_idle_down =
- kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->cur_policy = policy;
+
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down
+ = j_dbs_info->prev_cpu_idle_up;
+ }
this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
dbs_enable++;
@@ -370,6 +424,7 @@
def_sampling_rate = (latency / 1000) *
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
+ dbs_tuners_ins.ignore_nice = 0;
dbs_timer_init();
}
@@ -409,12 +464,11 @@
return 0;
}
-struct cpufreq_governor cpufreq_gov_dbs = {
+static struct cpufreq_governor cpufreq_gov_dbs = {
.name = "ondemand",
.governor = cpufreq_governor_dbs,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_dbs);
static int __init cpufreq_gov_dbs_init(void)
{
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c
--- linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c 2004-12-24 16:33:59.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c 2007-10-04 19:10:37.000000000 -0400
@@ -17,51 +17,13 @@
#include
#include
#include
-#include
#include
-#include
#include
#include
#include
#include
-#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \
- .ctl_name = CPU_NR_FREQ_MAX, \
- .data = &cpu_max_freq[cpunr], \
- .procname = "speed-max", \
- .maxlen = sizeof(cpu_max_freq[cpunr]),\
- .mode = 0444, \
- .proc_handler = proc_dointvec, }
-
-#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \
- .ctl_name = CPU_NR_FREQ_MIN, \
- .data = &cpu_min_freq[cpunr], \
- .procname = "speed-min", \
- .maxlen = sizeof(cpu_min_freq[cpunr]),\
- .mode = 0444, \
- .proc_handler = proc_dointvec, }
-
-#define CTL_CPU_VARS_SPEED(cpunr) { \
- .ctl_name = CPU_NR_FREQ, \
- .procname = "speed", \
- .mode = 0644, \
- .proc_handler = cpufreq_procctl, \
- .strategy = cpufreq_sysctl, \
- .extra1 = (void*) (cpunr), }
-
-#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
- CTL_CPU_VARS_SPEED_MAX(cpunr), \
- CTL_CPU_VARS_SPEED_MIN(cpunr), \
- CTL_CPU_VARS_SPEED(cpunr), \
- { .ctl_name = 0, }, }
-
-/* the ctl_table entry for each CPU */
-#define CPU_ENUM(s) { \
- .ctl_name = (CPU_NR + s), \
- .procname = #s, \
- .mode = 0555, \
- .child = ctl_cpu_vars_##s }
/**
* A few values needed by the userspace governor
@@ -96,17 +58,17 @@
/**
- * _cpufreq_set - set the CPU frequency
+ * cpufreq_set - set the CPU frequency
* @freq: target frequency in kHz
* @cpu: CPU for which the frequency is to be set
*
* Sets the CPU frequency to freq.
*/
-static int _cpufreq_set(unsigned int freq, unsigned int cpu)
+static int cpufreq_set(unsigned int freq, unsigned int cpu)
{
int ret = -EINVAL;
- dprintk("_cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
+ dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
down(&userspace_sem);
if (!cpu_is_managed[cpu])
@@ -134,359 +96,6 @@
return ret;
}
-
-#ifdef CONFIG_CPU_FREQ_24_API
-
-#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01
-
-static unsigned int warning_print = 0;
-
-int __deprecated cpufreq_set(unsigned int freq, unsigned int cpu)
-{
- return _cpufreq_set(freq, cpu);
-}
-EXPORT_SYMBOL_GPL(cpufreq_set);
-
-
-/**
- * cpufreq_setmax - set the CPU to the maximum frequency
- * @cpu - affected cpu;
- *
- * Sets the CPU frequency to the maximum frequency supported by
- * this CPU.
- */
-int __deprecated cpufreq_setmax(unsigned int cpu)
-{
- if (!cpu_is_managed[cpu] || !cpu_online(cpu))
- return -EINVAL;
- return _cpufreq_set(cpu_max_freq[cpu], cpu);
-}
-EXPORT_SYMBOL_GPL(cpufreq_setmax);
-
-/*********************** cpufreq_sysctl interface ********************/
-static int
-cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- char buf[16], *p;
- int cpu = (long) ctl->extra1;
- unsigned int len, left = *lenp;
-
- if (!left || (*ppos && !write) || !cpu_online(cpu)) {
- *lenp = 0;
- return 0;
- }
-
- if (!warning_print) {
- warning_print++;
- printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
- "will be removed from (new) 2.6. kernels soon "
- "after 2005-01-01\n");
- }
-
- if (write) {
- unsigned int freq;
-
- len = left;
- if (left > sizeof(buf))
- left = sizeof(buf);
- if (copy_from_user(buf, buffer, left))
- return -EFAULT;
- buf[sizeof(buf) - 1] = '\0';
-
- freq = simple_strtoul(buf, &p, 0);
- _cpufreq_set(freq, cpu);
- } else {
- len = sprintf(buf, "%d\n", cpufreq_get(cpu));
- if (len > left)
- len = left;
- if (copy_to_user(buffer, buf, len))
- return -EFAULT;
- }
-
- *lenp = len;
- *ppos += len;
- return 0;
-}
-
-static int
-cpufreq_sysctl(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
-{
- int cpu = (long) table->extra1;
-
- if (!cpu_online(cpu))
- return -EINVAL;
-
- if (!warning_print) {
- warning_print++;
- printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
- "will be removed from (new) 2.6. kernels soon "
- "after 2005-01-01\n");
- }
-
- if (oldval && oldlenp) {
- size_t oldlen;
-
- if (get_user(oldlen, oldlenp))
- return -EFAULT;
-
- if (oldlen != sizeof(unsigned int))
- return -EINVAL;
-
- if (put_user(cpufreq_get(cpu), (unsigned int __user *)oldval) ||
- put_user(sizeof(unsigned int), oldlenp))
- return -EFAULT;
- }
- if (newval && newlen) {
- unsigned int freq;
-
- if (newlen != sizeof(unsigned int))
- return -EINVAL;
-
- if (get_user(freq, (unsigned int __user *)newval))
- return -EFAULT;
-
- _cpufreq_set(freq, cpu);
- }
- return 1;
-}
-
-/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
-/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
- CTL_TABLE_CPU_VARS(0);
-#if NR_CPUS > 1
- CTL_TABLE_CPU_VARS(1);
-#endif
-#if NR_CPUS > 2
- CTL_TABLE_CPU_VARS(2);
-#endif
-#if NR_CPUS > 3
- CTL_TABLE_CPU_VARS(3);
-#endif
-#if NR_CPUS > 4
- CTL_TABLE_CPU_VARS(4);
-#endif
-#if NR_CPUS > 5
- CTL_TABLE_CPU_VARS(5);
-#endif
-#if NR_CPUS > 6
- CTL_TABLE_CPU_VARS(6);
-#endif
-#if NR_CPUS > 7
- CTL_TABLE_CPU_VARS(7);
-#endif
-#if NR_CPUS > 8
- CTL_TABLE_CPU_VARS(8);
-#endif
-#if NR_CPUS > 9
- CTL_TABLE_CPU_VARS(9);
-#endif
-#if NR_CPUS > 10
- CTL_TABLE_CPU_VARS(10);
-#endif
-#if NR_CPUS > 11
- CTL_TABLE_CPU_VARS(11);
-#endif
-#if NR_CPUS > 12
- CTL_TABLE_CPU_VARS(12);
-#endif
-#if NR_CPUS > 13
- CTL_TABLE_CPU_VARS(13);
-#endif
-#if NR_CPUS > 14
- CTL_TABLE_CPU_VARS(14);
-#endif
-#if NR_CPUS > 15
- CTL_TABLE_CPU_VARS(15);
-#endif
-#if NR_CPUS > 16
- CTL_TABLE_CPU_VARS(16);
-#endif
-#if NR_CPUS > 17
- CTL_TABLE_CPU_VARS(17);
-#endif
-#if NR_CPUS > 18
- CTL_TABLE_CPU_VARS(18);
-#endif
-#if NR_CPUS > 19
- CTL_TABLE_CPU_VARS(19);
-#endif
-#if NR_CPUS > 20
- CTL_TABLE_CPU_VARS(20);
-#endif
-#if NR_CPUS > 21
- CTL_TABLE_CPU_VARS(21);
-#endif
-#if NR_CPUS > 22
- CTL_TABLE_CPU_VARS(22);
-#endif
-#if NR_CPUS > 23
- CTL_TABLE_CPU_VARS(23);
-#endif
-#if NR_CPUS > 24
- CTL_TABLE_CPU_VARS(24);
-#endif
-#if NR_CPUS > 25
- CTL_TABLE_CPU_VARS(25);
-#endif
-#if NR_CPUS > 26
- CTL_TABLE_CPU_VARS(26);
-#endif
-#if NR_CPUS > 27
- CTL_TABLE_CPU_VARS(27);
-#endif
-#if NR_CPUS > 28
- CTL_TABLE_CPU_VARS(28);
-#endif
-#if NR_CPUS > 29
- CTL_TABLE_CPU_VARS(29);
-#endif
-#if NR_CPUS > 30
- CTL_TABLE_CPU_VARS(30);
-#endif
-#if NR_CPUS > 31
- CTL_TABLE_CPU_VARS(31);
-#endif
-#if NR_CPUS > 32
-#error please extend CPU enumeration
-#endif
-
-/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
-static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
- CPU_ENUM(0),
-#if NR_CPUS > 1
- CPU_ENUM(1),
-#endif
-#if NR_CPUS > 2
- CPU_ENUM(2),
-#endif
-#if NR_CPUS > 3
- CPU_ENUM(3),
-#endif
-#if NR_CPUS > 4
- CPU_ENUM(4),
-#endif
-#if NR_CPUS > 5
- CPU_ENUM(5),
-#endif
-#if NR_CPUS > 6
- CPU_ENUM(6),
-#endif
-#if NR_CPUS > 7
- CPU_ENUM(7),
-#endif
-#if NR_CPUS > 8
- CPU_ENUM(8),
-#endif
-#if NR_CPUS > 9
- CPU_ENUM(9),
-#endif
-#if NR_CPUS > 10
- CPU_ENUM(10),
-#endif
-#if NR_CPUS > 11
- CPU_ENUM(11),
-#endif
-#if NR_CPUS > 12
- CPU_ENUM(12),
-#endif
-#if NR_CPUS > 13
- CPU_ENUM(13),
-#endif
-#if NR_CPUS > 14
- CPU_ENUM(14),
-#endif
-#if NR_CPUS > 15
- CPU_ENUM(15),
-#endif
-#if NR_CPUS > 16
- CPU_ENUM(16),
-#endif
-#if NR_CPUS > 17
- CPU_ENUM(17),
-#endif
-#if NR_CPUS > 18
- CPU_ENUM(18),
-#endif
-#if NR_CPUS > 19
- CPU_ENUM(19),
-#endif
-#if NR_CPUS > 20
- CPU_ENUM(20),
-#endif
-#if NR_CPUS > 21
- CPU_ENUM(21),
-#endif
-#if NR_CPUS > 22
- CPU_ENUM(22),
-#endif
-#if NR_CPUS > 23
- CPU_ENUM(23),
-#endif
-#if NR_CPUS > 24
- CPU_ENUM(24),
-#endif
-#if NR_CPUS > 25
- CPU_ENUM(25),
-#endif
-#if NR_CPUS > 26
- CPU_ENUM(26),
-#endif
-#if NR_CPUS > 27
- CPU_ENUM(27),
-#endif
-#if NR_CPUS > 28
- CPU_ENUM(28),
-#endif
-#if NR_CPUS > 29
- CPU_ENUM(29),
-#endif
-#if NR_CPUS > 30
- CPU_ENUM(30),
-#endif
-#if NR_CPUS > 31
- CPU_ENUM(31),
-#endif
-#if NR_CPUS > 32
-#error please extend CPU enumeration
-#endif
- {
- .ctl_name = 0,
- }
-};
-
-static ctl_table ctl_cpu[2] = {
- {
- .ctl_name = CTL_CPU,
- .procname = "cpu",
- .mode = 0555,
- .child = ctl_cpu_table,
- },
- {
- .ctl_name = 0,
- }
-};
-
-static struct ctl_table_header *cpufreq_sysctl_table;
-
-static inline void cpufreq_sysctl_init(void)
-{
- cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
-}
-
-static inline void cpufreq_sysctl_exit(void)
-{
- unregister_sysctl_table(cpufreq_sysctl_table);
-}
-
-#else
-#define cpufreq_sysctl_init() do {} while(0)
-#define cpufreq_sysctl_exit() do {} while(0)
-#endif /* CONFIG_CPU_FREQ_24API */
-
-
/************************** sysfs interface ************************/
static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
{
@@ -503,7 +112,7 @@
if (ret != 1)
return -EINVAL;
- _cpufreq_set(freq, policy->cpu);
+ cpufreq_set(freq, policy->cpu);
return count;
}
@@ -577,7 +186,6 @@
static int __init cpufreq_gov_userspace_init(void)
{
- cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
@@ -587,7 +195,6 @@
{
cpufreq_unregister_governor(&cpufreq_gov_userspace);
cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
- cpufreq_sysctl_exit();
}
diff -wur linux-2.6.10/drivers/cpufreq/freq_table.c linux-2.6.10-lab/drivers/cpufreq/freq_table.c
--- linux-2.6.10/drivers/cpufreq/freq_table.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/freq_table.c 2007-10-04 19:10:37.000000000 -0400
@@ -214,6 +214,11 @@
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
+struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
+{
+ return show_table[cpu];
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
MODULE_AUTHOR ("Dominik Brodowski ");
MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
diff -wur linux-2.6.10/drivers/i2c/algos/Makefile linux-2.6.10-lab/drivers/i2c/algos/Makefile
--- linux-2.6.10/drivers/i2c/algos/Makefile 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/algos/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -6,6 +6,7 @@
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
+obj-$(CONFIG_I2C_PXA) += i2c-algo-pxa.o
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
EXTRA_CFLAGS += -DDEBUG
diff -wur linux-2.6.10/drivers/i2c/busses/Kconfig linux-2.6.10-lab/drivers/i2c/busses/Kconfig
--- linux-2.6.10/drivers/i2c/busses/Kconfig 2004-12-24 16:35:25.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/busses/Kconfig 2007-10-04 19:10:38.000000000 -0400
@@ -466,4 +466,15 @@
This driver can also be built as a module. If so, the module
will be called i2c-pca-isa.
+config I2C_PXA
+ tristate "I2C interface in Intel PXA2x0"
+ depends on ARCH_PXA && I2C
+ help
+ This supports the use of the PXA I2C interface found on the Intel
+ PXA 25x and PXA 26x systems. Say Y if you have one of these.
+ You should also say Y for the PXA I2C peripheral driver support below.
+
+ To compile this driver as a module, say M here: the
+ modules will be called i2c-pxa and i2c-algo-pxa.
+
endmenu
diff -wur linux-2.6.10/drivers/i2c/busses/Makefile linux-2.6.10-lab/drivers/i2c/busses/Makefile
--- linux-2.6.10/drivers/i2c/busses/Makefile 2004-12-24 16:33:51.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/busses/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -26,6 +26,7 @@
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
@@ -36,6 +37,7 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
diff -wur linux-2.6.10/drivers/i2c/chips/Kconfig linux-2.6.10-lab/drivers/i2c/chips/Kconfig
--- linux-2.6.10/drivers/i2c/chips/Kconfig 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/chips/Kconfig 2007-10-04 19:10:38.000000000 -0400
@@ -347,6 +347,11 @@
This driver can also be built as a module. If so, the module
will be called i2c-rtc8564.
+config RS5C372_RTC
+ tristate "RS5C372 Real Time Clock"
+ depends on I2C
+
+
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
diff -wur linux-2.6.10/drivers/i2c/chips/Makefile linux-2.6.10-lab/drivers/i2c/chips/Makefile
--- linux-2.6.10/drivers/i2c/chips/Makefile 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/chips/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -30,6 +30,7 @@
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
+obj-$(CONFIG_RS5C372_RTC) += rs5c372.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
diff -wur linux-2.6.10/drivers/misc/Kconfig linux-2.6.10-lab/drivers/misc/Kconfig
--- linux-2.6.10/drivers/misc/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/misc/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -29,5 +29,21 @@
If unsure, say N.
+config PROC_SERIALNUMBER
+ bool "Device serial number driver"
+ default n
+ ---help---
+ This option enables the creation of the /proc/serialnumber entry,
+ which returns the unique serial number of the device.
+
+config PROC_BOOTDATA
+ bool "Boot data driver"
+ default n
+ ---help---
+ This option enables the creation of the /proc/bd/ entries,
+ which provide an interface for accessing various shared boot
+ global data entries in the common memory space between the
+ kernel and bootloader
+
endmenu
diff -wur linux-2.6.10/drivers/misc/Makefile linux-2.6.10-lab/drivers/misc/Makefile
--- linux-2.6.10/drivers/misc/Makefile 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/misc/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -4,3 +4,5 @@
obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
+obj-$(CONFIG_PROC_SERIALNUMBER) += serialnumber.o
+obj-$(CONFIG_PROC_BOOTDATA) += bootdata.o
diff -wur linux-2.6.10/drivers/mmc/mmc.c linux-2.6.10-lab/drivers/mmc/mmc.c
--- linux-2.6.10/drivers/mmc/mmc.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc.c 2007-10-04 19:10:37.000000000 -0400
@@ -6,6 +6,9 @@
* 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.
+ *
+ * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc.
+ *
*/
#include
#include
@@ -16,6 +19,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -25,8 +30,16 @@
#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
+#define MDEBUG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
+#define MDEBUG(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_PM_DEBUG) || defined(CONFIG_MMC_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while (0)
#endif
#define CMD_RETRIES 3
@@ -125,8 +138,17 @@
complete(mrq->done_data);
}
+#ifdef CONFIG_ARCH_LAB126
+#define MMC_WAIT_REQUEST_TIMEOUT (1 * HZ)
+#define MMC_WAIT_REQUEST_RETRIES 3
+#endif
+
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
+#ifdef CONFIG_ARCH_LAB126
+ if (host != NULL && mrq != NULL) {
+ int retries;
+#endif
DECLARE_COMPLETION(complete);
mrq->done_data = &complete;
@@ -134,7 +156,30 @@
mmc_start_request(host, mrq);
+#ifndef CONFIG_ARCH_LAB126
wait_for_completion(&complete);
+#else
+ retries = 0;
+
+ while (wait_for_completion_interruptible_timeout(&complete, MMC_WAIT_REQUEST_TIMEOUT) == 0) {
+
+ if ((retries++ >= MMC_WAIT_REQUEST_RETRIES) || !host->ops->card_inserted()) {
+ struct mmc_command *cmd = mrq->cmd;
+
+ cmd->error = MMC_ERR_ABORTED;
+ cmd->retries = 0;
+
+ mmc_request_done(host, mrq);
+
+ host->card_busy = NULL;
+
+ break;
+ }
+
+ }
+#endif
+
+ }
return 0;
}
@@ -172,7 +217,134 @@
EXPORT_SYMBOL(mmc_wait_for_cmd);
+/**
+ * mmc_wait_for_app_cmd - start an application command and wait for
+ completion
+ * @host: MMC host to start command
+ * @rca: RCA to send MMC_APP_CMD to
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Sends a MMC_APP_CMD, checks the card response, sends the command
+ * in the parameter and waits for it to complete. Return any error
+ * that occurred while the command was executing. Do not attempt to
+ * parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+ struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+ struct mmc_command appcmd;
+
+ int i, err;
+
+ BUG_ON(host->card_busy == NULL);
+ BUG_ON(retries < 0);
+
+ err = MMC_ERR_INVALID;
+
+ /*
+ * We have to resend MMC_APP_CMD for each attempt so
+ * we cannot use the retries field in mmc_command.
+ */
+ for (i = 0;i <= retries;i++) {
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ appcmd.opcode = MMC_APP_CMD;
+ appcmd.arg = rca << 16;
+ appcmd.flags = MMC_RSP_R1;
+ appcmd.retries = 0;
+ memset(appcmd.resp, 0, sizeof(appcmd.resp));
+ appcmd.data = NULL;
+
+ mrq.cmd = &appcmd;
+ appcmd.data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (appcmd.error) {
+ err = appcmd.error;
+ continue;
+ }
+
+ /* Check that card supported application commands */
+ if (!(appcmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ err = cmd->error;
+ if (cmd->error == MMC_ERR_NONE)
+ break;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+/**
+ * mmc_set_data_timeout - set the timeout for a data command
+ * @data: data phase for command
+ * @card: the MMC card associated with the data transfer
+ * @write: flag to differentiate reads from writes
+ */
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+ int write)
+{
+ unsigned int mult;
+
+ /*
+ * SD cards use a 100 multiplier rather than 10
+ */
+ mult = mmc_card_sd(card) ? 100 : 10;
+
+ /*
+ * Scale up the multiplier (and therefore the timeout) by
+ * the r2w factor for writes.
+ */
+ if (write)
+ mult <<= card->csd.r2w_factor;
+
+ data->timeout_ns = card->csd.tacc_ns * mult;
+ data->timeout_clks = card->csd.tacc_clks * mult;
+
+ /*
+ * SD cards also have an upper limit on the timeout.
+ */
+ if (mmc_card_sd(card)) {
+ unsigned int timeout_us, limit_us;
+
+ timeout_us = data->timeout_ns / 1000;
+ timeout_us += data->timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (write)
+ limit_us = 250000;
+ else
+ limit_us = 100000;
+
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+ data->timeout_ns = limit_us * 1000;
+ data->timeout_clks = 0;
+ }
+ }
+}
+
+EXPORT_SYMBOL(mmc_set_data_timeout);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
/**
* __mmc_claim_host - exclusively claim a host
@@ -191,6 +363,13 @@
unsigned long flags;
int err = 0;
+#ifdef CONFIG_ARCH_LAB126
+ if (host == NULL) {
+ /* this case can be hit on card abort */
+ return MMC_ERR_ABORTED;
+ }
+#endif
+
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
@@ -206,16 +385,17 @@
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (card != (void *)-1 && host->card_selected != card) {
- struct mmc_command cmd;
-
- host->card_selected = card;
+ if (card != (void *)-1) {
+ err = mmc_select_card(host, card);
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+#ifdef CONFIG_ARCH_LAB126
+ if (err == MMC_ERR_ABORTED) {
+ host->ops->clear(host);
+ }
+#endif
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
}
return err;
@@ -234,7 +414,14 @@
{
unsigned long flags;
+#ifdef CONFIG_ARCH_LAB126
+ if (host == NULL) {
+ /* this case can be hit on card abort */
+ return;
+ }
+#else
BUG_ON(host->card_busy == NULL);
+#endif
spin_lock_irqsave(&host->lock, flags);
host->card_busy = NULL;
@@ -245,6 +432,63 @@
EXPORT_SYMBOL(mmc_release_host);
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(host->card_busy == NULL);
+
+ if (host->card_selected == card)
+ return MMC_ERR_NONE;
+
+ host->card_selected = card;
+
+ cmd.opcode = MMC_SELECT_CARD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /*
+ * Default bus width is 1 bit.
+ */
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+ /*
+ * We can only change the bus width of the selected
+ * card so therefore we have to put the handling
+ * here.
+ */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /*
+ * The card is in 1 bit mode by default so
+ * we only need to change if it supports the
+ * wider version.
+ */
+ if (mmc_card_sd(card) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ struct mmc_command cmd;
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.arg = SD_BUS_WIDTH_4;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+ CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ }
+ }
+
+ host->ops->set_ios(host, &host->ios);
+
+ return MMC_ERR_NONE;
+}
+
/*
* Ensure that no card is selected.
*/
@@ -321,12 +565,33 @@
memset(&card->cid, 0, sizeof(struct mmc_cid));
+ if (mmc_card_sd(card)) {
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
+
+ card->cid.year += 2000; /* SD cards year offset */
+ }
+ else {
/*
- * The selection of the format here is guesswork based upon
- * information people have sent to date.
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
*/
switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.? */
+ case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
@@ -343,8 +608,9 @@
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
break;
- case 2: /* MMC v2.x ? */
- case 3: /* MMC v3.x ? */
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ case 4: /* MMC v4.0 */
card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
@@ -365,6 +631,7 @@
break;
}
}
+}
/*
* Given a 128-bit response, decode to our card CSD structure.
@@ -375,12 +642,66 @@
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
+ if (mmc_card_sd(card)) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ break;
+ case 1:
/*
- * We only understand CSD structure v1.1 and v2.
- * v2 has extra information in bits 15, 11 and 10.
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->r2w_factor = 4; /* Unused */
+ break;
+ default:
+ printk("%s: unrecognised CSD structure version %d\n",
+ card->host->host_name, csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ }
+ else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
*/
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
+ if (csd_struct != 1 && csd_struct != 2 && csd_struct != 3) {
printk("%s: unrecognised CSD structure version %d\n",
card->host->host_name, csd_struct);
mmc_card_set_bad(card);
@@ -404,6 +725,39 @@
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
}
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+ struct sd_scr *scr = &card->scr;
+ unsigned int scr_struct;
+ u32 resp[4];
+
+ BUG_ON(!mmc_card_sd(card));
+
+ resp[3] = card->raw_scr[1];
+ resp[2] = card->raw_scr[0];
+
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
+
+// testing of SCR v1 and v3 cards indicates that the spec is
+// backwards compatible, so we shouldn't limit the operation
+// cards based on the SCR version field value
+#if 0
+ if (scr_struct != 0) {
+ printk("%s: unrecognised SCR structure version %d\n",
+ card->host->host_name, scr_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+#endif
+
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+}
/*
* Locate a MMC card on this MMC host given a raw CID.
@@ -472,9 +826,12 @@
{
int bit = fls(host->ocr_avail) - 1;
+ MDEBUG("MMC: mmc_power_up()\n");
+
host->ios.vdd = bit;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
mmc_delay(1);
@@ -488,10 +845,12 @@
static void mmc_power_off(struct mmc_host *host)
{
+ MDEBUG("MMC: mmc_power_off()\n");
host->ios.clock = 0;
host->ios.vdd = 0;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
}
@@ -523,6 +882,69 @@
return err;
}
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ cmd.opcode = SD_APP_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+ struct mmc_command cmd;
+ int err, sd2;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err == MMC_ERR_NONE) {
+ if ((cmd.resp[0] & 0xFF) == test_pattern) {
+ sd2 = 1;
+ } else {
+ sd2 = 0;
+ err = MMC_ERR_FAILED;
+ }
+ } else {
+ /*
+ * Treat errors as SD 1.0 card.
+ */
+ sd2 = 0;
+ err = MMC_ERR_NONE;
+ }
+ if (rsd2)
+ *rsd2 = sd2;
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -561,11 +983,36 @@
err = PTR_ERR(card);
break;
}
+ MDEBUG("MMC: mmc_discover_cards adding card to list\n");
list_add(&card->node, &host->cards);
}
card->state &= ~MMC_STATE_DEAD;
+ if (host->mode == MMC_MODE_SD) {
+ mmc_card_set_sd(card);
+
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+
+ card->rca = cmd.resp[0] >> 16;
+
+ if (!host->ops->get_ro) {
+ printk(KERN_WARNING "%s: host does not support "
+ "reading read-only switch. assuming "
+ "write-enable.\n", host->host_name);
+ }
+ else {
+ if (host->ops->get_ro(host))
+ mmc_card_set_readonly(card);
+ }
+ }
+ else {
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1;
@@ -575,6 +1022,7 @@
mmc_card_set_dead(card);
}
}
+}
static void mmc_read_csds(struct mmc_host *host)
{
@@ -604,6 +1052,80 @@
}
}
+static void mmc_read_scrs(struct mmc_host *host)
+{
+ int err;
+ struct mmc_card *card;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ list_for_each_entry(card, &host->cards, node) {
+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+ continue;
+ if (!mmc_card_sd(card))
+ continue;
+
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE)
+ {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ data.blksz_bits = 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, (u8*)card->raw_scr, 64);
+
+ err = mmc_wait_for_req(host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ card->raw_scr[0] = ntohl(card->raw_scr[0]);
+ card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+ mmc_decode_scr(card);
+ }
+
+ mmc_deselect_cards(host);
+}
+
static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
struct mmc_card *card;
@@ -643,8 +1165,11 @@
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
+ if (err == MMC_ERR_NONE) {
+ MDEBUG("Card responded in mmc_check_cards - 0x%x\n",(int)card);
continue;
+ }
+ else MDEBUG("Couldn't find card in mmc_check_cards - dead card 0x%x\n",(int)card);
mmc_card_set_dead(card);
}
@@ -656,13 +1181,31 @@
int err;
u32 ocr;
+ host->mode = MMC_MODE_MMC;
+
mmc_power_up(host);
mmc_idle_cards(host);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
+
err = mmc_send_op_cond(host, 0, &ocr);
+
+ /*
+ * If we fail to detect any cards then try
+ * searching for SD cards.
+ */
+ if (err != MMC_ERR_NONE)
+ {
+ err = mmc_send_app_op_cond(host, 0, &ocr);
if (err != MMC_ERR_NONE)
return;
+ host->mode = MMC_MODE_SD;
+ }
+
host->ocr = mmc_select_voltage(host, ocr);
/*
@@ -701,7 +1244,21 @@
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
+ if (host->mode == MMC_MODE_SD) {
+ int err, sd2;
+ err = mmc_send_if_cond(host, host->ocr, &sd2);
+ if (err == MMC_ERR_NONE) {
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+ }
+ } else {
mmc_send_op_cond(host, host->ocr, NULL);
+ }
mmc_discover_cards(host);
@@ -712,6 +1269,9 @@
host->ops->set_ios(host, &host->ios);
mmc_read_csds(host);
+
+ if (host->mode == MMC_MODE_SD)
+ mmc_read_scrs(host);
}
@@ -737,8 +1297,11 @@
mmc_claim_host(host);
- if (host->ios.power_mode == MMC_POWER_ON)
+ if (host->ios.power_mode == MMC_POWER_ON) {
+ msleep(100);
mmc_check_cards(host);
+ MDEBUG("mmc_rescan found MMC_POWER_ON, checking for existence of cards\n");
+ }
mmc_setup(host);
@@ -760,19 +1323,25 @@
* If this is a new and good card, register it.
*/
if (!mmc_card_present(card) && !mmc_card_dead(card)) {
- if (mmc_register_card(card))
+ if (mmc_register_card(card)) {
+ MDEBUG("MMC: calling mmc_card_set_dead (card = 0x%x).\n",(int)card);
mmc_card_set_dead(card);
- else
+ }
+ else {
+ MDEBUG("MMC: calling mmc_card_set_present (card = 0x%x).\n",(int)card);
mmc_card_set_present(card);
}
+ }
/*
* If this card is dead, destroy it.
*/
if (mmc_card_dead(card)) {
+ MDEBUG("MMC: Removing card from list (card = 0x%x).\n",(int) card);
list_del(&card->node);
mmc_remove_card(card);
}
+ else MDEBUG("MMC: mmc card NOT dead and NOT removed (card = 0x%x).\n",(int) card);
}
/*
@@ -781,6 +1350,8 @@
*/
if (list_empty(&host->cards))
mmc_power_off(host);
+ else
+ MDEBUG("Card list NOT empty in mmc_rescan\n");
}
@@ -851,9 +1422,12 @@
{
struct list_head *l, *n;
+ MDEBUG("MMC: mmc_remove_host called\n");
+
list_for_each_safe(l, n, &host->cards) {
struct mmc_card *card = mmc_list_to_card(l);
+ MDEBUG("MMC: mmc_remove_host calling mmc_remove_card\n");
mmc_remove_card(card);
}
@@ -885,8 +1459,26 @@
*/
int mmc_suspend_host(struct mmc_host *host, u32 state)
{
+ pinfo("MMC: mmc_suspend_host()...\n");
mmc_claim_host(host);
mmc_deselect_cards(host);
+
+#ifdef CONFIG_FIONA_PM_MMC
+ {
+ struct list_head *l, *n;
+
+ list_for_each_safe(l, n, &host->cards) {
+ struct mmc_card *card = mmc_list_to_card(l);
+
+ MDEBUG("MMC: mmc_suspend_host() removing card 0x%X\n", (int)card);
+ mmc_card_set_dead(card);
+
+ list_del(&card->node);
+ mmc_remove_card(card);
+ }
+ }
+#endif
+
mmc_power_off(host);
mmc_release_host(host);
@@ -901,7 +1493,14 @@
*/
int mmc_resume_host(struct mmc_host *host)
{
+#ifdef CONFIG_FIONA_PM_MMC
+ extern struct mmc_host *g_pm_mmc_resume_host;
+
+ /* we need to defer resume processing because of "fpow" */
+ g_pm_mmc_resume_host = host;
+#else
mmc_detect_change(host);
+#endif
return 0;
}
diff -wur linux-2.6.10/drivers/mmc/mmc_block.c linux-2.6.10-lab/drivers/mmc/mmc_block.c
--- linux-2.6.10/drivers/mmc/mmc_block.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_block.c 2007-10-04 19:10:37.000000000 -0400
@@ -16,6 +16,7 @@
* Author: Andrew Christian
* 28 May 2002
*/
+#include
#include
#include
#include
@@ -42,6 +43,16 @@
*/
#define MMC_SHIFT 3
+
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
+extern int mmc_suspend_host(struct mmc_host *host, u32 state);
+extern int mmc_resume_host(struct mmc_host *host);
+
static int major;
/*
@@ -95,6 +106,10 @@
if (md->usage == 2)
check_disk_change(inode->i_bdev);
ret = 0;
+
+ if ((filp->f_mode & FMODE_WRITE) &&
+ mmc_card_readonly(md->queue.card))
+ ret = -EROFS;
}
return ret;
@@ -168,7 +183,12 @@
int ret;
if (mmc_card_claim_host(card))
+#ifndef CONFIG_ARCH_LAB126
goto cmd_err;
+#else
+ /* this case can occur on card abort */
+ goto cmd_err_skip_release;
+#endif
do {
struct mmc_blk_request brq;
@@ -178,17 +198,20 @@
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
- brq.cmd.arg = req->sector << 9;
+ brq.cmd.arg = req->sector;
+ if (!mmc_card_blockaddr(card))
+ brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1;
brq.data.req = req;
- brq.data.timeout_ns = card->csd.tacc_ns * 10;
- brq.data.timeout_clks = card->csd.tacc_clks * 10;
+
brq.data.blksz_bits = md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B;
+ mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
+
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
brq.data.flags |= MMC_DATA_READ;
@@ -267,6 +290,10 @@
cmd_err:
mmc_card_release_host(card);
+#ifdef CONFIG_ARCH_LAB126
+cmd_err_skip_release:
+#endif
+
/*
* This is a little draconian, but until we get proper
* error handling sorted out here, its the best we can
@@ -332,11 +359,21 @@
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
+ md->disk->flags |= GENHD_FL_REMOVABLE;
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
- md->block_bits = card->csd.read_blkbits;
+ /* the rest of the block operation code is written assuming */
+ /* 512-byte blocks, so let the system know that it should */
+ /* operate using 512-byte blocks as well */
+ /* md->block_bits = card->csd.read_blkbits; */
+ md->block_bits = 9; // (1 << 9) equals 512
+
+ /* in addition, adjust the known capacity by the delta */
+ if (card->csd.read_blkbits > md->block_bits) {
+ card->csd.capacity <<= (card->csd.read_blkbits - md->block_bits);
+ }
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
set_capacity(md->disk, card->csd.capacity);
@@ -351,9 +388,19 @@
struct mmc_command cmd;
int err;
+ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+ if (mmc_card_blockaddr(card))
+ return 0;
+
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 1 << card->csd.read_blkbits;
+
+ /* the rest of the block operation code is written assuming */
+ /* 512-byte blocks, so base the block size on the block data- */
+ /* based size, rather than the raw CSD-based size from the card */
+ /* cmd.arg = 1 << card->csd.read_blkbits; */
+ cmd.arg = 1 << md->block_bits; // (1 << 9) equals 512
+
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_card_release_host(card);
@@ -372,7 +419,10 @@
struct mmc_blk_data *md;
int err;
- if (card->csd.cmdclass & ~0x1ff)
+ /*
+ * Check that the card supports the command class(es) we need.
+ */
+ if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
if (card->csd.read_blkbits < 9) {
@@ -389,9 +439,10 @@
if (err)
goto out;
- printk(KERN_INFO "%s: %s %s %dKiB\n",
+ printk(KERN_INFO "%s: %s %s %dKiB %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- (card->csd.capacity << card->csd.read_blkbits) / 1024);
+ (int)(((long long)card->csd.capacity << md->block_bits) / 1024),
+ mmc_card_readonly(card)?"(read-only)":"");
mmc_set_drvdata(card, md);
add_disk(md->disk);
@@ -428,22 +479,15 @@
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, u32 state)
{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
+ pinfo("mmc_blk_suspend(%d)\n", state);
+
+ mmc_blk_remove(card);
- if (md) {
- mmc_queue_suspend(&md->queue);
- }
return 0;
}
static int mmc_blk_resume(struct mmc_card *card)
{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
-
- if (md) {
- mmc_blk_set_blksize(md, card);
- mmc_queue_resume(&md->queue);
- }
return 0;
}
#else
diff -wur linux-2.6.10/drivers/mmc/mmc_queue.c linux-2.6.10-lab/drivers/mmc/mmc_queue.c
--- linux-2.6.10/drivers/mmc/mmc_queue.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_queue.c 2007-10-04 19:10:37.000000000 -0400
@@ -18,6 +18,10 @@
#define MMC_QUEUE_EXIT (1 << 0)
#define MMC_QUEUE_SUSPENDED (1 << 1)
+#ifdef CONFIG_ARCH_LAB126
+#include
+#endif
+
/*
* Prepare a MMC request. Essentially, this means passing the
* preparation off to the media driver. The media driver will
@@ -92,7 +96,16 @@
}
set_current_state(TASK_RUNNING);
+#ifdef CONFIG_ARCH_LAB126
+ cpufreq_enable_speed_changes(0);
+#endif
+
mq->issue_fn(mq, req);
+
+#ifdef CONFIG_ARCH_LAB126
+ cpufreq_enable_speed_changes(1);
+#endif
+
} while (1);
remove_wait_queue(&mq->thread_wq, &wait);
up(&mq->thread_sem);
diff -wur linux-2.6.10/drivers/mmc/mmc_sysfs.c linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c
--- linux-2.6.10/drivers/mmc/mmc_sysfs.c 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c 2007-10-04 19:10:37.000000000 -0400
@@ -21,6 +21,12 @@
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
@@ -80,8 +86,12 @@
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
- if (dev->driver && drv->suspend)
+ pinfo("mmc_bus_suspend(%d)\n",state);
+
+ if (dev->driver && drv->suspend) {
+ pinfo("mmc_bus_suspend(%d) calling drv->suspend for %s\n",state,dev->driver->name);
ret = drv->suspend(card, state);
+ }
return ret;
}
@@ -91,8 +101,12 @@
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
- if (dev->driver && drv->resume)
+ pinfo("mmc_bus_resume()\n");
+
+ if (dev->driver && drv->resume) {
+ pinfo("mmc_bus_resume() calling drv->resume for %s\n",dev->driver->name);
ret = drv->resume(card);
+ }
return ret;
}
@@ -163,6 +177,7 @@
card->raw_cid[2], card->raw_cid[3]);
MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +189,7 @@
static struct device_attribute *mmc_dev_attributes[] = {
&dev_attr_cid,
&dev_attr_csd,
+ &dev_attr_scr,
&dev_attr_date,
&dev_attr_fwrev,
&dev_attr_hwrev,
@@ -229,7 +245,9 @@
static int __init mmc_init(void)
{
- return bus_register(&mmc_bus_type);
+ int rc = 0;
+ rc = bus_register(&mmc_bus_type);
+ return(rc);
}
static void __exit mmc_exit(void)
diff -wur linux-2.6.10/drivers/mmc/mmci.c linux-2.6.10-lab/drivers/mmc/mmci.c
--- linux-2.6.10/drivers/mmc/mmci.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmci.c 2007-10-04 19:10:37.000000000 -0400
@@ -37,6 +37,12 @@
#define DBG(host,fmt,args...) do { } while (0)
#endif
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
static unsigned int fmax = 515633;
static void
@@ -607,9 +613,12 @@
struct mmc_host *mmc = amba_get_drvdata(dev);
int ret = 0;
+ pinfo("mmci_suspend(%d)\n",state);
+
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
+ pinfo("mmci_suspend(%d) calling mmc_suspend_host()\n",state);
ret = mmc_suspend_host(mmc, state);
if (ret == 0)
writel(0, host->base + MMCIMASK0);
@@ -623,11 +632,14 @@
struct mmc_host *mmc = amba_get_drvdata(dev);
int ret = 0;
+ pinfo("mmci_resume(%d)\n",state);
+
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ pinfo("mmci_resume(%d) calling mmc_resume_host()\n",state);
ret = mmc_resume_host(mmc);
}
diff -wur linux-2.6.10/drivers/mmc/pxamci.c linux-2.6.10-lab/drivers/mmc/pxamci.c
--- linux-2.6.10/drivers/mmc/pxamci.c 2004-12-24 16:35:18.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/pxamci.c 2007-10-04 19:10:37.000000000 -0400
@@ -15,6 +15,8 @@
*
* 1 and 3 byte data transfers not supported
* max block length up to 1023
+ *
+ * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc.
*/
#include
#include
@@ -27,6 +29,11 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
@@ -36,18 +43,45 @@
#include
#include
+#ifdef CONFIG_ARCH_LAB126
+#ifdef CONFIG_ARCH_FIONA
+#include
+#ifdef CONFIG_FIONA_PM_MMC
+#include
+#endif
+#else
+#error unsupported board configuration
+#endif
+
+#include
+#endif
+
#include "pxamci.h"
#ifdef CONFIG_MMC_DEBUG
-#define DBG(x...) printk(KERN_DEBUG x)
+//#define DBG(x...) printk(KERN_DEBUG x)
+#define _DBG(x...) do { } while (0)
+#define DBG(x...) printk(x)
+#define MDEBUG(x...) printk(x)
#else
+#define _DBG(x...) do { } while (0)
#define DBG(x...) do { } while (0)
+#define MDEBUG(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
#endif
#define DRIVER_NAME "pxa2xx-mci"
#define NR_SG 1
+extern int mmc_suspend_host(struct mmc_host *host, u32 state);
+extern int mmc_resume_host(struct mmc_host *host);
+
struct pxamci_host {
struct mmc_host *mmc;
spinlock_t lock;
@@ -79,6 +113,7 @@
static void pxamci_stop_clock(struct pxamci_host *host)
{
+ _DBG("PXAMCI: pxamci_stop_clock called \n");
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
unsigned long timeout = 10000;
unsigned int v;
@@ -173,7 +208,11 @@
static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
{
+
+#ifndef CONFIG_ARCH_LAB126
WARN_ON(host->cmd != NULL);
+#endif
+
host->cmd = cmd;
if (cmd->flags & MMC_RSP_BUSY)
@@ -206,7 +245,7 @@
static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
{
- DBG("PXAMCI: request done\n");
+ _DBG("PXAMCI: request done\n");
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
@@ -277,8 +316,7 @@
return 0;
DCSR(host->dma) = 0;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
- host->dma_dir);
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir);
if (stat & STAT_READ_TIME_OUT)
data->error = MMC_ERR_TIMEOUT;
@@ -317,12 +355,12 @@
ireg = readl(host->base + MMC_I_REG);
- DBG("PXAMCI: irq %08x\n", ireg);
+ _DBG("PXAMCI: irq %08x\n", ireg);
if (ireg) {
unsigned stat = readl(host->base + MMC_STAT);
- DBG("PXAMCI: stat %08x\n", stat);
+ _DBG("PXAMCI: stat %08x\n", stat);
if (ireg & END_CMD_RES)
handled |= pxamci_cmd_done(host, stat);
@@ -338,7 +376,10 @@
struct pxamci_host *host = mmc_priv(mmc);
unsigned int cmdat;
+#ifndef CONFIG_ARCH_LAB126
+ /* mrq can be NULL on card abort case */
WARN_ON(host->mrq != NULL);
+#endif
host->mrq = mrq;
@@ -362,6 +403,17 @@
pxamci_start_cmd(host, mrq->cmd, cmdat);
}
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->dev);
+
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct pxamci_host *host = mmc_priv(mmc);
@@ -372,9 +424,9 @@
if (ios->clock) {
unsigned int clk = CLOCKRATE / ios->clock;
- if (CLOCKRATE / clk > ios->clock)
- clk <<= 1;
+ if(clk > (1<<6)) clk = (1<<6);
host->clkrt = fls(clk) - 1;
+ MDEBUG("PXAMCI: Starting HW clock in pxamci_set_ioc\n");
pxa_set_cken(CKEN12_MMC, 1);
/*
@@ -382,6 +434,7 @@
*/
} else {
pxamci_stop_clock(host);
+ MDEBUG("PXAMCI: Stopping HW clock in pxamci_set_ioc\n");
pxa_set_cken(CKEN12_MMC, 0);
}
@@ -399,9 +452,346 @@
host->clkrt, host->cmdat);
}
+#ifdef CONFIG_ARCH_LAB126
+
+void pxamci_clear(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ pxamci_stop_clock(host);
+ writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+ host->base + MMC_I_MASK);
+
+ DRCMRRXMMC = 0;
+ DRCMRTXMMC = 0;
+}
+
+int pxamci_card_inserted(void)
+{
+ return mmc_query_insertion_state();
+}
+
+#define MMC_NOTIFY_THREAD "mmcdd"
+
+static DECLARE_COMPLETION(mmc_detect_thread_exited);
+
+static struct {
+ pid_t thread_pid;
+ wait_queue_head_t event_wq;
+ unsigned int event_count;
+} mmc_detect_data;
+
+#undef NOTIFY_SEM
+
+#ifdef NOTIFY_SEM
+static void mmc_detect_notify_sem(void)
+{
+ int sem_id;
+
+ // retrieve the notification semaphore
+ sem_id = sys_semget(MMC_NOTIFY_SEM_KEY, 1, 0666);
+ if (sem_id >= 0) {
+ struct sembuf sem_operations[1];
+
+ // signal the semaphore
+ sem_operations[0].sem_num = 0; // which semaphore to use
+ sem_operations[0].sem_op = 1; // add one from the semaphore value
+ sem_operations[0].sem_flg = 0; // set wait flag
+
+ // do the signal
+ sys_semop(sem_id, sem_operations, 1);
+
+ } else {
+ // semaphore doesn't exist; ignore as nobody may be waiting on it
+
+ }
+}
+#endif
+
+static void mmc_detect_notify(int enabled, int notify)
+{
+ int err;
+
+ char *envp[] = {
+ "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL
+ };
+
+ char *argv[] = {
+ MMC_NOTIFY_SCRIPT,
+ enabled ? "1" : "0",
+ notify ? "1" : "0",
+ NULL
+ };
+
+ MDEBUG("mmc_detect_notify(CARD_%s)\n", (enabled ? "INSERTED" : "REMOVED"));
+ if ((err = call_usermodehelper(argv[0], argv, envp, 0)) < 0) {
+ printk("mmc: notification exec failed: \"" MMC_NOTIFY_SCRIPT "\", err %d\n", err);
+ }
+}
+
+#ifdef CONFIG_FIONA_PM_MMC
+static void mmc_detect_notify_signal(void);
+
+struct mmc_host *g_pm_mmc_resume_host = NULL;
+
+static int pm_mmc_wake_notify = 0;
+static int pm_mmc_power_mode = FPOW_MODE_ON;
+
+static int mmc_bus_fpow_getmode(void *private);
+static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode);
+
+static fpow_component *mmc_fpow_dev = NULL;
+
+static int mmc_register_with_fpow(struct device *dev, fpow_component **fpow_dev)
+{
+ struct fpow_registration_rec reg;
+ int rc = 0;
+
+ memclr(®, sizeof(reg));
+ strcpy((char*)®.name, "mmc");
+
+ reg.device_class = FPOW_CLASS_MMC;
+ reg.supported_modes = FPOW_MODE_ON_SUPPORTED | FPOW_MODE_SLEEP_SUPPORTED | FPOW_MODE_OFF_SUPPORTED;
+ reg.private = (void *)dev;
+ reg.getmode = mmc_bus_fpow_getmode;
+ reg.setmode = mmc_bus_fpow_setmode;
+ *fpow_dev = fpow_register(®);
+ if (*fpow_dev == NULL) {
+ printk("MMC: Failed to register with fpow !!\n");
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode)
+{
+ FPOW_ERR ret = FPOW_NO_ERR;
+
+ powdebug("mmc_bus_fpow_setmode(mode=%s)\n", fpow_mode_to_str(mode));
+
+ // if we're already in the correct mode, we don't need to do anything
+ if (pm_mmc_power_mode != mode) {
+
+ switch (mode) {
+
+ case FPOW_MODE_ON :
+ pm_mmc_wake_notify = 1;
+ mmc_detect_notify_signal();
+ // (fall through)
+
+ case FPOW_MODE_SLEEP :
+ case FPOW_MODE_OFF :
+ pm_mmc_power_mode = mode;
+ break;
+
+ default :
+ ret = -EINVAL;
+ break;
+ }
+
+ }
+
+ return ret;
+}
+
+static int mmc_bus_fpow_getmode(void *private)
+{
+ powdebug("mmc_bus_fpow_getmode()\n");
+
+ return pm_mmc_power_mode;
+}
+
+static void mmc_perform_suspend(void)
+{
+ // force an unmount of the card, without notification
+ mmc_detect_notify(0, 0);
+}
+
+static void mmc_perform_resume(void)
+{
+ if (g_pm_mmc_resume_host != NULL) {
+ MDEBUG("mmc_perform_resume: host=%p\n", g_pm_mmc_resume_host);
+
+ // force device rescan
+ mmc_detect_change(g_pm_mmc_resume_host);
+ flush_scheduled_work();
+
+ g_pm_mmc_resume_host = NULL;
+ }
+}
+#endif
+
+
+#define SETTLE_COUNT_MAX 10
+#define SETTLE_DELAY 10
+
+static int mmc_detect_notify_thread(void *arg)
+{
+ int last_notify = -1;
+ int settle_count;
+
+ daemonize(MMC_NOTIFY_THREAD);
+ allow_signal(SIGKILL);
+
+ while (1) {
+ wait_event_interruptible(mmc_detect_data.event_wq, mmc_detect_data.event_count != 0);
+
+#ifdef CONFIG_PM
+ if (current->flags & PF_FREEZE) {
+ refrigerator(PF_FREEZE);
+
+ if (!signal_pending(current)) {
+ continue;
+ }
+ }
+#endif
+ if (signal_pending(current)) {
+ break;
+ }
+
+#ifdef CONFIG_FIONA_PM_MMC
+ if (pm_mmc_wake_notify) {
+ mmc_perform_resume();
+
+ pm_mmc_wake_notify = 0;
+ }
+#endif
+
+ settle_count = 0;
+
+ while (++settle_count < SETTLE_COUNT_MAX) {
+ int prev_event_count = mmc_detect_data.event_count;
+
+ msleep(SETTLE_DELAY);
+
+ if (prev_event_count != mmc_detect_data.event_count) {
+ settle_count = 0;
+ }
+ }
+
+ mmc_detect_data.event_count = 0;
+
+#ifdef CONFIG_FIONA_PM_MMC
+ if (pm_mmc_power_mode == FPOW_MODE_ON) {
+#endif
+
+ int insertion_state = mmc_query_insertion_state();
+ int notify = insertion_state || last_notify != insertion_state;
+
+ last_notify = insertion_state;
+
+#ifdef NOTIFY_SEM
+ // notify any waiting processes
+ mmc_detect_notify_sem();
+#endif
+
+ // execute user-level notify script
+ mmc_detect_notify(insertion_state , notify);
+
+#ifdef CONFIG_FIONA_PM_MMC
+ }
+#endif
+
+ }
+
+ complete_and_exit(&mmc_detect_thread_exited, 0);
+
+ return 0;
+}
+
+static void mmc_detect_notify_init(void)
+{
+ pid_t pid;
+
+ memset(&mmc_detect_data, 0, sizeof(mmc_detect_data));
+
+ init_waitqueue_head(&mmc_detect_data.event_wq);
+
+ pid = kernel_thread(mmc_detect_notify_thread, NULL, CLONE_KERNEL);
+ if (pid >= 0) {
+ mmc_detect_data.thread_pid = pid;
+
+ } else {
+ mmc_detect_data.thread_pid = 0;
+ printk("mmc: thread " MMC_NOTIFY_THREAD " create failed (%d)\n", pid);
+
+ }
+}
+
+static void mmc_detect_notify_done(void)
+{
+ int ret;
+
+ if (mmc_detect_data.thread_pid > 0) {
+ ret = kill_proc(mmc_detect_data.thread_pid, SIGKILL, 1);
+ if (ret == 0) {
+ wait_for_completion(&mmc_detect_thread_exited);
+ }
+ }
+}
+
+static void mmc_detect_notify_signal(void)
+{
+ ++mmc_detect_data.event_count;
+
+ pinfo("mmc_detect_notify_signal()\n");
+ wake_up(&mmc_detect_data.event_wq);
+}
+
+static int proc_status_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = sprintf(page, "%d\n", mmc_query_insertion_state());
+
+ *eof = 1;
+
+ return len;
+}
+
+static int proc_ro_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = sprintf(page, "%d\n", mmc_query_readonly_state());
+
+ *eof = 1;
+
+ return len;
+}
+
+static void mmc_proc_init(void)
+{
+ struct proc_dir_entry *proc_mmc_parent, *proc_mmc_status, *proc_mmc_ro;
+
+ proc_mmc_parent = create_proc_entry("mmc", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+ if (proc_mmc_parent != NULL) {
+ proc_mmc_status = create_proc_entry("status", S_IRUGO, proc_mmc_parent);
+ if (proc_mmc_status != NULL) {
+ proc_mmc_status->data = NULL;
+ proc_mmc_status->read_proc = proc_status_read;
+ proc_mmc_status->write_proc = NULL;
+ }
+
+ proc_mmc_ro = create_proc_entry("readonly", S_IRUGO, proc_mmc_parent);
+ if (proc_mmc_ro != NULL) {
+ proc_mmc_ro->data = NULL;
+ proc_mmc_ro->read_proc = proc_ro_read;
+ proc_mmc_ro->write_proc = NULL;
+ }
+ }
+}
+#endif
+
static struct mmc_host_ops pxamci_ops = {
.request = pxamci_request,
+ .get_ro = pxamci_get_ro,
.set_ios = pxamci_set_ios,
+#ifdef CONFIG_ARCH_LAB126
+ .clear = pxamci_clear,
+ .card_inserted = pxamci_card_inserted,
+#endif
};
static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
@@ -412,7 +802,13 @@
static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
{
+ MDEBUG("pxamci_detect_irq() enter\n");
+
+ mmc_detect_notify_signal();
+
mmc_detect_change(devid);
+
+ MDEBUG("pxamci_detect_irq() exit\n");
return IRQ_HANDLED;
}
@@ -495,6 +891,10 @@
goto out;
}
+ MDEBUG("MMC DEBUG: Request %d RISING IRQ for mmc\n",host->irq);
+
+ set_irq_type(host->irq,IRQT_RISING);
+
ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
if (ret)
goto out;
@@ -563,8 +963,17 @@
struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
- if (mmc && level == SUSPEND_DISABLE)
+ pinfo("MMC: pxamci_suspend(%d)\n",level);
+
+ if (mmc && level == SUSPEND_DISABLE) {
+
+#ifdef CONFIG_FIONA_PM_MMC
+ mmc_perform_suspend();
+#endif
+
+ pinfo("MMC: pxamci_suspend(%d) calling mmc_suspend_host\n",level);
ret = mmc_suspend_host(mmc, state);
+ }
return ret;
}
@@ -574,8 +983,12 @@
struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
- if (mmc && level == RESUME_ENABLE)
+ pinfo("MMC: pxamci_resume(%d)\n",level);
+
+ if (mmc && level == RESUME_ENABLE) {
+ pinfo("MMC: pxamci_resume(%d) calling mmc_resume_host\n",level);
ret = mmc_resume_host(mmc);
+ }
return ret;
}
@@ -595,11 +1008,30 @@
static int __init pxamci_init(void)
{
+#ifdef CONFIG_ARCH_LAB126
+ mmc_proc_init();
+ mmc_detect_notify_init();
+
+#ifdef CONFIG_FIONA_PM_MMC
+ if (mmc_register_with_fpow(NULL, &mmc_fpow_dev)) {
+ printk("MMC failed to register with Fiona Power Manager.\n");
+ }
+#endif
+#endif
+
return driver_register(&pxamci_driver);
}
static void __exit pxamci_exit(void)
{
+#ifdef CONFIG_ARCH_LAB126
+ mmc_detect_notify_done();
+
+#ifdef CONFIG_FIONA_PM_MMC
+ fpow_unregister(mmc_fpow_dev);
+ mmc_fpow_dev = NULL;
+#endif
+#endif
driver_unregister(&pxamci_driver);
}
diff -wur linux-2.6.10/drivers/mtd/Kconfig linux-2.6.10-lab/drivers/mtd/Kconfig
--- linux-2.6.10/drivers/mtd/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -1,4 +1,4 @@
-# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $
+# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $
menu "Memory Technology Devices (MTD)"
@@ -54,8 +54,8 @@
depends on MTD_PARTITIONS
---help---
RedBoot is a ROM monitor and bootloader which deals with multiple
- 'images' in flash devices by putting a table in the last erase
- block of the device, similar to a partition table, which gives
+ 'images' in flash devices by putting a table one of the erase
+ blocks on the device, similar to a partition table, which gives
the offsets, lengths and names of all the images stored in the
flash.
@@ -68,6 +68,23 @@
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
+config MTD_REDBOOT_DIRECTORY_BLOCK
+ int "Location of RedBoot partition table"
+ depends on MTD_REDBOOT_PARTS
+ default "-1"
+ ---help---
+ This option is the Linux counterpart to the
+ CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
+ option.
+
+ The option specifies which Flash sectors holds the RedBoot
+ partition table. A zero or positive value gives an absolete
+ erase block number. A negative value specifies a number of
+ sectors before the end of the device.
+
+ For example "2" means block number 2, "-1" means the last
+ block and "-2" means the penultimate block.
+
config MTD_REDBOOT_PARTS_UNALLOCATED
bool " Include unallocated flash regions"
depends on MTD_REDBOOT_PARTS
@@ -244,5 +261,7 @@
source "drivers/mtd/nand/Kconfig"
+source "drivers/mtd/onenand/Kconfig"
+
endmenu
diff -wur linux-2.6.10/drivers/mtd/Makefile linux-2.6.10-lab/drivers/mtd/Makefile
--- linux-2.6.10/drivers/mtd/Makefile 2004-12-24 16:34:32.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/Makefile 2007-10-04 19:10:17.000000000 -0400
@@ -24,4 +24,4 @@
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
-obj-y += chips/ maps/ devices/ nand/
+obj-y += chips/ maps/ devices/ nand/ onenand/
diff -wur linux-2.6.10/drivers/mtd/chips/Kconfig linux-2.6.10-lab/drivers/mtd/chips/Kconfig
--- linux-2.6.10/drivers/mtd/chips/Kconfig 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
# drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.9 2004/07/16 15:32:14 dwmw2 Exp $
+# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -7,6 +7,7 @@
config MTD_CFI
tristate "Detect flash chips by Common Flash Interface (CFI) probe"
depends on MTD
+ select MTD_GEN_PROBE
help
The Common Flash Interface specification was developed by Intel,
AMD and other flash manufactures that provides a universal method
@@ -18,6 +19,7 @@
config MTD_JEDECPROBE
tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
depends on MTD
+ select MTD_GEN_PROBE
help
This option enables JEDEC-style probing of flash chips which are not
compatible with the Common Flash Interface, but will use the common
@@ -29,8 +31,6 @@
config MTD_GEN_PROBE
tristate
- default m if MTD_CFI!=y && !MTD_INTELPROBE && MTD_JEDECPROBE!=y && (MTD_CFI=m || MTD_JEDECPROBE=m)
- default y if MTD_CFI=y || MTD_INTELPROBE || MTD_JEDECPROBE=y
config MTD_CFI_ADV_OPTIONS
bool "Flash chip driver advanced configuration options"
@@ -158,6 +158,7 @@
config MTD_CFI_INTELEXT
tristate "Support for Intel/Sharp flash chips"
depends on MTD_GEN_PROBE
+ select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
@@ -167,6 +168,7 @@
config MTD_CFI_AMDSTD
tristate "Support for AMD/Fujitsu flash chips"
depends on MTD_GEN_PROBE
+ select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
@@ -197,6 +199,7 @@
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
+ select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
@@ -204,8 +207,6 @@
config MTD_CFI_UTIL
tristate
- default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
- default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
config MTD_RAM
tristate "Support for RAM chips in bus mapping"
@@ -272,5 +273,14 @@
distributes the identification codes for the
chips.
+config MTD_XIP
+ bool "XIP aware MTD support"
+ depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
+ default y if XIP_KERNEL
+ help
+ This allows MTD support to work with flash memory which is also
+ used for XIP purposes. If you're not sure what this is all about
+ then say N.
+
endmenu
diff -wur linux-2.6.10/drivers/mtd/chips/amd_flash.c linux-2.6.10-lab/drivers/mtd/chips/amd_flash.c
--- linux-2.6.10/drivers/mtd/chips/amd_flash.c 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/amd_flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg
*
- * $Id: amd_flash.c,v 1.25 2004/08/09 13:19:43 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
@@ -67,7 +67,6 @@
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
-#define AM29BDS643D 0x227E
/* Atmel */
#define AT49xV16x 0x00C0
@@ -618,17 +617,6 @@
{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
}
}, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29BDS643D,
- .name = "AMD AM29BDS643D",
- .size = 0x00800000,
- .numeraseregions = 3,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
- { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
.mfr_id = MANUFACTURER_ATMEL,
.dev_id = AT49xV16x,
.name = "Atmel AT49xV16x",
@@ -1122,7 +1110,7 @@
timeo = jiffies + (HZ * 20);
spin_unlock_bh(chip->mutex);
- schedule_timeout(HZ);
+ msleep(1000);
spin_lock_bh(chip->mutex);
while (flash_is_busy(map, adr, private->interleave)) {
diff -wur linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0001.c 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0001.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,9 +4,8 @@
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0001.c,v 1.160 2004/11/01 06:02:24 nico Exp $
- * (+ suspend fix from v1.162)
- * (+ partition detection fix from v1.163)
+ * $Id: cfi_cmdset_0001.c,v 1.166 2005/02/05 02:35:26 nico Exp $
+ *
*
* 10/10/2000 Nicolas Pitre
* - completely revamped method functions so they are aware and
@@ -30,12 +29,14 @@
#include
#include
#include
+#include
#include
#include
#include
#include
/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
+/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
// debugging, turns off buffer write mode if set to 1
#define FORCE_WORD_WRITE 0
@@ -147,6 +148,20 @@
}
#endif
+#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
+static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+ if (cfip && (cfip->FeatureSupport&4)) {
+ cfip->FeatureSupport &= ~4;
+ printk(KERN_WARNING "cfi_cmdset_0001: write suspend disabled\n");
+ }
+}
+#endif
+
static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
{
struct map_info *map = mtd->priv;
@@ -189,6 +204,9 @@
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
#endif
+#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
+#endif
#if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
#endif
@@ -234,7 +252,8 @@
int nb_parts, i;
/* Protection Register info */
- extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+ extra_size += (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
extra_size += 6;
@@ -453,7 +472,8 @@
int offs, numregions, numparts, partshift, numvirtchips, i, j;
/* Protection Register info */
- offs = (extp->NumProtectionFields - 1) * (4 + 6);
+ offs = (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
offs += 6;
@@ -679,6 +699,14 @@
chip->state = FL_STATUS;
return 0;
+ case FL_XIP_WHILE_ERASING:
+ if (mode != FL_READY && mode != FL_POINT &&
+ (mode != FL_WRITING || !cfip || !(cfip->SuspendCmdSupport&1)))
+ goto sleep;
+ chip->oldstate = chip->state;
+ chip->state = FL_READY;
+ return 0;
+
case FL_POINT:
/* Only if there's no operation suspended... */
if (mode == FL_READY && chip->oldstate == FL_READY)
@@ -703,7 +731,7 @@
if (chip->priv) {
struct flchip_shared *shared = chip->priv;
spin_lock(&shared->lock);
- if (shared->writing == chip) {
+ if (shared->writing == chip && chip->oldstate == FL_READY) {
/* We own the ability to write, but we're done */
shared->writing = shared->erasing;
if (shared->writing && shared->writing != chip) {
@@ -715,18 +743,25 @@
put_chip(map, loaner, loaner->start);
spin_lock(chip->mutex);
spin_unlock(loaner->mutex);
- } else {
- if (chip->oldstate != FL_ERASING) {
+ wake_up(&chip->wq);
+ return;
+ }
shared->erasing = NULL;
- if (chip->oldstate != FL_WRITING)
shared->writing = NULL;
- }
+ } else if (shared->erasing == chip && shared->writing != chip) {
+ /*
+ * We own the ability to erase without the ability
+ * to write, which means the erase was suspended
+ * and some other partition is currently writing.
+ * Don't let the switch below mess things up since
+ * we don't have ownership to resume anything.
+ */
spin_unlock(&shared->lock);
+ wake_up(&chip->wq);
+ return;
}
- } else {
spin_unlock(&shared->lock);
}
- }
switch(chip->oldstate) {
case FL_ERASING:
@@ -746,6 +781,11 @@
chip->state = FL_ERASING;
break;
+ case FL_XIP_WHILE_ERASING:
+ chip->state = chip->oldstate;
+ chip->oldstate = FL_READY;
+ break;
+
case FL_READY:
case FL_STATUS:
case FL_JEDEC_QUERY:
@@ -758,6 +798,201 @@
wake_up(&chip->wq);
}
+#ifdef CONFIG_MTD_XIP
+
+/*
+ * No interrupt what so ever can be serviced while the flash isn't in array
+ * mode. This is ensured by the xip_disable() and xip_enable() functions
+ * enclosing any code path where the flash is known not to be in array mode.
+ * And within a XIP disabled code path, only functions marked with __xipram
+ * may be called and nothing else (it's a good thing to inspect generated
+ * assembly to make sure inline functions were actually inlined and that gcc
+ * didn't emit calls to its own support functions). Also configuring MTD CFI
+ * support to a single buswidth and a single interleave is also recommended.
+ * Note that not only IRQs are disabled but the preemption count is also
+ * increased to prevent other locking primitives (namely spin_unlock) from
+ * decrementing the preempt count to zero and scheduling the CPU away while
+ * not in array mode.
+ */
+
+static void xip_disable(struct map_info *map, struct flchip *chip,
+ unsigned long adr)
+{
+ /* TODO: chips with no XIP use should ignore and return */
+ (void) map_read(map, adr); /* ensure mmu mapping is up to date */
+ preempt_disable();
+ local_irq_disable();
+}
+
+static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
+ unsigned long adr)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ if (chip->state != FL_POINT && chip->state != FL_READY) {
+ map_write(map, CMD(0xff), adr);
+ chip->state = FL_READY;
+ }
+ (void) map_read(map, adr);
+ asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
+ local_irq_enable();
+ preempt_enable();
+}
+
+/*
+ * When a delay is required for the flash operation to complete, the
+ * xip_udelay() function is polling for both the given timeout and pending
+ * (but still masked) hardware interrupts. Whenever there is an interrupt
+ * pending then the flash erase or write operation is suspended, array mode
+ * restored and interrupts unmasked. Task scheduling might also happen at that
+ * point. The CPU eventually returns from the interrupt or the call to
+ * schedule() and the suspended flash operation is resumed for the remaining
+ * of the delay period.
+ *
+ * Warning: this function _will_ fool interrupt latency tracing tools.
+ */
+
+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int usec)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+ map_word status, OK = CMD(0x80);
+ unsigned long suspended, start = xip_currtime();
+ flstate_t oldstate, newstate;
+
+ do {
+ cpu_relax();
+ if (xip_irqpending() && cfip &&
+ ((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
+ (chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
+ (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
+ /*
+ * Let's suspend the erase or write operation when
+ * supported. Note that we currently don't try to
+ * suspend interleaved chips if there is already
+ * another operation suspended (imagine what happens
+ * when one chip was already done with the current
+ * operation while another chip suspended it, then
+ * we resume the whole thing at once). Yes, it
+ * can happen!
+ */
+ map_write(map, CMD(0xb0), adr);
+ map_write(map, CMD(0x70), adr);
+ usec -= xip_elapsed_since(start);
+ suspended = xip_currtime();
+ do {
+ if (xip_elapsed_since(suspended) > 100000) {
+ /*
+ * The chip doesn't want to suspend
+ * after waiting for 100 msecs.
+ * This is a critical error but there
+ * is not much we can do here.
+ */
+ return;
+ }
+ status = map_read(map, adr);
+ } while (!map_word_andequal(map, status, OK, OK));
+
+ /* Suspend succeeded */
+ oldstate = chip->state;
+ if (oldstate == FL_ERASING) {
+ if (!map_word_bitsset(map, status, CMD(0x40)))
+ break;
+ newstate = FL_XIP_WHILE_ERASING;
+ chip->erase_suspended = 1;
+ } else {
+ if (!map_word_bitsset(map, status, CMD(0x04)))
+ break;
+ newstate = FL_XIP_WHILE_WRITING;
+ chip->write_suspended = 1;
+ }
+ chip->state = newstate;
+ map_write(map, CMD(0xff), adr);
+ (void) map_read(map, adr);
+ asm volatile (".rep 8; nop; .endr");
+ local_irq_enable();
+ preempt_enable();
+ asm volatile (".rep 8; nop; .endr");
+ cond_resched();
+
+ /*
+ * We're back. However someone else might have
+ * decided to go write to the chip if we are in
+ * a suspended erase state. If so let's wait
+ * until it's done.
+ */
+ preempt_disable();
+ while (chip->state != newstate) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ preempt_enable();
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ preempt_disable();
+ }
+ /* Disallow XIP again */
+ local_irq_disable();
+
+ /* Resume the write or erase operation */
+ map_write(map, CMD(0xd0), adr);
+ map_write(map, CMD(0x70), adr);
+ chip->state = oldstate;
+ start = xip_currtime();
+ } else if (usec >= 1000000/HZ) {
+ /*
+ * Try to save on CPU power when waiting delay
+ * is at least a system timer tick period.
+ * No need to be extremely accurate here.
+ */
+ xip_cpu_idle();
+ }
+ status = map_read(map, adr);
+ } while (!map_word_andequal(map, status, OK, OK)
+ && xip_elapsed_since(start) < usec);
+}
+
+#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)
+
+/*
+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
+ * the flash is actively programming or erasing since we have to poll for
+ * the operation to complete anyway. We can't do that in a generic way with
+ * a XIP setup so do it before the actual flash operation in this case.
+ */
+#undef INVALIDATE_CACHED_RANGE
+#define INVALIDATE_CACHED_RANGE(x...)
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+ do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+
+/*
+ * Extra notes:
+ *
+ * Activating this XIP support changes the way the code works a bit. For
+ * example the code to suspend the current process when concurrent access
+ * happens is never executed because xip_udelay() will always return with the
+ * same chip state as it was entered with. This is why there is no care for
+ * the presence of add_wait_queue() or schedule() calls from within a couple
+ * xip_disable()'d areas of code, like in do_erase_oneblock for example.
+ * The queueing and scheduling are always happening within xip_udelay().
+ *
+ * Similarly, get_chip() and put_chip() just happen to always be executed
+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
+ * is in array mode, therefore never executing many cases therein and not
+ * causing any problem with XIP.
+ */
+
+#else
+
+#define xip_disable(map, chip, adr)
+#define xip_enable(map, chip, adr)
+
+#define UDELAY(map, chip, adr, usec) cfi_udelay(usec)
+
+#define XIP_INVAL_CACHED_RANGE(x...)
+
+#endif
+
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
{
unsigned long cmd_addr;
@@ -944,7 +1179,11 @@
}
#if 0
-static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
+static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
+ loff_t from, size_t len,
+ size_t *retlen,
+ u_char *buf,
+ int base_offst, int reg_sz)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -973,6 +1212,8 @@
return (len-count)?:ret;
}
+ xip_disable(map, chip, chip->start);
+
if (chip->state != FL_JEDEC_QUERY) {
map_write(map, CMD(0x90), chip->start);
chip->state = FL_JEDEC_QUERY;
@@ -985,6 +1226,7 @@
count--;
}
+ xip_enable(map, chip, chip->start);
put_chip(map, chip, chip->start);
spin_unlock(chip->mutex);
@@ -1036,7 +1278,8 @@
}
#endif
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
+ unsigned long adr, map_word datum)
{
struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK;
@@ -1055,14 +1298,16 @@
return ret;
}
+ XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
ENABLE_VPP(map);
+ xip_disable(map, chip, adr);
map_write(map, CMD(0x40), adr);
map_write(map, datum, adr);
chip->state = FL_WRITING;
spin_unlock(chip->mutex);
INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
- cfi_udelay(chip->word_write_time);
+ UDELAY(map, chip, adr, chip->word_write_time);
spin_lock(chip->mutex);
timeo = jiffies + (HZ/2);
@@ -1089,6 +1334,7 @@
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
ret = -EIO;
goto out;
@@ -1097,7 +1343,7 @@
/* Latency issues. Drop the lock, wait a while and retry */
spin_unlock(chip->mutex);
z++;
- cfi_udelay(1);
+ UDELAY(map, chip, adr, 1);
spin_lock(chip->mutex);
}
if (!z) {
@@ -1119,8 +1365,9 @@
map_write(map, CMD(0x70), adr);
ret = -EROFS;
}
- out:
- put_chip(map, chip, adr);
+
+ xip_enable(map, chip, adr);
+ out: put_chip(map, chip, adr);
spin_unlock(chip->mutex);
return ret;
@@ -1210,7 +1457,7 @@
}
-static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
+static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long adr, const u_char *buf, int len)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -1232,6 +1479,10 @@
return ret;
}
+ XIP_INVAL_CACHED_RANGE(map, adr, len);
+ ENABLE_VPP(map);
+ xip_disable(map, chip, cmd_adr);
+
/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
[...], the device will not accept any more Write to Buffer commands".
So we must check here and reset those bits if they're set. Otherwise
@@ -1240,12 +1491,13 @@
map_write(map, CMD(0x70), cmd_adr);
status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x30))) {
+ xip_enable(map, chip, cmd_adr);
printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
+ xip_disable(map, chip, cmd_adr);
map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr);
}
- ENABLE_VPP(map);
chip->state = FL_WRITING_TO_BUFFER;
z = 0;
@@ -1257,7 +1509,7 @@
break;
spin_unlock(chip->mutex);
- cfi_udelay(1);
+ UDELAY(map, chip, cmd_adr, 1);
spin_lock(chip->mutex);
if (++z > 20) {
@@ -1269,6 +1521,7 @@
/* Odd. Clear status bits */
map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr);
+ xip_enable(map, chip, cmd_adr);
printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
status.x[0], Xstatus.x[0]);
ret = -EIO;
@@ -1305,7 +1558,7 @@
spin_unlock(chip->mutex);
INVALIDATE_CACHED_RANGE(map, adr, len);
- cfi_udelay(chip->buffer_write_time);
+ UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
spin_lock(chip->mutex);
timeo = jiffies + (HZ/2);
@@ -1331,6 +1584,7 @@
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
chip->state = FL_STATUS;
+ xip_enable(map, chip, cmd_adr);
printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
ret = -EIO;
goto out;
@@ -1338,7 +1592,7 @@
/* Latency issues. Drop the lock, wait a while and retry */
spin_unlock(chip->mutex);
- cfi_udelay(1);
+ UDELAY(map, chip, cmd_adr, 1);
z++;
spin_lock(chip->mutex);
}
@@ -1362,8 +1616,8 @@
ret = -EROFS;
}
- out:
- put_chip(map, chip, cmd_adr);
+ xip_enable(map, chip, cmd_adr);
+ out: put_chip(map, chip, cmd_adr);
spin_unlock(chip->mutex);
return ret;
}
@@ -1432,7 +1686,7 @@
return 0;
}
-static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
+static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -1455,7 +1709,10 @@
return ret;
}
+ XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
+ xip_disable(map, chip, adr);
+
/* Clear the status register first */
map_write(map, CMD(0x50), adr);
@@ -1467,7 +1724,7 @@
spin_unlock(chip->mutex);
INVALIDATE_CACHED_RANGE(map, adr, len);
- msleep(chip->erase_time / 2);
+ UDELAY(map, chip, adr, chip->erase_time*1000/2);
spin_lock(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
@@ -1505,6 +1762,7 @@
/* Clear status bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
+ xip_enable(map, chip, adr);
printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
adr, status.x[0], Xstatus.x[0]);
ret = -EIO;
@@ -1513,8 +1771,7 @@
/* Latency issues. Drop the lock, wait a while and retry */
spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
+ UDELAY(map, chip, adr, 1000000/HZ);
spin_lock(chip->mutex);
}
@@ -1530,6 +1787,7 @@
/* Reset the error bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
+ xip_enable(map, chip, adr);
chipstatus = status.x[0];
if (!map_word_equal(map, status, CMD(chipstatus))) {
@@ -1565,6 +1823,7 @@
ret = -EIO;
}
} else {
+ xip_enable(map, chip, adr);
ret = 0;
}
@@ -1632,15 +1891,19 @@
}
#ifdef DEBUG_LOCK_BITS
-static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip,
- unsigned long adr, int len, void *thunk)
+static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+ struct flchip *chip,
+ unsigned long adr,
+ int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
int status, ofs_factor = cfi->interleave * cfi->device_type;
+ xip_disable(map, chip, adr+(2*ofs_factor));
cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
chip->state = FL_JEDEC_QUERY;
status = cfi_read_query(map, adr+(2*ofs_factor));
+ xip_enable(map, chip, 0);
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
adr, status);
return 0;
@@ -1650,7 +1913,7 @@
#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)
#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)
-static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
+static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -1671,8 +1934,9 @@
}
ENABLE_VPP(map);
- map_write(map, CMD(0x60), adr);
+ xip_disable(map, chip, adr);
+ map_write(map, CMD(0x60), adr);
if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
map_write(map, CMD(0x01), adr);
chip->state = FL_LOCKING;
@@ -1683,7 +1947,7 @@
BUG();
spin_unlock(chip->mutex);
- schedule_timeout(HZ);
+ UDELAY(map, chip, adr, 1000000/HZ);
spin_lock(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
@@ -1702,6 +1966,7 @@
map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
Xstatus = map_read(map, adr);
+ xip_enable(map, chip, adr);
printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
status.x[0], Xstatus.x[0]);
put_chip(map, chip, adr);
@@ -1711,12 +1976,13 @@
/* Latency issues. Drop the lock, wait a while and retry */
spin_unlock(chip->mutex);
- cfi_udelay(1);
+ UDELAY(map, chip, adr, 1);
spin_lock(chip->mutex);
}
/* Done and happy. */
chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
return 0;
@@ -1875,7 +2141,7 @@
static char im_name_1[]="cfi_cmdset_0001";
static char im_name_3[]="cfi_cmdset_0003";
-int __init cfi_intelext_init(void)
+static int __init cfi_intelext_init(void)
{
inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);
inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);
diff -wur linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0002.c
--- linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0002.c 2004-12-24 16:34:32.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0002.c 2007-10-04 19:10:17.000000000 -0400
@@ -13,7 +13,7 @@
*
* This code is GPL
*
- * $Id: cfi_cmdset_0002.c,v 1.111 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
*
*/
@@ -707,7 +707,7 @@
*/
unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
int ret = 0;
- map_word oldd, curd;
+ map_word oldd;
int retry_cnt = 0;
adr += chip->start;
@@ -764,23 +764,11 @@
continue;
}
- /* Test to see if toggling has stopped. */
- oldd = map_read(map, adr);
- curd = map_read(map, adr);
- if (map_word_equal(map, curd, oldd)) {
- /* Do we have the correct value? */
- if (map_word_equal(map, curd, datum)) {
+ if (chip_ready(map, adr))
goto op_done;
- }
- /* Nope something has gone wrong. */
- break;
- }
- if (time_after(jiffies, timeo)) {
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
+ if (time_after(jiffies, timeo))
break;
- }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
@@ -788,6 +776,8 @@
cfi_spin_lock(chip->mutex);
}
+ printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
+
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
@@ -1173,8 +1163,7 @@
chip->in_progress_block_addr = adr;
cfi_spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((chip->erase_time*HZ)/(2*1000));
+ msleep(chip->erase_time/2);
cfi_spin_lock(chip->mutex);
timeo = jiffies + (HZ*20);
@@ -1259,8 +1248,7 @@
chip->in_progress_block_addr = adr;
cfi_spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((chip->erase_time*HZ)/(2*1000));
+ msleep(chip->erase_time/2);
cfi_spin_lock(chip->mutex);
timeo = jiffies + (HZ*20);
diff -wur linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0020.c
--- linux-2.6.10/drivers/mtd/chips/cfi_cmdset_0020.c 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/cfi_cmdset_0020.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0020.c,v 1.16 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0020.c,v 1.17 2004/11/20 12:49:04 dwmw2 Exp $
*
* 10/10/2000 Nicolas Pitre
* - completely revamped method functions so they are aware and
@@ -788,7 +788,7 @@
chip->state = FL_ERASING;
spin_unlock_bh(chip->mutex);
- schedule_timeout(HZ);
+ msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
@@ -1087,7 +1087,7 @@
chip->state = FL_LOCKING;
spin_unlock_bh(chip->mutex);
- schedule_timeout(HZ);
+ msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
@@ -1236,7 +1236,7 @@
chip->state = FL_UNLOCKING;
spin_unlock_bh(chip->mutex);
- schedule_timeout(HZ);
+ msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
diff -wur linux-2.6.10/drivers/mtd/chips/cfi_probe.c linux-2.6.10-lab/drivers/mtd/chips/cfi_probe.c
--- linux-2.6.10/drivers/mtd/chips/cfi_probe.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/cfi_probe.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: cfi_probe.c,v 1.79 2004/10/20 23:04:01 dwmw2 Exp $
+ $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $
*/
#include
@@ -15,6 +15,7 @@
#include
#include
+#include
#include
#include
#include
@@ -31,11 +32,47 @@
struct mtd_info *cfi_probe(struct map_info *map);
+#ifdef CONFIG_MTD_XIP
+
+/* only needed for short periods, so this is rather simple */
+#define xip_disable() local_irq_disable()
+
+#define xip_allowed(base, map) \
+do { \
+ (void) map_read(map, base); \
+ asm volatile (".rep 8; nop; .endr"); \
+ local_irq_enable(); \
+} while (0)
+
+#define xip_enable(base, map, cfi) \
+do { \
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
+ xip_allowed(base, map); \
+} while (0)
+
+#define xip_disable_qry(base, map, cfi) \
+do { \
+ xip_disable(); \
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
+} while (0)
+
+#else
+
+#define xip_disable() do { } while (0)
+#define xip_allowed(base, map) do { } while (0)
+#define xip_enable(base, map, cfi) do { } while (0)
+#define xip_disable_qry(base, map, cfi) do { } while (0)
+
+#endif
+
/* check for QRY.
in: interleave,type,mode
ret: table index, <0 for error
*/
-static int qry_present(struct map_info *map, __u32 base,
+static int __xipram qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
int osf = cfi->interleave * cfi->device_type; // scale factor
@@ -59,10 +96,10 @@
if (!map_word_equal(map, qry[2], val[2]))
return 0;
- return 1; // nothing found
+ return 1; // "QRY" found
}
-static int cfi_probe_chip(struct map_info *map, __u32 base,
+static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
@@ -79,12 +116,16 @@
(unsigned long)base + 0x55, map->size -1);
return 0;
}
+
+ xip_disable();
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
- if (!qry_present(map,base,cfi))
+ if (!qry_present(map,base,cfi)) {
+ xip_enable(base, map, cfi);
return 0;
+ }
if (!cfi->numchips) {
/* This is the first time we're called. Set up the CFI
@@ -110,6 +151,7 @@
/* If the QRY marker goes away, it's an alias */
if (!qry_present(map, start, cfi)) {
+ xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
return 0;
@@ -122,6 +164,7 @@
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
if (qry_present(map, base, cfi)) {
+ xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
return 0;
@@ -137,6 +180,7 @@
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ xip_allowed(base, map);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
@@ -145,7 +189,7 @@
return 1;
}
-static int cfi_chip_setup(struct map_info *map,
+static int __xipram cfi_chip_setup(struct map_info *map,
struct cfi_private *cfi)
{
int ofs_factor = cfi->interleave*cfi->device_type;
@@ -153,6 +197,7 @@
int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
int i;
+ xip_enable(base, map, cfi);
#ifdef DEBUG_CFI
printk("Number of erase regions: %d\n", num_erase_regions);
#endif
@@ -170,9 +215,29 @@
cfi->cfi_mode = CFI_MODE_CFI;
/* Read the CFI info structure */
- for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
+ xip_disable_qry(base, map, cfi);
+ for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
- }
+
+ /* Note we put the device back into Read Mode BEFORE going into Auto
+ * Select Mode, as some devices support nesting of modes, others
+ * don't. This way should always work.
+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
+ * so should be treated as nops or illegal (and so put the device
+ * back into Read Mode, which is a nop in this case).
+ */
+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi->mfr = cfi_read_query(map, base);
+ cfi->id = cfi_read_query(map, base + ofs_factor);
+
+ /* Put it back into Read Mode */
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ /* ... even if it's an Intel chip */
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ xip_allowed(base, map);
/* Do any necessary byteswapping */
cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);
@@ -198,25 +263,6 @@
#endif
}
- /* Note we put the device back into Read Mode BEFORE going into Auto
- * Select Mode, as some devices support nesting of modes, others
- * don't. This way should always work.
- * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
- * so should be treated as nops or illegal (and so put the device
- * back into Read Mode, which is a nop in this case).
- */
- cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
- cfi->mfr = cfi_read_query(map, base);
- cfi->id = cfi_read_query(map, base + ofs_factor);
-
- /* Put it back into Read Mode */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
- /* ... even if it's an Intel chip */
- cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
-
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
map->bankwidth*8);
diff -wur linux-2.6.10/drivers/mtd/chips/cfi_util.c linux-2.6.10-lab/drivers/mtd/chips/cfi_util.c
--- linux-2.6.10/drivers/mtd/chips/cfi_util.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/cfi_util.c 2007-10-04 19:10:17.000000000 -0400
@@ -7,7 +7,7 @@
*
* This code is covered by the GPL.
*
- * $Id: cfi_util.c,v 1.5 2004/08/12 06:40:23 eric Exp $
+ * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $
*
*/
@@ -22,13 +22,14 @@
#include
#include
#include
+#include
#include
#include
#include
#include
struct cfi_extquery *
-cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
+__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
{
struct cfi_private *cfi = map->fldrv_priv;
__u32 base = 0; // cfi->chips[0].start;
@@ -40,21 +41,35 @@
if (!adr)
goto out;
- /* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
extp = kmalloc(size, GFP_KERNEL);
if (!extp) {
printk(KERN_ERR "Failed to allocate memory\n");
goto out;
}
+#ifdef CONFIG_MTD_XIP
+ local_irq_disable();
+#endif
+
+ /* Switch it into Query Mode */
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
/* Read in the Extended Query Table */
for (i=0; idevice_type, NULL);
+ cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
+
+#ifdef CONFIG_MTD_XIP
+ (void) map_read(map, base);
+ asm volatile (".rep 8; nop; .endr");
+ local_irq_enable();
+#endif
+
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
printk(KERN_WARNING " Unknown %s Extended Query "
@@ -62,15 +77,9 @@
extp->MinorVersion);
kfree(extp);
extp = NULL;
- goto out;
}
-out:
- /* Make sure it's in read mode */
- cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
-
- return extp;
+ out: return extp;
}
EXPORT_SYMBOL(cfi_read_pri);
@@ -156,7 +165,6 @@
i=first;
while(len) {
- unsigned long chipmask;
int size = regions[i].erasesize;
ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
@@ -165,10 +173,10 @@
return ret;
adr += size;
+ ofs += size;
len -= size;
- chipmask = (1 << cfi->chipshift) - 1;
- if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
+ if (ofs == regions[i].offset + size * regions[i].numblocks)
i++;
if (adr >> cfi->chipshift) {
diff -wur linux-2.6.10/drivers/mtd/chips/chipreg.c linux-2.6.10-lab/drivers/mtd/chips/chipreg.c
--- linux-2.6.10/drivers/mtd/chips/chipreg.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/chipreg.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: chipreg.c,v 1.17 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.18 2005/01/12 22:34:34 gleixner Exp $
*
* Registration for chip drivers
*
@@ -15,7 +15,7 @@
#include
#include
-static spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(chip_drvs_lock);
static LIST_HEAD(chip_drvs_list);
void register_mtd_chip_driver(struct mtd_chip_driver *drv)
diff -wur linux-2.6.10/drivers/mtd/chips/gen_probe.c linux-2.6.10-lab/drivers/mtd/chips/gen_probe.c
--- linux-2.6.10/drivers/mtd/chips/gen_probe.c 2004-12-24 16:35:27.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/gen_probe.c 2007-10-04 19:10:17.000000000 -0400
@@ -2,7 +2,7 @@
* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
*/
#include
@@ -162,7 +162,7 @@
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
- for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+ for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
if (!cfi_interleave_supported(nr_chips))
continue;
diff -wur linux-2.6.10/drivers/mtd/chips/jedec.c linux-2.6.10-lab/drivers/mtd/chips/jedec.c
--- linux-2.6.10/drivers/mtd/chips/jedec.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/jedec.c 2007-10-04 19:10:17.000000000 -0400
@@ -11,7 +11,7 @@
* not going to guess how to send commands to them, plus I expect they will
* all speak CFI..
*
- * $Id: jedec.c,v 1.21 2004/08/09 13:19:43 dwmw2 Exp $
+ * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
*/
#include
@@ -529,7 +529,7 @@
static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
map_copy_from(map, buf, from, len);
*retlen = len;
@@ -541,8 +541,8 @@
static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+ struct map_info *map = mtd->priv;
+ struct jedec_private *priv = map->fldrv_priv;
*retlen = 0;
while (len > 0)
@@ -593,8 +593,8 @@
unsigned long NoTime = 0;
unsigned long start = instr->addr, len = instr->len;
unsigned int I;
- struct map_info *map = (struct map_info *)mtd->priv;
- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+ struct map_info *map = mtd->priv;
+ struct jedec_private *priv = map->fldrv_priv;
// Verify the arguments..
if (start + len > mtd->size ||
@@ -800,8 +800,8 @@
#define flread(x) map_read8(map,base+(off&((1<addrshift)-1))+((x)<addrshift))
#define flwrite(v,x) map_write8(map,v,base+(off&((1<addrshift)-1))+((x)<addrshift))
- struct map_info *map = (struct map_info *)mtd->priv;
- struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+ struct map_info *map = mtd->priv;
+ struct jedec_private *priv = map->fldrv_priv;
unsigned long base;
unsigned long off;
size_t save_len = len;
diff -wur linux-2.6.10/drivers/mtd/chips/jedec_probe.c linux-2.6.10-lab/drivers/mtd/chips/jedec_probe.c
--- linux-2.6.10/drivers/mtd/chips/jedec_probe.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/jedec_probe.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: jedec_probe.c,v 1.58 2004/11/16 18:29:00 dwmw2 Exp $
+ $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
@@ -227,6 +227,11 @@
[MTD_UADDR_DONT_CARE] = {
.addr1 = 0x0000, /* Doesn't matter which address */
.addr2 = 0x0000 /* is used - must be last entry */
+ },
+
+ [MTD_UADDR_UNNECESSARY] = {
+ .addr1 = 0x0000,
+ .addr2 = 0x0000
}
};
@@ -514,15 +519,20 @@
ERASEINFO(0x10000,8),
}
}, {
- mfr_id: MANUFACTURER_AMD,
- dev_id: AM29F002T,
- name: "AMD AM29F002T",
- DevSize: SIZE_256KiB,
- NumEraseRegions: 4,
- regions: {ERASEINFO(0x10000,3),
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29F002T,
+ .name = "AMD AM29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_ATMEL,
@@ -770,15 +780,20 @@
ERASEINFO(0x04000,1)
}
}, {
- mfr_id: MANUFACTURER_HYUNDAI,
- dev_id: HY29F002T,
- name: "Hyundai HY29F002T",
- DevSize: SIZE_256KiB,
- NumEraseRegions: 4,
- regions: {ERASEINFO(0x10000,3),
+ .mfr_id = MANUFACTURER_HYUNDAI,
+ .dev_id = HY29F002T,
+ .name = "Hyundai HY29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_INTEL,
@@ -1177,15 +1192,20 @@
ERASEINFO(0x10000,7),
}
}, {
- mfr_id: MANUFACTURER_MACRONIX,
- dev_id: MX29F002T,
- name: "Macronix MX29F002T",
- DevSize: SIZE_256KiB,
- NumEraseRegions: 4,
- regions: {ERASEINFO(0x10000,3),
+ .mfr_id = MANUFACTURER_MACRONIX,
+ .dev_id = MX29F002T,
+ .name = "Macronix MX29F002T",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
- ERASEINFO(0x04000,1)
+ ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_PMC,
@@ -1780,7 +1800,6 @@
return 0;
}
- /* Mask out address bits which are smaller than the device type */
p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
@@ -1923,7 +1942,6 @@
if (MTD_UADDR_UNNECESSARY == uaddr_idx)
return 0;
- /* Mask out address bits which are smaller than the device type */
cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
}
diff -wur linux-2.6.10/drivers/mtd/chips/map_ram.c linux-2.6.10-lab/drivers/mtd/chips/map_ram.c
--- linux-2.6.10/drivers/mtd/chips/map_ram.c 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/map_ram.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
/*
* Common code to handle map devices which are simple RAM
* (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.21 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: map_ram.c,v 1.22 2005/01/05 18:05:12 dwmw2 Exp $
*/
#include
@@ -83,7 +83,7 @@
static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
map_copy_from(map, buf, from, len);
*retlen = len;
@@ -92,7 +92,7 @@
static int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
map_copy_to(map, to, buf, len);
*retlen = len;
@@ -103,7 +103,7 @@
{
/* Yeah, it's inefficient. Who cares? It's faster than a _real_
flash erase. */
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
map_word allff;
unsigned long i;
diff -wur linux-2.6.10/drivers/mtd/chips/map_rom.c linux-2.6.10-lab/drivers/mtd/chips/map_rom.c
--- linux-2.6.10/drivers/mtd/chips/map_rom.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/chips/map_rom.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
/*
* Common code to handle map devices which are simple ROM
* (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.22 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: map_rom.c,v 1.23 2005/01/05 18:05:12 dwmw2 Exp $
*/
#include
@@ -57,7 +57,7 @@
static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
map_copy_from(map, buf, from, len);
*retlen = len;
diff -wur linux-2.6.10/drivers/mtd/cmdlinepart.c linux-2.6.10-lab/drivers/mtd/cmdlinepart.c
--- linux-2.6.10/drivers/mtd/cmdlinepart.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/cmdlinepart.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: cmdlinepart.c,v 1.16 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
*
* Read flash partition table from command line
*
@@ -338,8 +338,10 @@
* This is the handler for our kernel parameter, called from
* main.c::checksetup(). Note that we can not yet kmalloc() anything,
* so we only save the commandline for later processing.
+ *
+ * This function needs to be visible for bootloaders.
*/
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
diff -wur linux-2.6.10/drivers/mtd/devices/Kconfig linux-2.6.10-lab/drivers/mtd/devices/Kconfig
--- linux-2.6.10/drivers/mtd/devices/Kconfig 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.13 2004/10/01 21:47:13 gleixner Exp $
+# $Id: Kconfig,v 1.16 2005/01/06 15:15:47 dwmw2 Exp $
menu "Self-contained MTD device drivers"
depends on MTD!=n
@@ -125,11 +125,22 @@
Testing MTD users (eg JFFS2) on large media and media that might
be removed during a write (using the floppy drive).
+config MTD_BLOCK2MTD
+ tristate "MTD using block device (rewrite)"
+ depends on MTD && EXPERIMENTAL
+ help
+ This driver is basically the same at MTD_BLKMTD above, but
+ experienced some interface changes plus serious speedups. In
+ the long term, it should replace MTD_BLKMTD. Right now, you
+ shouldn't entrust important data to it yet.
+
comment "Disk-On-Chip Device Drivers"
config MTD_DOC2000
tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
depends on MTD
+ select MTD_DOCPROBE
+ select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
2000 and Millennium devices. Originally designed for the DiskOnChip
@@ -151,6 +162,8 @@
config MTD_DOC2001
tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
depends on MTD
+ select MTD_DOCPROBE
+ select MTD_NAND_IDS
---help---
This provides an alternative MTD device driver for the M-Systems
DiskOnChip Millennium devices. Use this if you have problems with
@@ -171,6 +184,8 @@
config MTD_DOC2001PLUS
tristate "M-Systems Disk-On-Chip Millennium Plus"
depends on MTD
+ select MTD_DOCPROBE
+ select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
Millennium Plus devices.
@@ -186,17 +201,10 @@
config MTD_DOCPROBE
tristate
- default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
- default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
- help
- This isn't a real config option; it's derived.
+ select MTD_DOCECC
config MTD_DOCECC
tristate
- default m if MTD_DOCPROBE=m
- default y if MTD_DOCPROBE=y
- help
- This isn't a real config option; it's derived.
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
diff -wur linux-2.6.10/drivers/mtd/devices/Makefile linux-2.6.10-lab/drivers/mtd/devices/Makefile
--- linux-2.6.10/drivers/mtd/devices/Makefile 2004-12-24 16:33:48.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/Makefile 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
#
# linux/drivers/devices/Makefile
#
-# $Id: Makefile.common,v 1.6 2004/07/12 16:07:30 dwmw2 Exp $
+# $Id: Makefile.common,v 1.7 2004/12/22 17:51:15 joern Exp $
# *** BIG UGLY NOTE ***
#
@@ -22,3 +22,4 @@
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
+obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
diff -wur linux-2.6.10/drivers/mtd/devices/doc2000.c linux-2.6.10-lab/drivers/mtd/devices/doc2000.c
--- linux-2.6.10/drivers/mtd/devices/doc2000.c 2004-12-24 16:33:48.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/doc2000.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse
*
- * $Id: doc2000.c,v 1.64 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $
*/
#include
@@ -527,26 +527,26 @@
*/
static void DoC2k_init(struct mtd_info *mtd)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
int maxchips;
/* We must avoid being called twice for the same device. */
if (doc2klist)
- old = (struct DiskOnChip *) doc2klist->priv;
+ old = doc2klist->priv;
while (old) {
if (DoC2k_is_alias(old, this)) {
printk(KERN_NOTICE
"Ignoring DiskOnChip 2000 at 0x%lX - already configured\n",
this->physadr);
- iounmap((void *) this->virtadr);
+ iounmap(this->virtadr);
kfree(mtd);
return;
}
if (old->nextdoc)
- old = (struct DiskOnChip *) old->nextdoc->priv;
+ old = old->nextdoc->priv;
else
old = NULL;
}
@@ -573,7 +573,7 @@
default:
printk("Unknown ChipID 0x%02x\n", this->ChipID);
kfree(mtd);
- iounmap((void *) this->virtadr);
+ iounmap(this->virtadr);
return;
}
@@ -612,7 +612,7 @@
if (!this->totlen) {
kfree(mtd);
- iounmap((void *) this->virtadr);
+ iounmap(this->virtadr);
} else {
this->nextdoc = doc2klist;
doc2klist = mtd;
@@ -633,7 +633,7 @@
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip;
unsigned char syndrome[6];
@@ -790,7 +790,7 @@
size_t * retlen, const u_char * buf,
u_char * eccbuf, struct nand_oobinfo *oobsel)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
void __iomem *docptr = this->virtadr;
volatile char dummy;
@@ -1033,7 +1033,7 @@
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, u_char * buf)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
int len256 = 0, ret;
struct Nand *mychip;
@@ -1091,7 +1091,7 @@
static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, const u_char * buf)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
int len256 = 0;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
@@ -1194,7 +1194,7 @@
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, const u_char * buf)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
int ret;
down(&this->lock);
@@ -1206,7 +1206,7 @@
static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
__u32 ofs = instr->addr;
__u32 len = instr->len;
volatile int dummy;
@@ -1288,12 +1288,12 @@
struct DiskOnChip *this;
while ((mtd = doc2klist)) {
- this = (struct DiskOnChip *) mtd->priv;
+ this = mtd->priv;
doc2klist = this->nextdoc;
del_mtd_device(mtd);
- iounmap((void *) this->virtadr);
+ iounmap(this->virtadr);
kfree(this->chips);
kfree(mtd);
}
diff -wur linux-2.6.10/drivers/mtd/devices/doc2001.c linux-2.6.10-lab/drivers/mtd/devices/doc2001.c
--- linux-2.6.10/drivers/mtd/devices/doc2001.c 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/doc2001.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse
*
- * $Id: doc2001.c,v 1.46 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $
*/
#include
@@ -335,23 +335,23 @@
*/
static void DoCMil_init(struct mtd_info *mtd)
{
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
/* We must avoid being called twice for the same device. */
if (docmillist)
- old = (struct DiskOnChip *)docmillist->priv;
+ old = docmillist->priv;
while (old) {
if (DoCMil_is_alias(this, old)) {
printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at "
"0x%lX - already configured\n", this->physadr);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
kfree(mtd);
return;
}
if (old->nextdoc)
- old = (struct DiskOnChip *)old->nextdoc->priv;
+ old = old->nextdoc->priv;
else
old = NULL;
}
@@ -392,7 +392,7 @@
if (!this->totlen) {
kfree(mtd);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
} else {
this->nextdoc = docmillist;
docmillist = mtd;
@@ -416,7 +416,7 @@
int i, ret;
volatile char dummy;
unsigned char syndrome[6];
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -542,7 +542,7 @@
{
int i,ret = 0;
volatile char dummy;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@@ -677,7 +677,7 @@
int i;
#endif
volatile char dummy;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
@@ -729,7 +729,7 @@
#endif
volatile char dummy;
int ret = 0;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
@@ -796,7 +796,7 @@
int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
{
volatile char dummy;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
__u32 ofs = instr->addr;
__u32 len = instr->len;
void __iomem *docptr = this->virtadr;
@@ -868,12 +868,12 @@
struct DiskOnChip *this;
while ((mtd=docmillist)) {
- this = (struct DiskOnChip *)mtd->priv;
+ this = mtd->priv;
docmillist = this->nextdoc;
del_mtd_device(mtd);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
kfree(this->chips);
kfree(mtd);
}
diff -wur linux-2.6.10/drivers/mtd/devices/doc2001plus.c linux-2.6.10-lab/drivers/mtd/devices/doc2001plus.c
--- linux-2.6.10/drivers/mtd/devices/doc2001plus.c 2004-12-24 16:33:47.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/doc2001plus.c 2007-10-04 19:10:17.000000000 -0400
@@ -6,7 +6,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse
*
- * $Id: doc2001plus.c,v 1.11 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $
*
* Released under GPL
*/
@@ -190,7 +190,7 @@
may not want it */
static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
{
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
if (this->interleave) {
unsigned int ofs = *from & 0x3ff;
@@ -458,24 +458,24 @@
*/
static void DoCMilPlus_init(struct mtd_info *mtd)
{
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
struct DiskOnChip *old = NULL;
/* We must avoid being called twice for the same device. */
if (docmilpluslist)
- old = (struct DiskOnChip *)docmilpluslist->priv;
+ old = docmilpluslist->priv;
while (old) {
if (DoCMilPlus_is_alias(this, old)) {
printk(KERN_NOTICE "Ignoring DiskOnChip Millennium "
"Plus at 0x%lX - already configured\n",
this->physadr);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
kfree(mtd);
return;
}
if (old->nextdoc)
- old = (struct DiskOnChip *)old->nextdoc->priv;
+ old = old->nextdoc->priv;
else
old = NULL;
}
@@ -514,7 +514,7 @@
if (!this->totlen) {
kfree(mtd);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
} else {
this->nextdoc = docmilpluslist;
docmilpluslist = mtd;
@@ -530,7 +530,7 @@
{
int i;
loff_t fofs;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
unsigned char *bp, buf[1056];
@@ -615,7 +615,7 @@
volatile char dummy;
loff_t fofs;
unsigned char syndrome[6];
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -754,7 +754,7 @@
int i, before, ret = 0;
loff_t fto;
volatile char dummy;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@@ -880,7 +880,7 @@
size_t *retlen, u_char *buf)
{
loff_t fofs, base;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
@@ -958,7 +958,7 @@
{
volatile char dummy;
loff_t fofs, base;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
size_t i, size, got, want;
@@ -1058,7 +1058,7 @@
int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
{
volatile char dummy;
- struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *this = mtd->priv;
__u32 ofs = instr->addr;
__u32 len = instr->len;
void __iomem * docptr = this->virtadr;
@@ -1134,12 +1134,12 @@
struct DiskOnChip *this;
while ((mtd=docmilpluslist)) {
- this = (struct DiskOnChip *)mtd->priv;
+ this = mtd->priv;
docmilpluslist = this->nextdoc;
del_mtd_device(mtd);
- iounmap((void *)this->virtadr);
+ iounmap(this->virtadr);
kfree(this->chips);
kfree(mtd);
}
diff -wur linux-2.6.10/drivers/mtd/devices/docprobe.c linux-2.6.10-lab/drivers/mtd/devices/docprobe.c
--- linux-2.6.10/drivers/mtd/devices/docprobe.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/docprobe.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,7 +4,7 @@
/* (C) 1999 Machine Vision Holdings, Inc. */
/* (C) 1999-2003 David Woodhouse */
-/* $Id: docprobe.c,v 1.43 2004/11/16 18:29:01 dwmw2 Exp $ */
+/* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $ */
@@ -94,9 +94,9 @@
/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
-static inline int __init doccheck(unsigned long potential, unsigned long physadr)
+static inline int __init doccheck(void __iomem *potential, unsigned long physadr)
{
- unsigned long window=potential;
+ void __iomem *window=potential;
unsigned char tmp, tmpb, tmpc, ChipID;
#ifndef DOC_PASSIVE_PROBE
unsigned char tmp2;
@@ -233,7 +233,7 @@
static void __init DoC_Probe(unsigned long physadr)
{
- unsigned long docptr;
+ void __iomem *docptr;
struct DiskOnChip *this;
struct mtd_info *mtd;
int ChipID;
@@ -243,7 +243,7 @@
char *im_modname = NULL;
void (*initroutine)(struct mtd_info *) = NULL;
- docptr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+ docptr = ioremap(physadr, DOC_IOREMAP_LEN);
if (!docptr)
return;
@@ -252,7 +252,7 @@
if (ChipID == DOC_ChipID_Doc2kTSOP) {
/* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
- iounmap((void *)docptr);
+ iounmap(docptr);
return;
}
docfound = 1;
@@ -260,7 +260,7 @@
if (!mtd) {
printk(KERN_WARNING "Cannot allocate memory for data structures. Dropping.\n");
- iounmap((void *)docptr);
+ iounmap(docptr);
return;
}
@@ -270,7 +270,7 @@
memset((char *)this, 0, sizeof(struct DiskOnChip));
mtd->priv = this;
- this->virtadr = (void __iomem *)docptr;
+ this->virtadr = docptr;
this->physadr = physadr;
this->ChipID = ChipID;
sprintf(namebuf, "with ChipID %2.2X", ChipID);
@@ -318,7 +318,7 @@
printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
kfree(mtd);
}
- iounmap((void *)docptr);
+ iounmap(docptr);
}
diff -wur linux-2.6.10/drivers/mtd/devices/ms02-nv.c linux-2.6.10-lab/drivers/mtd/devices/ms02-nv.c
--- linux-2.6.10/drivers/mtd/devices/ms02-nv.c 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/ms02-nv.c 2007-10-04 19:10:17.000000000 -0400
@@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: ms02-nv.c,v 1.7 2004/07/29 14:16:45 macro Exp $
+ * $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $
*/
#include
@@ -59,7 +59,7 @@
static int ms02nv_read(struct mtd_info *mtd, loff_t from,
size_t len, size_t *retlen, u_char *buf)
{
- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+ struct ms02nv_private *mp = mtd->priv;
if (from + len > mtd->size)
return -EINVAL;
@@ -73,7 +73,7 @@
static int ms02nv_write(struct mtd_info *mtd, loff_t to,
size_t len, size_t *retlen, const u_char *buf)
{
- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+ struct ms02nv_private *mp = mtd->priv;
if (to + len > mtd->size)
return -EINVAL;
@@ -265,7 +265,7 @@
static void __exit ms02nv_remove_one(void)
{
struct mtd_info *mtd = root_ms02nv_mtd;
- struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+ struct ms02nv_private *mp = mtd->priv;
root_ms02nv_mtd = mp->next;
diff -wur linux-2.6.10/drivers/mtd/devices/mtdram.c linux-2.6.10-lab/drivers/mtd/devices/mtdram.c
--- linux-2.6.10/drivers/mtd/devices/mtdram.c 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/mtdram.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,6 +1,6 @@
/*
* mtdram - a test mtd device
- * $Id: mtdram.c,v 1.34 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
* Author: Alexander Larsson
*
* Copyright (c) 1999 Alexander Larsson
@@ -158,7 +158,7 @@
void *addr;
int err;
/* Allocate some memory */
- mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd_info)
return -ENOMEM;
@@ -191,7 +191,7 @@
void *addr;
int err;
/* Allocate some memory */
- mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!mtd_info)
return -ENOMEM;
diff -wur linux-2.6.10/drivers/mtd/devices/phram.c linux-2.6.10-lab/drivers/mtd/devices/phram.c
--- linux-2.6.10/drivers/mtd/devices/phram.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/phram.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,13 +1,8 @@
/**
+ * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $
*
- * $Id: phram.c,v 1.3 2004/11/16 18:29:01 dwmw2 Exp $
- *
- * Copyright (c) Jochen Schaeuble
- * 07/2003 rewritten by Joern Engel
- *
- * DISCLAIMER: This driver makes use of Rusty's excellent module code,
- * so it will not work for 2.4 without changes and it wont work for 2.4
- * as a module without major changes. Oh well!
+ * Copyright (c) ???? Jochen Schäuble
+ * Copyright (c) 2003-2004 Jörn Engel
*
* Usage:
*
@@ -15,9 +10,12 @@
* phram=,,
* may be up to 63 characters.
* and can be octal, decimal or hexadecimal. If followed
- * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
+ * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
* gigabytes.
*
+ * Example:
+ * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
+ *
*/
#include
@@ -31,8 +29,8 @@
#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
struct phram_mtd_list {
+ struct mtd_info mtd;
struct list_head list;
- struct mtd_info *mtdinfo;
};
static LIST_HEAD(phram_list);
@@ -41,7 +39,7 @@
static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- u_char *start = (u_char *)mtd->priv;
+ u_char *start = mtd->priv;
if (instr->addr + instr->len > mtd->size)
return -EINVAL;
@@ -63,7 +61,7 @@
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf)
{
- u_char *start = (u_char *)mtd->priv;
+ u_char *start = mtd->priv;
if (from + len > mtd->size)
return -EINVAL;
@@ -80,7 +78,7 @@
static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- u_char *start = (u_char *)mtd->priv;
+ u_char *start = mtd->priv;
if (from + len > mtd->size)
return -EINVAL;
@@ -94,7 +92,7 @@
static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- u_char *start = (u_char *)mtd->priv;
+ u_char *start = mtd->priv;
if (to + len > mtd->size)
return -EINVAL;
@@ -112,9 +110,8 @@
struct phram_mtd_list *this;
list_for_each_entry(this, &phram_list, list) {
- del_mtd_device(this->mtdinfo);
- iounmap(this->mtdinfo->priv);
- kfree(this->mtdinfo);
+ del_mtd_device(&this->mtd);
+ iounmap(this->mtd.priv);
kfree(this);
}
}
@@ -128,45 +125,39 @@
if (!new)
goto out0;
- new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!new->mtdinfo)
- goto out1;
-
- memset(new->mtdinfo, 0, sizeof(struct mtd_info));
+ memset(new, 0, sizeof(*new));
ret = -EIO;
- new->mtdinfo->priv = ioremap(start, len);
- if (!new->mtdinfo->priv) {
+ new->mtd.priv = ioremap(start, len);
+ if (!new->mtd.priv) {
ERROR("ioremap failed\n");
- goto out2;
+ goto out1;
}
- new->mtdinfo->name = name;
- new->mtdinfo->size = len;
- new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
- new->mtdinfo->erase = phram_erase;
- new->mtdinfo->point = phram_point;
- new->mtdinfo->unpoint = phram_unpoint;
- new->mtdinfo->read = phram_read;
- new->mtdinfo->write = phram_write;
- new->mtdinfo->owner = THIS_MODULE;
- new->mtdinfo->type = MTD_RAM;
- new->mtdinfo->erasesize = 0x0;
+ new->mtd.name = name;
+ new->mtd.size = len;
+ new->mtd.flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
+ new->mtd.erase = phram_erase;
+ new->mtd.point = phram_point;
+ new->mtd.unpoint = phram_unpoint;
+ new->mtd.read = phram_read;
+ new->mtd.write = phram_write;
+ new->mtd.owner = THIS_MODULE;
+ new->mtd.type = MTD_RAM;
+ new->mtd.erasesize = 0;
ret = -EAGAIN;
- if (add_mtd_device(new->mtdinfo)) {
+ if (add_mtd_device(&new->mtd)) {
ERROR("Failed to register new device\n");
- goto out3;
+ goto out2;
}
list_add_tail(&new->list, &phram_list);
return 0;
-out3:
- iounmap(new->mtdinfo->priv);
out2:
- kfree(new->mtdinfo);
+ iounmap(new->mtd.priv);
out1:
kfree(new);
out0:
@@ -184,7 +175,9 @@
result *= 1024;
case 'k':
result *= 1024;
- endp++;
+ /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
+ if ((*endp)[1] == 'i')
+ (*endp) += 2;
}
return result;
}
@@ -235,7 +228,7 @@
uint32_t len;
int i, ret;
- if (strnlen(val, sizeof(str)) >= sizeof(str))
+ if (strnlen(val, sizeof(buf)) >= sizeof(buf))
parse_err("parameter too long\n");
strcpy(str, val);
@@ -271,78 +264,11 @@
}
module_param_call(phram, phram_setup, NULL, NULL, 000);
-MODULE_PARM_DESC(phram, "Memory region to map. \"map=,\"");
-
-/*
- * Just for compatibility with slram, this is horrible and should go someday.
- */
-static int __init slram_setup(const char *val, struct kernel_param *kp)
-{
- char buf[256], *str = buf;
-
- if (!val || !val[0])
- parse_err("no arguments to \"slram=\"\n");
-
- if (strnlen(val, sizeof(str)) >= sizeof(str))
- parse_err("parameter too long\n");
-
- strcpy(str, val);
-
- while (str) {
- char *token[3];
- char *name;
- uint32_t start;
- uint32_t len;
- int i, ret;
-
- for (i=0; i<3; i++) {
- token[i] = strsep(&str, ",");
- if (token[i])
- continue;
- parse_err("wrong number of arguments to \"slram=\"\n");
- }
-
- /* name */
- ret = parse_name(&name, token[0]);
- if (ret == -ENOMEM)
- parse_err("of memory\n");
- if (ret == -ENOSPC)
- parse_err("too long\n");
- if (ret)
- return 1;
-
- /* start */
- ret = parse_num32(&start, token[1]);
- if (ret)
- parse_err("illegal start address\n");
-
- /* len */
- if (token[2][0] == '+')
- ret = parse_num32(&len, token[2] + 1);
- else
- ret = parse_num32(&len, token[2]);
-
- if (ret)
- parse_err("illegal device length\n");
-
- if (token[2][0] != '+') {
- if (len < start)
- parse_err("end < start\n");
- len -= start;
- }
-
- register_device(name, start, len);
- }
- return 1;
-}
-
-module_param_call(slram, slram_setup, NULL, NULL, 000);
-MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=,\"");
+MODULE_PARM_DESC(phram,"Memory region to map. \"map=,,\"");
static int __init init_phram(void)
{
- printk(KERN_ERR "phram loaded\n");
return 0;
}
diff -wur linux-2.6.10/drivers/mtd/devices/pmc551.c linux-2.6.10-lab/drivers/mtd/devices/pmc551.c
--- linux-2.6.10/drivers/mtd/devices/pmc551.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/pmc551.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: pmc551.c,v 1.29 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $
*
* PMC551 PCI Mezzanine Ram Device
*
@@ -113,7 +113,7 @@
static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
{
- struct mypriv *priv = (struct mypriv *)mtd->priv;
+ struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
@@ -176,7 +176,7 @@
static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
{
- struct mypriv *priv = (struct mypriv *)mtd->priv;
+ struct mypriv *priv = mtd->priv;
u32 soff_hi;
u32 soff_lo;
@@ -217,7 +217,7 @@
static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
- struct mypriv *priv = (struct mypriv *)mtd->priv;
+ struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
@@ -279,7 +279,7 @@
static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
- struct mypriv *priv = (struct mypriv *)mtd->priv;
+ struct mypriv *priv = mtd->priv;
u32 soff_hi, soff_lo; /* start address offset hi/lo */
u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
unsigned long end;
@@ -820,7 +820,7 @@
struct mypriv *priv;
while((mtd=pmc551list)) {
- priv = (struct mypriv *)mtd->priv;
+ priv = mtd->priv;
pmc551list = priv->nextpmc551;
if(priv->start) {
diff -wur linux-2.6.10/drivers/mtd/devices/slram.c linux-2.6.10-lab/drivers/mtd/devices/slram.c
--- linux-2.6.10/drivers/mtd/devices/slram.c 2004-12-24 16:33:47.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/devices/slram.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,6 +1,6 @@
/*======================================================================
- $Id: slram.c,v 1.32 2004/11/16 18:29:01 dwmw2 Exp $
+ $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
This driver provides a method to access memory not used by the kernel
itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -50,6 +50,7 @@
#include
#define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */
+#define SLRAM_BLK_SZ 0x4000
#define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
#define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
@@ -106,7 +107,10 @@
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf)
{
- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
+ slram_priv_t *priv = mtd->priv;
+
+ if (from + len > mtd->size)
+ return -EINVAL;
*mtdbuf = priv->start + from;
*retlen = len;
@@ -120,7 +124,13 @@
static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
+ slram_priv_t *priv = mtd->priv;
+
+ if (from > mtd->size)
+ return -EINVAL;
+
+ if (from + len > mtd->size)
+ len = mtd->size - from;
memcpy(buf, priv->start + from, len);
@@ -131,7 +141,10 @@
static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- slram_priv_t *priv = (slram_priv_t *)mtd->priv;
+ slram_priv_t *priv = mtd->priv;
+
+ if (to + len > mtd->size)
+ return -EINVAL;
memcpy(priv->start + to, buf, len);
@@ -161,7 +174,7 @@
if ((*curmtd)->mtdinfo) {
memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
(*curmtd)->mtdinfo->priv =
- (void *)kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
+ kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
if (!(*curmtd)->mtdinfo->priv) {
kfree((*curmtd)->mtdinfo);
@@ -188,7 +201,7 @@
(*curmtd)->mtdinfo->name = name;
(*curmtd)->mtdinfo->size = length;
(*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
- MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+ MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
(*curmtd)->mtdinfo->erase = slram_erase;
(*curmtd)->mtdinfo->point = slram_point;
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
@@ -196,7 +209,7 @@
(*curmtd)->mtdinfo->write = slram_write;
(*curmtd)->mtdinfo->owner = THIS_MODULE;
(*curmtd)->mtdinfo->type = MTD_RAM;
- (*curmtd)->mtdinfo->erasesize = 0x0;
+ (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
if (add_mtd_device((*curmtd)->mtdinfo)) {
E("slram: Failed to register new device\n");
@@ -261,7 +274,7 @@
}
T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
devname, devstart, devlength);
- if ((devstart < 0) || (devlength < 0)) {
+ if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
E("slram: Illegal start / length parameter.\n");
return(-EINVAL);
}
diff -wur linux-2.6.10/drivers/mtd/ftl.c linux-2.6.10-lab/drivers/mtd/ftl.c
--- linux-2.6.10/drivers/mtd/ftl.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/ftl.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $
+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
*
* Fixes: Arnaldo Carvalho de Melo
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -357,6 +357,7 @@
if (!erase)
return -ENOMEM;
+ erase->mtd = part->mbd.mtd;
erase->callback = ftl_erase_callback;
erase->addr = xfer->Offset;
erase->len = 1 << part->header.EraseUnitSize;
@@ -1096,7 +1097,7 @@
int init_ftl(void)
{
- DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n");
+ DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
return register_mtd_blktrans(&ftl_tr);
}
diff -wur linux-2.6.10/drivers/mtd/inftlmount.c linux-2.6.10-lab/drivers/mtd/inftlmount.c
--- linux-2.6.10/drivers/mtd/inftlmount.c 2004-12-24 16:33:51.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/inftlmount.c 2007-10-04 19:10:17.000000000 -0400
@@ -8,7 +8,7 @@
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
- * $Id: inftlmount.c,v 1.15 2004/11/05 21:55:55 kalev Exp $
+ * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $
*
* 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
@@ -41,7 +41,7 @@
#include
#include
-char inftlmountrev[]="$Revision: 1.15 $";
+char inftlmountrev[]="$Revision: 1.16 $";
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
@@ -389,8 +389,6 @@
struct erase_info *instr = &inftl->instr;
int physblock;
- instr->mtd = inftl->mbd.mtd;
-
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
"block=%d)\n", inftl, block);
@@ -400,6 +398,7 @@
_first_? */
/* Use async erase interface, test return code */
+ instr->mtd = inftl->mbd.mtd;
instr->addr = block * inftl->EraseSize;
instr->len = inftl->mbd.mtd->erasesize;
/* Erase one physical eraseblock at a time, even though the NAND api
diff -wur linux-2.6.10/drivers/mtd/maps/Kconfig linux-2.6.10-lab/drivers/mtd/maps/Kconfig
--- linux-2.6.10/drivers/mtd/maps/Kconfig 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.37 2004/10/20 22:57:18 dwmw2 Exp $
+# $Id: Kconfig,v 1.43 2005/01/24 00:35:21 bjd Exp $
menu "Mapping drivers for chip access"
depends on MTD!=n
@@ -132,6 +132,29 @@
devices. This board utilizes Intel StrataFlash. More info at
.
+config MTD_GUMSTIX
+ tristate "CFI Flash device mapped the gumstix "
+ depends on ARCH_GUMSTIX && MTD_CFI_INTELEXT && MTD_PARTITIONS
+ help
+ This provides a driver for the on-board flash of the Gumstix
+ single board computers.
+
+
+config MTD_FIONA
+ tristate "CFI Flash device mapped on Fiona board"
+ depends on ARCH_FIONA && MTD_CFI_INTELEXT && MTD_PARTITIONS
+ help
+ This provides a driver for the on-board flash of the Fiona
+ development board.
+
+
+config MTD_ONENAND_FIONA
+ tristate "OneNAND Flash device on FIONA board"
+ depends on ARCH_FIONA && MTD_ONENAND
+ help
+ Support for OneNAND flash on FIONA board.
+
+
config MTD_LUBBOCK
tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
@@ -159,7 +182,7 @@
config MTD_SCx200_DOCFLASH
tristate "Flash device mapped with DOCCS on NatSemi SCx200"
- depends on X86 && MTD_CFI
+ depends on X86 && MTD_CFI && MTD_PARTITIONS
help
Enable support for a flash chip mapped using the DOCCS signal on a
National Semiconductor SCx200 processor.
@@ -373,9 +396,17 @@
Arctic board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
+config MTD_WALNUT
+ tristate "Flash device mapped on IBM 405GP Walnut"
+ depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT
+ help
+ This enables access routines for the flash chips on the IBM 405GP
+ Walnut board. If you have one of these boards and would like to
+ use the flash chips on it, say 'Y'.
+
config MTD_EBONY
tristate "Flash devices mapped on IBM 440GP Ebony"
- depends on MTD_CFI && PPC32 && 44x && EBONY
+ depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY
help
This enables access routines for the flash chips on the IBM 440GP
Ebony board. If you have one of these boards and would like to
@@ -397,6 +428,14 @@
Redwood board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
+config MTD_CHESTNUT
+ tristate "CFI Flash devices mapped on IBM 750FX or IBM 750GX Eval Boards"
+ depends on MTD_CFI && PPC32 && CHESTNUT && MTD_PARTITIONS
+ help
+ This enables access routines for the flash chips on the IBM
+ 750FX and 750GX Eval Boards. If you have one of these boards and
+ would like to use the flash chips on it, say 'Y'
+
config MTD_CSTM_MIPS_IXX
tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
@@ -467,6 +506,12 @@
This enables access to the flash or ROM chips on the CDB89712 board.
If you have such a board, say 'Y'.
+config MTD_PCMCIA
+ tristate "PCMCIA/CF MTD flash cards"
+ depends on PCMCIA
+ help
+ This enables access to generic flash memory CF and PCMCIA card.
+
config MTD_SA1100
tristate "CFI Flash device mapped on StrongARM SA11x0"
depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
@@ -645,5 +690,21 @@
depends on MTD_BAST
default "4"
+config MTD_SHARP_SL
+ bool "ROM maped on Sharp SL Series"
+ depends on MTD && ARCH_PXA
+ help
+ This enables access to the flash chip on the Sharp SL Series of PDAs.
+
+config MTD_PLATRAM
+ tristate "Map driver for platfrom device RAM (mtd-ram)"
+ depends on MTD
+ select MTD_RAM
+ help
+ Map driver for RAM areas described via the platform device
+ system.
+
+ This selection automatically selects the map_ram driver.
+
endmenu
diff -wur linux-2.6.10/drivers/mtd/maps/Makefile linux-2.6.10-lab/drivers/mtd/maps/Makefile
--- linux-2.6.10/drivers/mtd/maps/Makefile 2004-12-24 16:33:47.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/Makefile 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
#
# linux/drivers/maps/Makefile
#
-# $Id: Makefile.common,v 1.19 2004/09/21 14:27:16 bjd Exp $
+# $Id: Makefile.common,v 1.24 2005/01/24 00:35:21 bjd Exp $
ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
obj-$(CONFIG_MTD) += map_funcs.o
@@ -54,6 +54,7 @@
obj-$(CONFIG_MTD_IMPA7) += impa7.o
obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
obj-$(CONFIG_MTD_REDWOOD) += redwood.o
+obj-$(CONFIG_MTD_CHESTNUT) += chestnut.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
@@ -61,6 +62,7 @@
obj-$(CONFIG_MTD_OCOTEA) += ocotea.o
obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
+obj-$(CONFIG_MTD_WALNUT) += walnut.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
@@ -69,3 +71,8 @@
obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
+obj-$(CONFIG_MTD_GUMSTIX) += gumstix-flash.o
+obj-$(CONFIG_MTD_FIONA) += fiona-flash.o
+obj-$(CONFIG_MTD_ONENAND_FIONA) += fiona-onenand.o
+obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
+obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
diff -wur linux-2.6.10/drivers/mtd/maps/amd76xrom.c linux-2.6.10-lab/drivers/mtd/maps/amd76xrom.c
--- linux-2.6.10/drivers/mtd/maps/amd76xrom.c 2004-12-24 16:34:27.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/amd76xrom.c 2007-10-04 19:10:17.000000000 -0400
@@ -2,7 +2,7 @@
* amd76xrom.c
*
* Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.18 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
*/
#include
diff -wur linux-2.6.10/drivers/mtd/maps/bast-flash.c linux-2.6.10-lab/drivers/mtd/maps/bast-flash.c
--- linux-2.6.10/drivers/mtd/maps/bast-flash.c 2004-12-24 16:33:52.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/bast-flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,14 +1,15 @@
/* linux/drivers/mtd/maps/bast_flash.c
*
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks
*
* Simtec Bast (EB2410ITX) NOR MTD Mapping driver
*
* Changelog:
* 20-Sep-2004 BJD Initial version
+ * 17-Jan-2005 BJD Add whole device if no partitions found
*
- * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
*
* 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
@@ -46,9 +47,9 @@
#include
#ifdef CONFIG_MTD_BAST_MAXSIZE
-#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
#else
-#define AREA_MAXSIZE (32*1024*1024)
+#define AREA_MAXSIZE (32 * SZ_1M)
#endif
#define PFX "bast-flash: "
@@ -189,6 +190,8 @@
err = add_mtd_partitions(info->mtd, info->partitions, err);
if (err)
printk(KERN_ERR PFX "cannot add/parse partitions\n");
+ } else {
+ err = add_mtd_device(info->mtd);
}
if (err == 0)
diff -wur linux-2.6.10/drivers/mtd/maps/cstm_mips_ixx.c linux-2.6.10-lab/drivers/mtd/maps/cstm_mips_ixx.c
--- linux-2.6.10/drivers/mtd/maps/cstm_mips_ixx.c 2004-12-24 16:34:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/cstm_mips_ixx.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: cstm_mips_ixx.c,v 1.12 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: cstm_mips_ixx.c,v 1.13 2005/01/12 22:34:35 gleixner Exp $
*
* Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
* Config with both CFI and JEDEC device support.
@@ -58,7 +58,7 @@
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
{
- static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(vpp_lock);
static int vpp_count = 0;
unsigned long flags;
diff -wur linux-2.6.10/drivers/mtd/maps/dilnetpc.c linux-2.6.10-lab/drivers/mtd/maps/dilnetpc.c
--- linux-2.6.10/drivers/mtd/maps/dilnetpc.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/dilnetpc.c 2007-10-04 19:10:17.000000000 -0400
@@ -14,7 +14,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: dilnetpc.c,v 1.16 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: dilnetpc.c,v 1.18 2005/01/12 22:34:35 gleixner Exp $
*
* The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
* featuring the AMD Elan SC410 processor. There are two variants of this
@@ -197,7 +197,7 @@
************************************************************
*/
-static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dnpc_spin);
static int vpp_counter = 0;
/*
** This is what has to be done for the DNP board ..
diff -wur linux-2.6.10/drivers/mtd/maps/ebony.c linux-2.6.10-lab/drivers/mtd/maps/ebony.c
--- linux-2.6.10/drivers/mtd/maps/ebony.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/ebony.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: ebony.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $
*
* Mapping for Ebony user flash
*
@@ -103,7 +103,7 @@
simple_map_init(&ebony_small_map);
- flash = do_map_probe("map_rom", &ebony_small_map);
+ flash = do_map_probe("jedec_probe", &ebony_small_map);
if (flash) {
flash->owner = THIS_MODULE;
add_mtd_partitions(flash, ebony_small_partitions,
@@ -124,7 +124,7 @@
simple_map_init(&ebony_large_map);
- flash = do_map_probe("cfi_probe", &ebony_large_map);
+ flash = do_map_probe("jedec_probe", &ebony_large_map);
if (flash) {
flash->owner = THIS_MODULE;
add_mtd_partitions(flash, ebony_large_partitions,
diff -wur linux-2.6.10/drivers/mtd/maps/elan-104nc.c linux-2.6.10-lab/drivers/mtd/maps/elan-104nc.c
--- linux-2.6.10/drivers/mtd/maps/elan-104nc.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/elan-104nc.c 2007-10-04 19:10:17.000000000 -0400
@@ -16,7 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- $Id: elan-104nc.c,v 1.24 2004/11/16 18:29:02 dwmw2 Exp $
+ $Id: elan-104nc.c,v 1.26 2005/01/12 22:34:35 gleixner Exp $
The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
@@ -54,7 +54,7 @@
static volatile int page_in_window = -1; // Current page in window.
static void __iomem *iomapadr;
-static spinlock_t elan_104nc_spin = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(elan_104nc_spin);
/* partition_info gives details on the logical partitions that the split the
* single flash device into. If the size if zero we use up to the end of the
diff -wur linux-2.6.10/drivers/mtd/maps/ichxrom.c linux-2.6.10-lab/drivers/mtd/maps/ichxrom.c
--- linux-2.6.10/drivers/mtd/maps/ichxrom.c 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/ichxrom.c 2007-10-04 19:10:17.000000000 -0400
@@ -2,7 +2,7 @@
* ichxrom.c
*
* Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.15 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
*/
#include
diff -wur linux-2.6.10/drivers/mtd/maps/ipaq-flash.c linux-2.6.10-lab/drivers/mtd/maps/ipaq-flash.c
--- linux-2.6.10/drivers/mtd/maps/ipaq-flash.c 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/ipaq-flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -5,7 +5,7 @@
* (C) 2002 Hewlett-Packard Company
* (C) 2003 Christian Pellegrin , : concatenation of multiple flashes
*
- * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: ipaq-flash.c,v 1.4 2005/01/12 22:34:35 gleixner Exp $
*/
#include
@@ -143,7 +143,7 @@
};
#endif
-static spinlock_t ipaq_vpp_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ipaq_vpp_lock);
static void h3xxx_set_vpp(struct map_info *map, int vpp)
{
diff -wur linux-2.6.10/drivers/mtd/maps/l440gx.c linux-2.6.10-lab/drivers/mtd/maps/l440gx.c
--- linux-2.6.10/drivers/mtd/maps/l440gx.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/l440gx.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: l440gx.c,v 1.16 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
*
* BIOS Flash chip on Intel 440GX board.
*
diff -wur linux-2.6.10/drivers/mtd/maps/netsc520.c linux-2.6.10-lab/drivers/mtd/maps/netsc520.c
--- linux-2.6.10/drivers/mtd/maps/netsc520.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/netsc520.c 2007-10-04 19:10:17.000000000 -0400
@@ -3,7 +3,7 @@
* Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
* based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
*
- * $Id: netsc520.c,v 1.12 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $
*
* 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
diff -wur linux-2.6.10/drivers/mtd/maps/nettel.c linux-2.6.10-lab/drivers/mtd/maps/nettel.c
--- linux-2.6.10/drivers/mtd/maps/nettel.c 2004-12-24 16:34:27.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/nettel.c 2007-10-04 19:10:17.000000000 -0400
@@ -6,7 +6,7 @@
* (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
* (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
*
- * $Id: nettel.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $
*/
/****************************************************************************/
@@ -332,8 +332,8 @@
/* Destroy useless AMD MTD mapping */
amd_mtd = NULL;
- iounmap((void *) nettel_amd_map.virt);
- nettel_amd_map.virt = (unsigned long) NULL;
+ iounmap(nettel_amd_map.virt);
+ nettel_amd_map.virt = NULL;
#else
/* Only AMD flash supported */
return(-ENXIO);
@@ -357,8 +357,7 @@
/* Probe for the the size of the first Intel flash */
nettel_intel_map.size = maxsize;
nettel_intel_map.phys = intel0addr;
- nettel_intel_map.virt = (unsigned long)
- ioremap_nocache(intel0addr, maxsize);
+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
return(-EIO);
@@ -367,7 +366,7 @@
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (! intel_mtd) {
- iounmap((void *) nettel_intel_map.virt);
+ iounmap(nettel_intel_map.virt);
return(-ENXIO);
}
@@ -388,11 +387,10 @@
/* Delete the old map and probe again to do both chips */
map_destroy(intel_mtd);
intel_mtd = NULL;
- iounmap((void *) nettel_intel_map.virt);
+ iounmap(nettel_intel_map.virt);
nettel_intel_map.size = maxsize;
- nettel_intel_map.virt = (unsigned long)
- ioremap_nocache(intel0addr, maxsize);
+ nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
return(-EIO);
@@ -480,7 +478,7 @@
map_destroy(intel_mtd);
}
if (nettel_intel_map.virt) {
- iounmap((void *)nettel_intel_map.virt);
+ iounmap(nettel_intel_map.virt);
nettel_intel_map.virt = 0;
}
#endif
diff -wur linux-2.6.10/drivers/mtd/maps/ocelot.c linux-2.6.10-lab/drivers/mtd/maps/ocelot.c
--- linux-2.6.10/drivers/mtd/maps/ocelot.c 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/ocelot.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: ocelot.c,v 1.15 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $
*
* Flash on Momenco Ocelot
*/
@@ -28,7 +28,7 @@
static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
- struct map_info *map = (struct map_info *)mtd->priv;
+ struct map_info *map = mtd->priv;
size_t done = 0;
/* If we use memcpy, it does word-wide writes. Even though we told the
diff -wur linux-2.6.10/drivers/mtd/maps/octagon-5066.c linux-2.6.10-lab/drivers/mtd/maps/octagon-5066.c
--- linux-2.6.10/drivers/mtd/maps/octagon-5066.c 2004-12-24 16:34:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/octagon-5066.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.27 2005/01/12 22:34:35 gleixner Exp $
/* ######################################################################
Octagon 5066 MTD Driver.
@@ -41,7 +41,7 @@
static volatile char page_n_dev = 0;
static unsigned long iomapadr;
-static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(oct5066_spin);
/*
* We use map_priv_1 to identify which device we are.
diff -wur linux-2.6.10/drivers/mtd/maps/pci.c linux-2.6.10-lab/drivers/mtd/maps/pci.c
--- linux-2.6.10/drivers/mtd/maps/pci.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/pci.c 2007-10-04 19:10:17.000000000 -0400
@@ -7,7 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $
+ * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
*
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
diff -wur linux-2.6.10/drivers/mtd/maps/physmap.c linux-2.6.10-lab/drivers/mtd/maps/physmap.c
--- linux-2.6.10/drivers/mtd/maps/physmap.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/physmap.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: physmap.c,v 1.36 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $
*
* Normal mappings of chips in physical memory
*
diff -wur linux-2.6.10/drivers/mtd/maps/sa1100-flash.c linux-2.6.10-lab/drivers/mtd/maps/sa1100-flash.c
--- linux-2.6.10/drivers/mtd/maps/sa1100-flash.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/sa1100-flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -5,6 +5,7 @@
*
* $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
*/
+
#include
#include
#include
@@ -13,24 +14,177 @@
#include
#include
#include
-#include
-#include
#include
#include
#include
#include
+#include
#include
#include
#include
-#include
-#if 0
+#include
+
+#ifndef CONFIG_ARCH_SA1100
+#error This is for SA1100 architecture only
+#endif
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_SA1100_STATICMAP 1
+
+#ifdef CONFIG_MTD_SA1100_STATICMAP
/*
- * This is here for documentation purposes only - until these people
- * submit their machine types. It will be gone January 2005.
+ * Here are partition information for all known SA1100-based devices.
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ * 1. We no longer support static flash mappings via the machine io_desc
+ * structure.
+ * 2. The flash size given should be the largest flash size that can
+ * be accommodated.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries. Thanks.
*/
+
+#ifdef CONFIG_SA1100_ADSBITSY
+static struct mtd_partition adsbitsy_partitions[] = {
+ {
+ .name = "bootROM",
+ .size = 0x80000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "zImage",
+ .size = 0x100000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "ramdisk.gz",
+ .size = 0x300000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "User FS",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_ASSABET
+/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
+static struct mtd_partition assabet4_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "bootloader params",
+ .size = 0x00020000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "jffs",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
+static struct mtd_partition assabet5_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "bootloader params",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "jffs",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+#define assabet_partitions assabet5_partitions
+#endif
+
+#ifdef CONFIG_SA1100_BADGE4
+/*
+ * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ * Sixty-three 32 KiW Main Blocks (4032 Ki b)
+ *
+ *
+ *
+ * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
+ */
+static struct mtd_partition badge4_partitions[] = {
+ {
+ .name = "BLOB boot loader",
+ .offset = 0,
+ .size = 0x0000A000
+ }, {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 0x00006000
+ }, {
+ .name = "root",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL
+ }
+};
+#endif
+
+
+#ifdef CONFIG_SA1100_CERF
+#ifdef CONFIG_SA1100_CERF_FLASH_32MB
+# define CERF_FLASH_SIZE 0x02000000
+#elif defined CONFIG_SA1100_CERF_FLASH_16MB
+# define CERF_FLASH_SIZE 0x01000000
+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
+# define CERF_FLASH_SIZE 0x00800000
+#else
+# error "Undefined flash size for CERF in sa1100-flash.c"
+#endif
+
+static struct mtd_partition cerf_partitions[] = {
+ {
+ .name = "Bootloader",
+ .size = 0x00020000,
+ .offset = 0x00000000,
+ }, {
+ .name = "Params",
+ .size = 0x00040000,
+ .offset = 0x00020000,
+ }, {
+ .name = "Kernel",
+ .size = 0x00100000,
+ .offset = 0x00060000,
+ }, {
+ .name = "Filesystem",
+ .size = CERF_FLASH_SIZE-0x00160000,
+ .offset = 0x00160000,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_CONSUS
static struct mtd_partition consus_partitions[] = {
{
.name = "Consus boot firmware",
@@ -65,388 +219,1169 @@
.mask_flags = 0,
}
};
+#endif
+
+#ifdef CONFIG_SA1100_FLEXANET
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+#define FLEXANET_FLASH_SIZE 0x02000000
+static struct mtd_partition flexanet_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "bootloader params",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "kernel",
+ .size = 0x000C0000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "altkernel",
+ .size = 0x000C0000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "root",
+ .size = 0x00400000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "free1",
+ .size = 0x00300000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "free2",
+ .size = 0x00300000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "free3",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_FREEBIRD
+static struct mtd_partition freebird_partitions[] = {
+#ifdef CONFIG_SA1100_FREEBIRD_NEW
+ {
+ .name = "firmware",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "kernel",
+ .size = 0x00080000,
+ .offset = 0x00040000,
+ }, {
+ .name = "params",
+ .size = 0x00040000,
+ .offset = 0x000C0000,
+ }, {
+ .name = "initrd",
+ .size = 0x00100000,
+ .offset = 0x00100000,
+ }, {
+ .name = "root cramfs",
+ .size = 0x00300000,
+ .offset = 0x00200000,
+ }, {
+ .name = "usr cramfs",
+ .size = 0x00C00000,
+ .offset = 0x00500000,
+ }, {
+ .name = "local",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x01100000,
+ }
+#else
+ {
+ .size = 0x00040000,
+ .offset = 0,
+ }, {
+ .size = 0x000c0000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .size = 0x00400000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+#endif
+};
+#endif
+
+#ifdef CONFIG_SA1100_FRODO
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+static struct mtd_partition frodo_partitions[] =
+{
+ {
+ .name = "bootloader",
+ .size = 0x00040000,
+ .offset = 0x00000000,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "bootloader params",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "kernel",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "ramdisk",
+ .size = 0x00400000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE
+ }, {
+ .name = "file system",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+static struct mtd_partition graphicsclient_partitions[] = {
+ {
+ .name = "zImage",
+ .size = 0x100000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "ramdisk.gz",
+ .size = 0x300000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "User FS",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+static struct mtd_partition graphicsmaster_partitions[] = {
+ {
+ .name = "zImage",
+ .size = 0x100000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "ramdisk.gz",
+ .size = 0x300000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "User FS",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_H3XXX
+static struct mtd_partition h3xxx_partitions[] = {
+ {
+ .name = "H3XXX boot firmware",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+#ifdef CONFIG_MTD_2PARTS_IPAQ
+ .name = "H3XXX root jffs2",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00040000,
+#else
+ .name = "H3XXX kernel",
+ .size = 0x00080000,
+ .offset = 0x00040000,
+ }, {
+ .name = "H3XXX params",
+ .size = 0x00040000,
+ .offset = 0x000C0000,
+ }, {
+#ifdef CONFIG_JFFS2_FS
+ .name = "H3XXX root jffs2",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00100000,
+#else
+ .name = "H3XXX initrd",
+ .size = 0x00100000,
+ .offset = 0x00100000,
+ }, {
+ .name = "H3XXX root cramfs",
+ .size = 0x00300000,
+ .offset = 0x00200000,
+ }, {
+ .name = "H3XXX usr cramfs",
+ .size = 0x00800000,
+ .offset = 0x00500000,
+ }, {
+ .name = "H3XXX usr local",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00d00000,
+#endif
+#endif
+ }
+};
+
+static void h3xxx_set_vpp(struct map_info *map, int vpp)
+{
+ assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
+}
+#else
+#define h3xxx_set_vpp NULL
+#endif
+
+#ifdef CONFIG_SA1100_HACKKIT
+static struct mtd_partition hackkit_partitions[] = {
+ {
+ .name = "BLOB",
+ .size = 0x00040000,
+ .offset = 0x00000000,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "config",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "kernel",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "initrd",
+ .size = 0x00180000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "rootfs",
+ .size = 0x700000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "data",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct mtd_partition huw_webpanel_partitions[] = {
+ {
+ .name = "Loader",
+ .size = 0x00040000,
+ .offset = 0,
+ }, {
+ .name = "Sector 1",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA56X
+static struct mtd_partition jornada56x_partitions[] = {
+ {
+ .name = "bootldr",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE,
+ }, {
+ .name = "rootfs",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+static void jornada56x_set_vpp(struct map_info *map, int vpp)
+{
+ if (vpp)
+ GPSR = GPIO_GPIO26;
+ else
+ GPCR = GPIO_GPIO26;
+ GPDR |= GPIO_GPIO26;
+}
+#else
+#define jornada56x_set_vpp NULL
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+static struct mtd_partition jornada720_partitions[] = {
+ {
+ .name = "JORNADA720 boot firmware",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "JORNADA720 kernel",
+ .size = 0x000c0000,
+ .offset = 0x00040000,
+ }, {
+ .name = "JORNADA720 params",
+ .size = 0x00040000,
+ .offset = 0x00100000,
+ }, {
+ .name = "JORNADA720 initrd",
+ .size = 0x00100000,
+ .offset = 0x00140000,
+ }, {
+ .name = "JORNADA720 root cramfs",
+ .size = 0x00300000,
+ .offset = 0x00240000,
+ }, {
+ .name = "JORNADA720 usr cramfs",
+ .size = 0x00800000,
+ .offset = 0x00540000,
+ }, {
+ .name = "JORNADA720 usr local",
+ .size = 0, /* will expand to the end of the flash */
+ .offset = 0x00d00000,
+ }
+};
+
+static void jornada720_set_vpp(struct map_info *map, int vpp)
+{
+ if (vpp)
+ PPSR |= 0x80;
+ else
+ PPSR &= ~0x80;
+ PPDR |= 0x80;
+}
+#else
+#define jornada720_set_vpp NULL
+#endif
+
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct mtd_partition pangolin_partitions[] = {
+ {
+ .name = "boot firmware",
+ .size = 0x00080000,
+ .offset = 0x00000000,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "kernel",
+ .size = 0x00100000,
+ .offset = 0x00080000,
+ }, {
+ .name = "initrd",
+ .size = 0x00280000,
+ .offset = 0x00180000,
+ }, {
+ .name = "initrd-test",
+ .size = 0x03C00000,
+ .offset = 0x00400000,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+/* erase size is 0x40000 == 256k partitions have to have this boundary */
+static struct mtd_partition system3_partitions[] = {
+ {
+ .name = "BLOB",
+ .size = 0x00040000,
+ .offset = 0x00000000,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "config",
+ .size = 0x00040000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "kernel",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "root",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHANNON
+static struct mtd_partition shannon_partitions[] = {
+ {
+ .name = "BLOB boot loader",
+ .offset = 0,
+ .size = 0x20000
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 0xe0000
+ },
+ {
+ .name = "initrd",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL
+ }
+};
+
+#endif
+
+#ifdef CONFIG_SA1100_SHERMAN
+static struct mtd_partition sherman_partitions[] = {
+ {
+ .size = 0x50000,
+ .offset = 0,
+ }, {
+ .size = 0x70000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .size = 0x600000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .size = 0xA0000,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+#endif
-/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
-static struct mtd_partition frodo_partitions[] =
+#ifdef CONFIG_SA1100_SIMPAD
+static struct mtd_partition simpad_partitions[] = {
{
+ .name = "SIMpad boot firmware",
+ .size = 0x00080000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "SIMpad kernel",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+#ifdef CONFIG_ROOT_CRAMFS
+ .name = "SIMpad root cramfs",
+ .size =0x00D80000,
+ .offset = MTDPART_OFS_APPEND
+
+ }, {
+ .name = "SIMpad local jffs2",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND
+#else
+ .name = "SIMpad root jffs2",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND
+#endif
+ }
+};
+#endif /* CONFIG_SA1100_SIMPAD */
+
+#ifdef CONFIG_SA1100_STORK
+static struct mtd_partition stork_partitions[] = {
{
- .name = "bootloader",
+ .name = "STORK boot firmware",
.size = 0x00040000,
- .offset = 0x00000000,
- .mask_flags = MTD_WRITEABLE
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
- .name = "bootloader params",
+ .name = "STORK params",
.size = 0x00040000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
+ .offset = 0x00040000,
}, {
- .name = "kernel",
+ .name = "STORK kernel",
.size = 0x00100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
+ .offset = 0x00080000,
}, {
- .name = "ramdisk",
- .size = 0x00400000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
+#ifdef CONFIG_JFFS2_FS
+ .name = "STORK root jffs2",
+ .offset = 0x00180000,
+ .size = MTDPART_SIZ_FULL,
+#else
+ .name = "STORK initrd",
+ .size = 0x00100000,
+ .offset = 0x00180000,
}, {
- .name = "file system",
+ .name = "STORK root cramfs",
+ .size = 0x00300000,
+ .offset = 0x00280000,
+ }, {
+ .name = "STORK usr cramfs",
+ .size = 0x00800000,
+ .offset = 0x00580000,
+ }, {
+ .name = "STORK usr local",
+ .offset = 0x00d80000,
.size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND
+#endif
}
};
+#endif
-static struct mtd_partition jornada56x_partitions[] = {
+#ifdef CONFIG_SA1100_TRIZEPS
+static struct mtd_partition trizeps_partitions[] = {
{
- .name = "bootldr",
- .size = 0x00040000,
+ .name = "Bootloader",
+ .size = 0x00100000,
.offset = 0,
- .mask_flags = MTD_WRITEABLE,
}, {
- .name = "rootfs",
+ .name = "Kernel",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "root",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
+#endif
-static void jornada56x_set_vpp(int vpp)
+#ifdef CONFIG_SA1100_YOPY
+static struct mtd_partition yopy_partitions[] = {
{
- if (vpp)
- GPSR = GPIO_GPIO26;
- else
- GPCR = GPIO_GPIO26;
- GPDR |= GPIO_GPIO26;
+ .name = "boot firmware",
+ .size = 0x00040000,
+ .offset = 0x00000000,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "kernel",
+ .size = 0x00080000,
+ .offset = 0x00080000,
+ }, {
+ .name = "initrd",
+ .size = 0x00300000,
+ .offset = 0x00100000,
+ }, {
+ .name = "root",
+ .size = 0x01000000,
+ .offset = 0x00400000,
}
+};
+#endif
-/*
- * Machine Phys Size set_vpp
- * Consus : SA1100_CS0_PHYS SZ_32M
- * Frodo : SA1100_CS0_PHYS SZ_32M
- * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
- */
+static int __init sa1100_static_partitions(struct mtd_partition **parts)
+{
+ int nb_parts = 0;
+
+#ifdef CONFIG_SA1100_ADSBITSY
+ if (machine_is_adsbitsy()) {
+ *parts = adsbitsy_partitions;
+ nb_parts = ARRAY_SIZE(adsbitsy_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_ASSABET
+ if (machine_is_assabet()) {
+ *parts = assabet_partitions;
+ nb_parts = ARRAY_SIZE(assabet_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+ if (machine_is_badge4()) {
+ *parts = badge4_partitions;
+ nb_parts = ARRAY_SIZE(badge4_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf()) {
+ *parts = cerf_partitions;
+ nb_parts = ARRAY_SIZE(cerf_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_CONSUS
+ if (machine_is_consus()) {
+ *parts = consus_partitions;
+ nb_parts = ARRAY_SIZE(consus_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+ if (machine_is_flexanet()) {
+ *parts = flexanet_partitions;
+ nb_parts = ARRAY_SIZE(flexanet_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+ if (machine_is_freebird()) {
+ *parts = freebird_partitions;
+ nb_parts = ARRAY_SIZE(freebird_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_FRODO
+ if (machine_is_frodo()) {
+ *parts = frodo_partitions;
+ nb_parts = ARRAY_SIZE(frodo_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+ if (machine_is_graphicsclient()) {
+ *parts = graphicsclient_partitions;
+ nb_parts = ARRAY_SIZE(graphicsclient_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+ if (machine_is_graphicsmaster()) {
+ *parts = graphicsmaster_partitions;
+ nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_H3XXX
+ if (machine_is_h3xxx()) {
+ *parts = h3xxx_partitions;
+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_HACKKIT
+ if (machine_is_hackkit()) {
+ *parts = hackkit_partitions;
+ nb_parts = ARRAY_SIZE(hackkit_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ if (machine_is_huw_webpanel()) {
+ *parts = huw_webpanel_partitions;
+ nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_JORNADA56X
+ if (machine_is_jornada56x()) {
+ *parts = jornada56x_partitions;
+ nb_parts = ARRAY_SIZE(jornada56x_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+ if (machine_is_jornada720()) {
+ *parts = jornada720_partitions;
+ nb_parts = ARRAY_SIZE(jornada720_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+ if (machine_is_pangolin()) {
+ *parts = pangolin_partitions;
+ nb_parts = ARRAY_SIZE(pangolin_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+ if (machine_is_pt_system3()) {
+ *parts = system3_partitions;
+ nb_parts = ARRAY_SIZE(system3_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+ if (machine_is_shannon()) {
+ *parts = shannon_partitions;
+ nb_parts = ARRAY_SIZE(shannon_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_SHERMAN
+ if (machine_is_sherman()) {
+ *parts = sherman_partitions;
+ nb_parts = ARRAY_SIZE(sherman_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_SIMPAD
+ if (machine_is_simpad()) {
+ *parts = simpad_partitions;
+ nb_parts = ARRAY_SIZE(simpad_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_STORK
+ if (machine_is_stork()) {
+ *parts = stork_partitions;
+ nb_parts = ARRAY_SIZE(stork_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_TRIZEPS
+ if (machine_is_trizeps()) {
+ *parts = trizeps_partitions;
+ nb_parts = ARRAY_SIZE(trizeps_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_YOPY
+ if (machine_is_yopy()) {
+ *parts = yopy_partitions;
+ nb_parts = ARRAY_SIZE(yopy_partitions);
+ }
#endif
-struct sa_subdev_info {
- char name[16];
- struct map_info map;
- struct mtd_info *mtd;
- struct flash_platform_data *data;
-};
+ return nb_parts;
+}
+#endif
struct sa_info {
- struct mtd_partition *parts;
+ unsigned long base;
+ unsigned long size;
+ int width;
+ void (*set_vpp)(struct map_info *, int);
+ char name[16];
+ struct map_info *map;
struct mtd_info *mtd;
- int num_subdev;
- struct sa_subdev_info subdev[0];
};
-static void sa1100_set_vpp(struct map_info *map, int on)
-{
- struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
- subdev->data->set_vpp(on);
-}
+#define NR_SUBMTD 4
-static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
-{
- if (subdev->mtd)
- map_destroy(subdev->mtd);
- if (subdev->map.virt)
- iounmap(subdev->map.virt);
- release_mem_region(subdev->map.phys, subdev->map.size);
-}
+static struct sa_info info[NR_SUBMTD];
-static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
{
- unsigned long phys;
- unsigned int size;
- int ret;
-
- phys = res->start;
- size = res->end - phys + 1;
+ struct mtd_info *subdev[nr];
+ struct map_info *maps;
+ int i, found = 0, ret = 0;
/*
- * Retrieve the bankwidth from the MSC registers.
- * We currently only implement CS0 and CS1 here.
+ * Allocate the map_info structs in one go.
*/
- switch (phys) {
- default:
- printk(KERN_WARNING "SA1100 flash: unknown base address "
- "0x%08lx, assuming CS0\n", phys);
+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
- case SA1100_CS0_PHYS:
- subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
- break;
+ memset(maps, 0, sizeof(struct map_info) * nr);
- case SA1100_CS1_PHYS:
- subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+ /*
+ * Claim and then map the memory regions.
+ */
+ for (i = 0; i < nr; i++) {
+ if (sa[i].base == (unsigned long)-1)
break;
- }
- if (!request_mem_region(phys, size, subdev->name)) {
+ sa[i].map = maps + i;
+ sa[i].map->name = sa[i].name;
+ sprintf(sa[i].name, "sa1100-%d", i);
+
+ if (!request_mem_region(sa[i].base, sa[i].size, sa[i].name)) {
+ i -= 1;
ret = -EBUSY;
- goto out;
+ break;
}
- if (subdev->data->set_vpp)
- subdev->map.set_vpp = sa1100_set_vpp;
-
- subdev->map.phys = phys;
- subdev->map.size = size;
- subdev->map.virt = ioremap(phys, size);
- if (!subdev->map.virt) {
+ sa[i].map->virt = ioremap(sa[i].base, sa[i].size);
+ if (!sa[i].map->virt) {
ret = -ENOMEM;
- goto err;
+ break;
}
- simple_map_init(&subdev->map);
+ sa[i].map->phys = sa[i].base;
+ sa[i].map->set_vpp = sa[i].set_vpp;
+ sa[i].map->bankwidth = sa[i].width;
+ sa[i].map->size = sa[i].size;
+
+ simple_map_init(sa[i].map);
/*
* Now let's probe for the actual flash. Do it here since
* specific machine settings might have been set above.
*/
- subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map);
- if (subdev->mtd == NULL) {
+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
+ if (sa[i].mtd == NULL) {
ret = -ENXIO;
- goto err;
+ break;
}
- subdev->mtd->owner = THIS_MODULE;
+ sa[i].mtd->owner = THIS_MODULE;
+ subdev[i] = sa[i].mtd;
printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
- "%d-bit\n", phys, subdev->mtd->size >> 20,
- subdev->map.bankwidth * 8);
+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
+ sa[i].width * 8);
+ found += 1;
+ }
+
+ /*
+ * ENXIO is special. It means we didn't find a chip when
+ * we probed. We need to tear down the mapping, free the
+ * resource and mark it as such.
+ */
+ if (ret == -ENXIO) {
+ iounmap(sa[i].map->virt);
+ sa[i].map->virt = NULL;
+ release_mem_region(sa[i].base, sa[i].size);
+ }
+
+ /*
+ * If we found one device, don't bother with concat support.
+ * If we found multiple devices, use concat if we have it
+ * available, otherwise fail.
+ */
+ if (ret == 0 || ret == -ENXIO) {
+ if (found == 1) {
+ *rmtd = subdev[0];
+ ret = 0;
+ } else if (found > 1) {
+ /*
+ * We detected multiple devices. Concatenate
+ * them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ *rmtd = mtd_concat_create(subdev, found,
+ "sa1100");
+ if (*rmtd == NULL)
+ ret = -ENXIO;
+#else
+ printk(KERN_ERR "SA1100 flash: multiple devices "
+ "found but MTD concat support disabled.\n");
+ ret = -ENXIO;
+#endif
+ }
+ }
+
+ /*
+ * If we failed, clean up.
+ */
+ if (ret) {
+ do {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].map->virt)
+ iounmap(sa[i].map->virt);
+ release_mem_region(sa[i].base, sa[i].size);
+ } while (i-- > 0);
- return 0;
+ kfree(maps);
+ }
- err:
- sa1100_destroy_subdev(subdev);
- out:
return ret;
}
-static void sa1100_destroy(struct sa_info *info)
+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
{
int i;
- if (info->mtd) {
- del_mtd_partitions(info->mtd);
+ del_mtd_partitions(mtd);
#ifdef CONFIG_MTD_CONCAT
- if (info->mtd != info->subdev[0].mtd)
- mtd_concat_destroy(info->mtd);
+ if (mtd != sa[0].mtd)
+ mtd_concat_destroy(mtd);
#endif
- }
- if (info->parts)
- kfree(info->parts);
-
- for (i = info->num_subdev - 1; i >= 0; i--)
- sa1100_destroy_subdev(&info->subdev[i]);
- kfree(info);
+ for (i = NR_SUBMTD; i >= 0; i--) {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].map->virt)
+ iounmap(sa[i].map->virt);
+ release_mem_region(sa[i].base, sa[i].size);
+ }
+ kfree(sa[0].map);
}
-
-static struct sa_info *__init
-sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash)
-{
- struct sa_info *info;
- int nr, size, i, ret = 0;
/*
- * Count number of devices.
+ * A Thought: can we automatically detect the flash?
+ * - Check to see if the region is busy (yes -> failure)
+ * - Is the MSC setup for flash (no -> failure)
+ * - Probe for flash
*/
- for (nr = 0; ; nr++)
- if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
- break;
+static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
+{
+ struct map_info map;
+ struct mtd_info *mtd;
- if (nr == 0) {
- ret = -ENODEV;
- goto out;
- }
+ printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
+ phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
- size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
+ if (check_mem_region(phys, 0x08000000)) {
+ printk("busy\n");
+ return;
+ }
- /*
- * Allocate the map_info structs in one go.
- */
- info = kmalloc(size, GFP_KERNEL);
- if (!info) {
- ret = -ENOMEM;
- goto out;
+ if ((msc & 3) == 1) {
+ printk("wrong type\n");
+ return;
}
- memset(info, 0, size);
+ memset(&map, 0, sizeof(struct map_info));
- /*
- * Claim and then map the memory regions.
- */
- for (i = 0; i < nr; i++) {
- struct sa_subdev_info *subdev = &info->subdev[i];
- struct resource *res;
+ map.name = "Probe";
+ map.bankwidth = msc & MSC_RBW ? 2 : 4;
+ map.size = SZ_1M;
+ map.phys = phys;
+ map.virt = ioremap(phys, SZ_1M);
+ if (map.virt == NULL)
+ goto fail;
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res)
- break;
+ simple_map_init(&map);
- subdev->map.name = subdev->name;
- sprintf(subdev->name, "sa1100-%d", i);
- subdev->data = flash;
+ /* Shame cfi_probe blurts out kernel messages... */
+ mtd = do_map_probe("cfi_probe", &map);
+ if (mtd)
+ map_destroy(mtd);
+ iounmap(map.virt);
- ret = sa1100_probe_subdev(subdev, res);
- if (ret)
- break;
+ if (!mtd)
+ goto fail;
+
+ printk("pass\n");
+ return;
+
+ fail:
+ printk("failed\n");
+}
+
+static void __init sa1100_probe_flash(void)
+{
+ printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n");
+ sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
+ sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
+ sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
+ sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
+ sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
+ sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
+ printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
}
- info->num_subdev = i;
+static int __init sa1100_locate_flash(void)
+{
+ int i, nr = -ENODEV;
- /*
- * ENXIO is special. It means we didn't find a chip when we probed.
- */
- if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
- goto err;
+ sa1100_probe_flash();
+
+ if (machine_is_adsbitsy()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_assabet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ info[1].base = SA1100_CS1_PHYS; /* neponset */
+ info[1].size = SZ_32M;
+ nr = 2;
+ }
+ if (machine_is_badge4()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ nr = 1;
+ }
+ if (machine_is_cerf()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_consus()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_flexanet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_freebird()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_frodo()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsclient()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsmaster()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_h3xxx()) {
+ info[0].set_vpp = h3xxx_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_huw_webpanel()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_itsy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_jornada56x()) {
+ info[0].set_vpp = jornada56x_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_jornada720()) {
+ info[0].set_vpp = jornada720_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_nanoengine()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[1].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pangolin()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ nr = 1;
+ }
+ if (machine_is_pfs168()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pleb()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_4M;
+ nr = 2;
+ }
+ if (machine_is_pt_system3()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_shannon()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ nr = 1;
+ }
+ if (machine_is_sherman()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_simpad()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_16M;
+ nr = 2;
+ }
+ if (machine_is_stork()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_trizeps()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_victor()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_2M;
+ nr = 1;
+ }
+ if (machine_is_yopy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_64M;
+ nr = 2;
+ }
+
+ if (nr < 0)
+ return nr;
/*
- * If we found one device, don't bother with concat support. If
- * we found multiple devices, use concat if we have it available,
- * otherwise fail. Either way, it'll be called "sa1100".
- */
- if (info->num_subdev == 1) {
- strcpy(info->subdev[0].name, "sa1100");
- info->mtd = info->subdev[0].mtd;
- ret = 0;
- } else if (info->num_subdev > 1) {
-#ifdef CONFIG_MTD_CONCAT
- struct mtd_info *cdev[nr];
- /*
- * We detected multiple devices. Concatenate them together.
+ * Retrieve the bankwidth from the MSC registers.
+ * We currently only implement CS0 and CS1 here.
*/
- for (i = 0; i < info->num_subdev; i++)
- cdev[i] = info->subdev[i].mtd;
+ for (i = 0; i < nr; i++) {
+ switch (info[i].base) {
+ default:
+ printk(KERN_WARNING "SA1100 flash: unknown base address "
+ "0x%08lx, assuming CS0\n", info[i].base);
+ case SA1100_CS0_PHYS:
+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
+ break;
- info->mtd = mtd_concat_create(cdev, info->num_subdev,
- "sa1100");
- if (info->mtd == NULL)
- ret = -ENXIO;
-#else
- printk(KERN_ERR "SA1100 flash: multiple devices "
- "found but MTD concat support disabled.\n");
- ret = -ENXIO;
-#endif
+ case SA1100_CS1_PHYS:
+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+ break;
+ }
}
- if (ret == 0)
- return info;
-
- err:
- sa1100_destroy(info);
- out:
- return ERR_PTR(ret);
+ return nr;
}
-static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
+static struct mtd_partition *parsed_parts;
+const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-static int __init sa1100_mtd_probe(struct device *dev)
+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct flash_platform_data *flash = pdev->dev.platform_data;
- struct mtd_partition *parts;
const char *part_type = NULL;
- struct sa_info *info;
- int err, nr_parts = 0;
-
- if (!flash)
- return -ENODEV;
-
- info = sa1100_setup_mtd(pdev, flash);
- if (IS_ERR(info)) {
- err = PTR_ERR(info);
- goto out;
- }
+ int nr_parts = 0;
+ do {
/*
* Partition selection stuff.
*/
#ifdef CONFIG_MTD_PARTITIONS
- nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
+ nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
if (nr_parts > 0) {
- info->parts = parts;
part_type = "dynamic";
- } else
+ break;
+ }
#endif
- {
- parts = flash->parts;
- nr_parts = flash->nr_parts;
+#ifdef CONFIG_MTD_SA1100_STATICMAP
+ nr_parts = sa1100_static_partitions(&parsed_parts);
+ if (nr_parts > 0) {
part_type = "static";
+ break;
}
+#endif
+ } while (0);
if (nr_parts == 0) {
printk(KERN_NOTICE "SA1100 flash: no partition info "
"available, registering whole flash\n");
- add_mtd_device(info->mtd);
+ add_mtd_device(mtd);
} else {
printk(KERN_NOTICE "SA1100 flash: using %s partition "
"definition\n", part_type);
- add_mtd_partitions(info->mtd, parts, nr_parts);
+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
}
- dev_set_drvdata(dev, info);
- err = 0;
-
- out:
- return err;
+ /* Always succeeds. */
}
-static int __exit sa1100_mtd_remove(struct device *dev)
+static void __exit sa1100_destroy_partitions(void)
{
- struct sa_info *info = dev_get_drvdata(dev);
- dev_set_drvdata(dev, NULL);
- sa1100_destroy(info);
- return 0;
+ if (parsed_parts)
+ kfree(parsed_parts);
}
-#ifdef CONFIG_PM
-static int sa1100_mtd_suspend(struct device *dev, u32 state, u32 level)
-{
- struct sa_info *info = dev_get_drvdata(dev);
- int ret = 0;
-
- if (info && level == SUSPEND_SAVE_STATE)
- ret = info->mtd->suspend(info->mtd);
-
- return ret;
-}
+static struct mtd_info *mymtd;
-static int sa1100_mtd_resume(struct device *dev, u32 level)
+static int __init sa1100_mtd_init(void)
{
- struct sa_info *info = dev_get_drvdata(dev);
- if (info && level == RESUME_RESTORE_STATE)
- info->mtd->resume(info->mtd);
- return 0;
-}
-#else
-#define sa1100_mtd_suspend NULL
-#define sa1100_mtd_resume NULL
-#endif
+ int ret;
+ int nr;
-static struct device_driver sa1100_mtd_driver = {
- .name = "flash",
- .bus = &platform_bus_type,
- .probe = sa1100_mtd_probe,
- .remove = __exit_p(sa1100_mtd_remove),
- .suspend = sa1100_mtd_suspend,
- .resume = sa1100_mtd_resume,
-};
+ nr = sa1100_locate_flash();
+ if (nr < 0)
+ return nr;
-static int __init sa1100_mtd_init(void)
-{
- return driver_register(&sa1100_mtd_driver);
+ ret = sa1100_setup_mtd(info, nr, &mymtd);
+ if (ret == 0)
+ sa1100_locate_partitions(mymtd);
+
+ return ret;
}
-static void __exit sa1100_mtd_exit(void)
+static void __exit sa1100_mtd_cleanup(void)
{
- driver_unregister(&sa1100_mtd_driver);
+ sa1100_destroy_mtd(info, mymtd);
+ sa1100_destroy_partitions();
}
module_init(sa1100_mtd_init);
-module_exit(sa1100_mtd_exit);
+module_exit(sa1100_mtd_cleanup);
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("SA1100 CFI map driver");
diff -wur linux-2.6.10/drivers/mtd/maps/sbc_gxx.c linux-2.6.10-lab/drivers/mtd/maps/sbc_gxx.c
--- linux-2.6.10/drivers/mtd/maps/sbc_gxx.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/sbc_gxx.c 2007-10-04 19:10:17.000000000 -0400
@@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- $Id: sbc_gxx.c,v 1.32 2004/11/16 18:29:02 dwmw2 Exp $
+ $Id: sbc_gxx.c,v 1.34 2005/01/12 22:34:35 gleixner Exp $
The SBC-MediaGX / SBC-GXx has up to 16 MiB of
Intel StrataFlash (28F320/28F640) in x8 mode.
@@ -85,7 +85,7 @@
static volatile int page_in_window = -1; // Current page in window.
static void __iomem *iomapadr;
-static spinlock_t sbc_gxx_spin = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sbc_gxx_spin);
/* partition_info gives details on the logical partitions that the split the
* single flash device into. If the size if zero we use up to the end of the
diff -wur linux-2.6.10/drivers/mtd/maps/sc520cdp.c linux-2.6.10-lab/drivers/mtd/maps/sc520cdp.c
--- linux-2.6.10/drivers/mtd/maps/sc520cdp.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/sc520cdp.c 2007-10-04 19:10:17.000000000 -0400
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: sc520cdp.c,v 1.18 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $
*
*
* The SC520CDP is an evaluation board for the Elan SC520 processor available
diff -wur linux-2.6.10/drivers/mtd/maps/scb2_flash.c linux-2.6.10-lab/drivers/mtd/maps/scb2_flash.c
--- linux-2.6.10/drivers/mtd/maps/scb2_flash.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/scb2_flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,6 +1,6 @@
/*
* MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.10 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
* Copyright (C) 2002 Sun Microsystems, Inc.
* Tim Hockin
*
diff -wur linux-2.6.10/drivers/mtd/maps/scx200_docflash.c linux-2.6.10-lab/drivers/mtd/maps/scx200_docflash.c
--- linux-2.6.10/drivers/mtd/maps/scx200_docflash.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/scx200_docflash.c 2007-10-04 19:10:17.000000000 -0400
@@ -2,7 +2,7 @@
Copyright (c) 2001,2002 Christer Weinigel
- $Id: scx200_docflash.c,v 1.9 2004/11/16 18:29:02 dwmw2 Exp $
+ $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $
National Semiconductor SCx200 flash mapped with DOCCS
*/
diff -wur linux-2.6.10/drivers/mtd/maps/ts5500_flash.c linux-2.6.10-lab/drivers/mtd/maps/ts5500_flash.c
--- linux-2.6.10/drivers/mtd/maps/ts5500_flash.c 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/ts5500_flash.c 2007-10-04 19:10:17.000000000 -0400
@@ -25,7 +25,7 @@
* - If you have created your own jffs file system and the bios overwrites
* it during boot, try disabling Drive A: and B: in the boot order.
*
- * $Id: ts5500_flash.c,v 1.1 2004/09/20 15:33:26 sean Exp $
+ * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $
*/
#include
diff -wur linux-2.6.10/drivers/mtd/maps/uclinux.c linux-2.6.10-lab/drivers/mtd/maps/uclinux.c
--- linux-2.6.10/drivers/mtd/maps/uclinux.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/uclinux.c 2007-10-04 19:10:17.000000000 -0400
@@ -5,7 +5,7 @@
*
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
*
- * $Id: uclinux.c,v 1.9 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $
*/
/****************************************************************************/
@@ -47,7 +47,7 @@
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf)
{
- struct map_info *map = (struct map_info *) mtd->priv;
+ struct map_info *map = mtd->priv;
*mtdbuf = (u_char *) (map->virt + ((int) from));
*retlen = len;
return(0);
@@ -81,7 +81,7 @@
mtd = do_map_probe("map_ram", mapp);
if (!mtd) {
printk("uclinux[mtd]: failed to find a mapping?\n");
- iounmap((void *) mapp->virt);
+ iounmap(mapp->virt);
return(-ENXIO);
}
diff -wur linux-2.6.10/drivers/mtd/maps/vmax301.c linux-2.6.10-lab/drivers/mtd/maps/vmax301.c
--- linux-2.6.10/drivers/mtd/maps/vmax301.c 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/maps/vmax301.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,4 +1,4 @@
-// $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $
+// $Id: vmax301.c,v 1.31 2005/01/12 22:34:35 gleixner Exp $
/* ######################################################################
Tempustech VMAX SBC301 MTD Driver.
@@ -38,7 +38,7 @@
the extra indirection from having one of the map->map_priv
fields pointing to yet another private struct.
*/
-static spinlock_t vmax301_spin = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(vmax301_spin);
static void __vmax301_page(struct map_info *map, unsigned long page)
{
diff -wur linux-2.6.10/drivers/mtd/mtdblock.c linux-2.6.10-lab/drivers/mtd/mtdblock.c
--- linux-2.6.10/drivers/mtd/mtdblock.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/mtdblock.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
/*
* Direct MTD block device access
*
- * $Id: mtdblock.c,v 1.65 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $
*
* (C) 2000-2003 Nicolas Pitre
* (C) 1999-2003 David Woodhouse
@@ -248,7 +248,7 @@
unsigned long block, char *buf)
{
struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
- if (unlikely(!mtdblk->cache_data)) {
+ if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
if (!mtdblk->cache_data)
return -EINTR;
diff -wur linux-2.6.10/drivers/mtd/mtdchar.c linux-2.6.10-lab/drivers/mtd/mtdchar.c
--- linux-2.6.10/drivers/mtd/mtdchar.c 2004-12-24 16:35:18.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/mtdchar.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: mtdchar.c,v 1.65 2004/09/23 23:45:47 gleixner Exp $
+ * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $
*
* Character-device access to raw MTD devices.
*
@@ -61,7 +61,7 @@
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
{
- struct mtd_info *mtd=(struct mtd_info *)file->private_data;
+ struct mtd_info *mtd = file->private_data;
switch (orig) {
case 0:
@@ -134,7 +134,7 @@
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- mtd = (struct mtd_info *)file->private_data;
+ mtd = file->private_data;
if (mtd->sync)
mtd->sync(mtd);
@@ -151,7 +151,7 @@
static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ struct mtd_info *mtd = file->private_data;
size_t retlen=0;
size_t total_retlen=0;
int ret=0;
@@ -210,7 +210,7 @@
static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ struct mtd_info *mtd = file->private_data;
char *kbuf;
size_t retlen;
size_t total_retlen=0;
@@ -276,7 +276,7 @@
static int mtd_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
- struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ struct mtd_info *mtd = file->private_data;
void __user *argp = (void __user *)arg;
int ret = 0;
u_long size;
diff -wur linux-2.6.10/drivers/mtd/mtdpart.c linux-2.6.10-lab/drivers/mtd/mtdpart.c
--- linux-2.6.10/drivers/mtd/mtdpart.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/mtdpart.c 2007-10-04 19:10:17.000000000 -0400
@@ -5,7 +5,7 @@
*
* This code is GPL
*
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.52 2005/01/12 22:34:33 gleixner Exp $
*
* 02-21-2002 Thomas Gleixner
* added support for read_oob, write_oob
@@ -523,7 +523,7 @@
EXPORT_SYMBOL(add_mtd_partitions);
EXPORT_SYMBOL(del_mtd_partitions);
-static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);
static struct mtd_part_parser *get_partition_parser(const char *name)
diff -wur linux-2.6.10/drivers/mtd/nand/Kconfig linux-2.6.10-lab/drivers/mtd/nand/Kconfig
--- linux-2.6.10/drivers/mtd/nand/Kconfig 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
# drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.22 2004/10/05 22:11:46 gleixner Exp $
+# $Id: Kconfig,v 1.26 2005/01/05 12:42:24 dwmw2 Exp $
menu "NAND Flash Device Drivers"
depends on MTD!=n
@@ -7,6 +7,7 @@
config MTD_NAND
tristate "NAND Device Support"
depends on MTD
+ select MTD_NAND_IDS
help
This enables support for accessing all type of NAND flash
devices. For further information see
@@ -56,8 +57,6 @@
config MTD_NAND_IDS
tristate
- default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
- default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
config MTD_NAND_TX4925NDFMC
tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
@@ -192,4 +191,17 @@
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
+
+ config MTD_NAND_SHARPSL
+ bool "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+ depends on MTD_NAND && ARCH_PXA
+
+ config MTD_NAND_NANDSIM
+ bool "Support for NAND Flash Simulator"
+ depends on MTD_NAND && MTD_PARTITIONS
+
+ help
+ The simulator may simulate verious NAND flash chips for the
+ MTD nand layer.
+
endmenu
diff -wur linux-2.6.10/drivers/mtd/nand/Makefile linux-2.6.10-lab/drivers/mtd/nand/Makefile
--- linux-2.6.10/drivers/mtd/nand/Makefile 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/Makefile 2007-10-04 19:10:17.000000000 -0400
@@ -1,7 +1,7 @@
#
# linux/drivers/nand/Makefile
#
-# $Id: Makefile.common,v 1.13 2004/09/28 22:04:23 bjd Exp $
+# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
@@ -18,5 +18,7 @@
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
+obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
+obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
nand-objs = nand_base.o nand_bbt.o
diff -wur linux-2.6.10/drivers/mtd/nand/diskonchip.c linux-2.6.10-lab/drivers/mtd/nand/diskonchip.c
--- linux-2.6.10/drivers/mtd/nand/diskonchip.c 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/diskonchip.c 2007-10-04 19:10:17.000000000 -0400
@@ -16,7 +16,7 @@
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
*
- * $Id: diskonchip.c,v 1.42 2004/11/16 18:29:03 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.48 2005/01/31 22:22:21 gleixner Exp $
*/
#include
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -34,13 +35,13 @@
#include
/* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
#endif
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
@@ -122,7 +123,7 @@
#endif
module_param(inftl_bbt_write, int, 0);
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
@@ -308,7 +309,7 @@
static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
if(debug)printk("write_byte %02x\n", datum);
@@ -319,7 +320,7 @@
static u_char doc2000_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -334,7 +335,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
if (debug)printk("writebuf of %d bytes: ", len);
@@ -350,7 +351,7 @@
u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -365,7 +366,7 @@
u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -386,7 +387,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -399,7 +400,7 @@
static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
uint16_t ret;
doc200x_select_chip(mtd, nr);
@@ -441,7 +442,7 @@
static void __init doc2000_count_chips(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
uint16_t mfrid;
int i;
@@ -462,7 +463,7 @@
static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
{
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
int status;
@@ -477,7 +478,7 @@
static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
WriteDOC(datum, docptr, CDSNSlowIO);
@@ -488,7 +489,7 @@
static u_char doc2001_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
//ReadDOC(docptr, CDSNSlowIO);
@@ -503,7 +504,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -517,7 +518,7 @@
u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -535,7 +536,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -555,7 +556,7 @@
static u_char doc2001plus_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
u_char ret;
@@ -570,7 +571,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -587,7 +588,7 @@
u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -617,7 +618,7 @@
const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
@@ -643,7 +644,7 @@
static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -669,7 +670,7 @@
static void doc200x_select_chip(struct mtd_info *mtd, int chip)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int floor = 0;
@@ -696,7 +697,7 @@
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
switch(cmd) {
@@ -734,7 +735,7 @@
static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
/*
@@ -838,7 +839,7 @@
static int doc200x_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
if (DoC_is_MillenniumPlus(doc)) {
@@ -876,7 +877,7 @@
static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -895,7 +896,7 @@
static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
/* Prime the ECC engine */
@@ -916,7 +917,7 @@
unsigned char *ecc_code)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
int i;
int emptymatch = 1;
@@ -974,7 +975,7 @@
{
int i, ret = 0;
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr;
volatile u_char dummy;
int emptymatch = 1;
@@ -1062,7 +1063,7 @@
const char *id, int findmirror)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
int ret;
size_t retlen;
@@ -1105,7 +1106,7 @@
struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
int ret = 0;
u_char *buf;
struct NFTLMediaHeader *mh;
@@ -1121,8 +1122,10 @@
if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
mh = (struct NFTLMediaHeader *) buf;
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+ mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+ mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+ mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
printk(KERN_INFO " DataOrgID = %s\n"
" NumEraseUnits = %d\n"
" FirstPhysicalEUN = %d\n"
@@ -1131,7 +1134,6 @@
mh->DataOrgID, mh->NumEraseUnits,
mh->FirstPhysicalEUN, mh->FormattedSize,
mh->UnitSizeFactor);
-//#endif
blocks = mtd->size >> this->phys_erase_shift;
maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1174,10 +1176,6 @@
offs <<= this->page_shift;
offs += mtd->erasesize;
- //parts[0].name = " DiskOnChip Boot / Media Header partition";
- //parts[0].offset = 0;
- //parts[0].size = offs;
-
parts[0].name = " DiskOnChip BDTL partition";
parts[0].offset = offs;
parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
@@ -1201,7 +1199,7 @@
struct mtd_partition *parts)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
int ret = 0;
u_char *buf;
struct INFTLMediaHeader *mh;
@@ -1232,8 +1230,6 @@
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
" NoOfBinaryPartitions = %d\n"
@@ -1251,7 +1247,6 @@
((unsigned char *) &mh->OsakVersion)[2] & 0xf,
((unsigned char *) &mh->OsakVersion)[3] & 0xf,
mh->PercentUsed);
-//#endif
vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
@@ -1277,8 +1272,6 @@
ip->spareUnits = le32_to_cpu(ip->spareUnits);
ip->Reserved0 = le32_to_cpu(ip->Reserved0);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " PARTITION[%d] ->\n"
" virtualUnits = %d\n"
" firstUnit = %d\n"
@@ -1288,16 +1281,15 @@
i, ip->virtualUnits, ip->firstUnit,
ip->lastUnit, ip->flags,
ip->spareUnits);
-//#endif
-/*
+#if 0
if ((i == 0) && (ip->firstUnit > 0)) {
parts[0].name = " DiskOnChip IPL / Media Header partition";
parts[0].offset = 0;
parts[0].size = mtd->erasesize * ip->firstUnit;
numparts = 1;
}
-*/
+#endif
if (ip->flags & INFTL_BINARY)
parts[numparts].name = " DiskOnChip BDK partition";
@@ -1326,7 +1318,7 @@
{
int ret, numparts;
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
struct mtd_partition parts[2];
memset((char *) parts, 0, sizeof(parts));
@@ -1365,7 +1357,7 @@
{
int ret, numparts;
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
struct mtd_partition parts[5];
if (this->numchips > doc->chips_per_floor) {
@@ -1424,7 +1416,7 @@
static inline int __init doc2000_init(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
this->write_byte = doc2000_write_byte;
this->read_byte = doc2000_read_byte;
@@ -1442,7 +1434,7 @@
static inline int __init doc2001_init(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
this->write_byte = doc2001_write_byte;
this->read_byte = doc2001_read_byte;
@@ -1474,7 +1466,7 @@
static inline int __init doc2001plus_init(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
- struct doc_priv *doc = (void *)this->priv;
+ struct doc_priv *doc = this->priv;
this->write_byte = NULL;
this->read_byte = doc2001plus_read_byte;
@@ -1596,7 +1588,7 @@
unsigned char oldval;
unsigned char newval;
nand = mtd->priv;
- doc = (void *)nand->priv;
+ doc = nand->priv;
/* Use the alias resolution register to determine if this is
in fact the same DOC aliased to a new address. If writes
to one chip's alias resolution register change the value on
@@ -1645,10 +1637,10 @@
nand->bbt_td = (struct nand_bbt_descr *) (doc + 1);
nand->bbt_md = nand->bbt_td + 1;
- mtd->priv = (void *) nand;
+ mtd->priv = nand;
mtd->owner = THIS_MODULE;
- nand->priv = (void *) doc;
+ nand->priv = doc;
nand->select_chip = doc200x_select_chip;
nand->hwcontrol = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready;
@@ -1699,7 +1691,7 @@
actually a DiskOnChip. */
WriteDOC(save_control, virtadr, DOCControl);
fail:
- iounmap((void *)virtadr);
+ iounmap(virtadr);
return ret;
}
@@ -1711,11 +1703,11 @@
for (mtd = doclist; mtd; mtd = nextmtd) {
nand = mtd->priv;
- doc = (void *)nand->priv;
+ doc = nand->priv;
nextmtd = doc->nextdoc;
nand_release(mtd);
- iounmap((void *)doc->virtadr);
+ iounmap(doc->virtadr);
kfree(mtd);
}
}
diff -wur linux-2.6.10/drivers/mtd/nand/nand_base.c linux-2.6.10-lab/drivers/mtd/nand/nand_base.c
--- linux-2.6.10/drivers/mtd/nand/nand_base.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/nand_base.c 2007-10-04 19:10:17.000000000 -0400
@@ -28,6 +28,24 @@
* among multiple independend devices. Suggestions and initial patch
* from Ben Dooks
*
+ * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ * Basically, any block not rewritten may lose data when surrounding blocks
+ * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
+ * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
+ * do not lose data, force them to be rewritten when some of the surrounding
+ * blocks are erased. Rather than tracking a specific nearby block (which
+ * could itself go bad), use a page address 'mask' to select several blocks
+ * in the same area, and rewrite the BBT when any of them are erased.
+ *
+ * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
+ * AG-AND chips. If there was a sudden loss of power during an erase operation,
+ * a "device recovery" operation must be performed when power is restored
+ * to ensure correct operation.
+ *
+ * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
+ * perform extra error status checks on erase and write failures. This required
+ * adding a wrapper function for nand_read_ecc.
+ *
* Credits:
* David Woodhouse for adding multichip support
*
@@ -41,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
- * $Id: nand_base.c,v 1.121 2004/10/06 19:53:11 gleixner Exp $
+ * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
*
* 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
@@ -466,7 +484,7 @@
struct nand_chip *this = mtd->priv;
/* Check the WP bit */
this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- return (this->read_byte(mtd) & 0x80) ? 0 : 1;
+ return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
/**
@@ -571,7 +589,7 @@
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
/* This applies to read commands */
@@ -619,7 +637,7 @@
/* Begin command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE);
/* Write out the command to the device. */
- this->write_byte(mtd, command);
+ this->write_byte(mtd, (command & 0xff));
/* End command latch cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -647,7 +665,7 @@
/*
* program and erase have their own busy handlers
- * status and sequential in needs no delay
+ * status, sequential in, and deplete1 need no delay
*/
switch (command) {
@@ -657,8 +675,19 @@
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
return;
+ /*
+ * read error status commands require only a short delay
+ */
+ case NAND_CMD_STATUS_ERROR:
+ case NAND_CMD_STATUS_ERROR0:
+ case NAND_CMD_STATUS_ERROR1:
+ case NAND_CMD_STATUS_ERROR2:
+ case NAND_CMD_STATUS_ERROR3:
+ udelay(this->chip_delay);
+ return;
case NAND_CMD_RESET:
if (this->dev_ready)
@@ -667,7 +696,7 @@
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
case NAND_CMD_READ0:
@@ -785,7 +814,7 @@
if (this->read_byte(mtd) & NAND_STATUS_READY)
break;
}
- yield ();
+ msleep(1);
}
status = (int) this->read_byte(mtd);
return status;
@@ -810,7 +839,7 @@
u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
{
int i, status;
- u_char ecc_code[8];
+ u_char ecc_code[32];
int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
int *oob_config = oobsel->eccpos;
int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
@@ -840,18 +869,8 @@
}
this->write_buf(mtd, this->data_poi, mtd->oobblock);
break;
-
- /* Hardware ecc 8 byte / 512 byte data */
- case NAND_ECC_HW8_512:
- eccbytes += 2;
- /* Hardware ecc 6 byte / 512 byte data */
- case NAND_ECC_HW6_512:
- eccbytes += 3;
- /* Hardware ecc 3 byte / 256 data */
- /* Hardware ecc 3 byte / 512 byte data */
- case NAND_ECC_HW3_256:
- case NAND_ECC_HW3_512:
- eccbytes += 3;
+ default:
+ eccbytes = this->eccbytes;
for (; eccsteps; eccsteps--) {
/* enable hardware ecc logic for write */
this->enable_hwecc(mtd, NAND_ECC_WRITE);
@@ -864,14 +883,9 @@
* the data bytes (words) */
if (this->options & NAND_HWECC_SYNDROME)
this->write_buf(mtd, ecc_code, eccbytes);
-
datidx += this->eccsize;
}
break;
-
- default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
}
/* Write out OOB data */
@@ -886,8 +900,14 @@
if (!cached) {
/* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING);
+
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_WRITING, status, page);
+ }
+
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
return -EIO;
}
@@ -1012,23 +1032,24 @@
#endif
/**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
*/
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
{
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
+ return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
}
/**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
@@ -1037,11 +1058,35 @@
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
*/
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
{
+ return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put data
+ * @oob_buf: filesystem supplied oob data buffer
+ * @oobsel: oob selection structure
+ * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
+ * and how many corrected error bits are acceptable:
+ * bits 0..7 - number of tolerable errors
+ * bit 8 - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags)
+{
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
struct nand_chip *this = mtd->priv;
@@ -1051,7 +1096,7 @@
int eccmode, eccsteps;
int *oob_config, datidx;
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
- int eccbytes = 3;
+ int eccbytes;
int compareecc = 1;
int oobreadlen;
@@ -1066,6 +1111,7 @@
}
/* Grab the lock and see if the device is available */
+ if (flags & NAND_GET_DEVICE)
nand_get_device (this, mtd ,FL_READING);
/* use userspace supplied oobinfo, if zero */
@@ -1092,19 +1138,9 @@
end = mtd->oobblock;
ecc = this->eccsize;
- switch (eccmode) {
- case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data */
- eccbytes = 6;
- break;
- case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data */
- eccbytes = 8;
- break;
- case NAND_ECC_NONE:
- compareecc = 0;
- break;
- }
+ eccbytes = this->eccbytes;
- if (this->options & NAND_HWECC_SYNDROME)
+ if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
compareecc = 0;
oobreadlen = mtd->oobsize;
@@ -1165,10 +1201,7 @@
this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
break;
- case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */
- case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */
- case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data */
- case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data */
+ default:
for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
this->enable_hwecc(mtd, NAND_ECC_READ);
this->read_buf(mtd, &data_poi[datidx], ecc);
@@ -1183,7 +1216,8 @@
/* We calc error correction directly, it checks the hw
* generator for an error, reads back the syndrome and
* does the error correction on the fly */
- if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
ecc_failed++;
@@ -1193,10 +1227,6 @@
}
}
break;
-
- default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
}
/* read oobdata */
@@ -1226,7 +1256,7 @@
p[i] = ecc_status;
}
- if (ecc_status == -1) {
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
ecc_failed++;
}
@@ -1296,6 +1326,7 @@
}
/* Deselect and wake up anyone waiting on the device */
+ if (flags & NAND_GET_DEVICE)
nand_release_device(mtd);
/*
@@ -1765,7 +1796,7 @@
status = this->waitfunc (mtd, this, FL_WRITING);
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
ret = -EIO;
goto out;
@@ -2019,6 +2050,7 @@
return nand_erase_nand (mtd, instr, 0);
}
+#define BBT_PAGE_MASK 0xffffff3f
/**
* nand_erase_intern - [NAND Interface] erase block(s)
* @mtd: MTD device structure
@@ -2031,6 +2063,10 @@
{
int page, len, status, pages_per_block, ret, chipnr;
struct nand_chip *this = mtd->priv;
+ int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
+ unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
+ /* It is used to see if the current page is in the same */
+ /* 256 block group and the same bank as the bbt. */
DEBUG (MTD_DEBUG_LEVEL3,
"nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2076,6 +2112,13 @@
goto erase_exit;
}
+ /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+ if (this->options & BBT_AUTO_REFRESH) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ } else {
+ bbt_masked_page = 0xffffffff; /* should not match anything */
+ }
+
/* Loop through the pages */
len = instr->len;
@@ -2098,14 +2141,27 @@
status = this->waitfunc (mtd, this, FL_ERASING);
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_ERASING, status, page);
+ }
+
/* See if block erase succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = (page << this->page_shift);
goto erase_exit;
}
+ /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+ if (this->options & BBT_AUTO_REFRESH) {
+ if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
+ (page != this->bbt_td->pages[chipnr])) {
+ rewrite_bbt[chipnr] = (page << this->page_shift);
+ }
+ }
+
/* Increment page address and decrement length */
len -= (1 << this->phys_erase_shift);
page += pages_per_block;
@@ -2115,6 +2171,13 @@
chipnr++;
this->select_chip(mtd, -1);
this->select_chip(mtd, chipnr);
+
+ /* if BBT requires refresh and BBT-PERCHIP,
+ * set the BBT page mask to see if this BBT should be rewritten */
+ if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ }
+
}
}
instr->state = MTD_ERASE_DONE;
@@ -2129,6 +2192,18 @@
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+ if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+ for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+ if (rewrite_bbt[chipnr]) {
+ /* update the BBT for chip */
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
+ chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+ nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+ }
+ }
+ }
+
/* Return more or less happy */
return ret;
}
@@ -2433,8 +2508,19 @@
* fallback to software ECC
*/
this->eccsize = 256; /* set default eccsize */
+ this->eccbytes = 3;
switch (this->eccmode) {
+ case NAND_ECC_HW12_2048:
+ if (mtd->oobblock < 2048) {
+ printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
+ mtd->oobblock);
+ this->eccmode = NAND_ECC_SOFT;
+ this->calculate_ecc = nand_calculate_ecc;
+ this->correct_data = nand_correct_data;
+ } else
+ this->eccsize = 2048;
+ break;
case NAND_ECC_HW3_512:
case NAND_ECC_HW6_512:
@@ -2444,15 +2530,12 @@
this->eccmode = NAND_ECC_SOFT;
this->calculate_ecc = nand_calculate_ecc;
this->correct_data = nand_correct_data;
- break;
} else
- this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
+ this->eccsize = 512; /* set eccsize to 512 */
+ break;
case NAND_ECC_HW3_256:
- if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
break;
- printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
- BUG();
case NAND_ECC_NONE:
printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
@@ -2469,10 +2552,31 @@
BUG();
}
+ /* Check hardware ecc function availability and adjust number of ecc bytes per
+ * calculation step
+ */
+ switch (this->eccmode) {
+ case NAND_ECC_HW12_2048:
+ this->eccbytes += 4;
+ case NAND_ECC_HW8_512:
+ this->eccbytes += 2;
+ case NAND_ECC_HW6_512:
+ this->eccbytes += 3;
+ case NAND_ECC_HW3_512:
+ case NAND_ECC_HW3_256:
+ if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+ break;
+ printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+ BUG();
+ }
+
mtd->eccsize = this->eccsize;
/* Set the number of read / write steps for one page to ensure ECC generation */
switch (this->eccmode) {
+ case NAND_ECC_HW12_2048:
+ this->eccsteps = mtd->oobblock / 2048;
+ break;
case NAND_ECC_HW3_512:
case NAND_ECC_HW6_512:
case NAND_ECC_HW8_512:
diff -wur linux-2.6.10/drivers/mtd/nand/nand_bbt.c linux-2.6.10-lab/drivers/mtd/nand/nand_bbt.c
--- linux-2.6.10/drivers/mtd/nand/nand_bbt.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/nand_bbt.c 2007-10-04 19:10:17.000000000 -0400
@@ -6,7 +6,7 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
*
* 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
@@ -1001,6 +1001,7 @@
return nand_scan_bbt (mtd, &agand_flashbased);
}
+
/* Is a flash based bad block table requested ? */
if (this->options & NAND_USE_FLASH_BBT) {
/* Use the default pattern descriptors */
@@ -1008,18 +1009,19 @@
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
- if (mtd->oobblock > 512)
- return nand_scan_bbt (mtd, &largepage_flashbased);
- else
- return nand_scan_bbt (mtd, &smallpage_flashbased);
+ if (!this->badblock_pattern) {
+ this->badblock_pattern = (mtd->oobblock > 512) ?
+ &largepage_flashbased : &smallpage_flashbased;
+ }
} else {
this->bbt_td = NULL;
this->bbt_md = NULL;
- if (mtd->oobblock > 512)
- return nand_scan_bbt (mtd, &largepage_memorybased);
- else
- return nand_scan_bbt (mtd, &smallpage_memorybased);
+ if (!this->badblock_pattern) {
+ this->badblock_pattern = (mtd->oobblock > 512) ?
+ &largepage_memorybased : &smallpage_memorybased;
+ }
}
+ return nand_scan_bbt (mtd, this->badblock_pattern);
}
/**
diff -wur linux-2.6.10/drivers/mtd/nand/nand_ids.c linux-2.6.10-lab/drivers/mtd/nand/nand_ids.c
--- linux-2.6.10/drivers/mtd/nand/nand_ids.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/nand_ids.c 2007-10-04 19:10:17.000000000 -0400
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ * $Id: nand_ids.c,v 1.11 2005/01/17 18:26:27 dmarlin Exp $
*
* 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
@@ -103,7 +103,7 @@
* Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
* There are more speed improvements for reads and writes possible, but not implemented now
*/
- {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
diff -wur linux-2.6.10/drivers/mtd/nand/rtc_from4.c linux-2.6.10-lab/drivers/mtd/nand/rtc_from4.c
--- linux-2.6.10/drivers/mtd/nand/rtc_from4.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/rtc_from4.c 2007-10-04 19:10:17.000000000 -0400
@@ -6,7 +6,7 @@
* Derived from drivers/mtd/nand/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
- * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
*
* 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
@@ -83,13 +83,18 @@
#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7)
+#define ERR_STAT_ECC_AVAILABLE 0x20
+
/* Undefine for software ECC */
#define RTC_FROM4_HWECC 1
+/* Define as 1 for no virtual erase blocks (in JFFS2) */
+#define RTC_FROM4_NO_VIRTBLOCKS 0
+
/*
* Module stuff
*/
-static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE);
+static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
const static struct mtd_partition partition_info[] = {
{
@@ -267,7 +272,6 @@
}
-
/*
* rtc_from4_nand_device_ready - hardware specific ready/busy check
* @mtd: MTD device structure
@@ -286,6 +290,40 @@
}
+
+/*
+ * deplete - code to perform device recovery in case there was a power loss
+ * @mtd: MTD device structure
+ * @chip: Chip to select (0 == slot 3, 1 == slot 4)
+ *
+ * If there was a sudden loss of power during an erase operation, a
+ * "device recovery" operation must be performed when power is restored
+ * to ensure correct operation. This routine performs the required steps
+ * for the requested chip.
+ *
+ * See page 86 of the data sheet for details.
+ *
+ */
+static void deplete(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *this = mtd->priv;
+
+ /* wait until device is ready */
+ while (!this->dev_ready(mtd));
+
+ this->select_chip(mtd, chip);
+
+ /* Send the commands for device recovery, phase 1 */
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+ /* Send the commands for device recovery, phase 2 */
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+}
+
+
#ifdef RTC_FROM4_HWECC
/*
* rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
@@ -329,6 +367,7 @@
}
+
/*
* rtc_from4_calculate_ecc - hardware specific code to read ECC code
* @mtd: MTD device structure
@@ -356,6 +395,7 @@
ecc_code[7] |= 0x0f; /* set the last four bits (not used) */
}
+
/*
* rtc_from4_correct_data - hardware specific code to correct data using ECC code
* @mtd: MTD device structure
@@ -365,16 +405,14 @@
*
* The FPGA tells us fast, if there's an error or not. If no, we go back happy
* else we read the ecc results from the fpga and call the rs library to decode
- * and hopefully correct the error
+ * and hopefully correct the error.
*
- * For now I use the code, which we read from the FLASH to use the RS lib,
- * as the syndrom conversion has a unresolved issue.
*/
static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
{
int i, j, res;
unsigned short status;
- uint16_t par[6], syn[6], tmp;
+ uint16_t par[6], syn[6];
uint8_t ecc[8];
volatile unsigned short *rs_ecc;
@@ -416,15 +454,86 @@
}
/* Let the library code do its magic.*/
- res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL);
+ res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
if (res > 0) {
DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
"ECC corrected %d errors on read\n", res);
}
return res;
}
+
+
+/**
+ * rtc_from4_errstat - perform additional error status checks
+ * @mtd: MTD device structure
+ * @this: NAND chip structure
+ * @state: state or the operation
+ * @status: status code returned from read status
+ * @page: startpage inside the chip, must be called with (page & this->pagemask)
+ *
+ * Perform additional error status checks on erase and write failures
+ * to determine if errors are correctable. For this device, correctable
+ * 1-bit errors on erase and write are considered acceptable.
+ *
+ * note: see pages 34..37 of data sheet for details.
+ *
+ */
+static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
+{
+ int er_stat=0;
+ int rtn, retlen;
+ size_t len;
+ uint8_t *buf;
+ int i;
+
+ this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
+
+ if (state == FL_ERASING) {
+ for (i=0; i<4; i++) {
+ if (status & 1<<(i+1)) {
+ this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
+ rtn = this->read_byte(mtd);
+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+ er_stat |= 1<<(i+1); /* err_ecc_not_avail */
+ }
+ }
+ }
+ } else if (state == FL_WRITING) {
+ /* single bank write logic */
+ this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1);
+ rtn = this->read_byte(mtd);
+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+ er_stat |= 1<<1; /* err_ecc_not_avail */
+ } else {
+ len = mtd->oobblock;
+ buf = kmalloc (len, GFP_KERNEL);
+ if (!buf) {
+ printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
+ er_stat = 1; /* if we can't check, assume failed */
+ } else {
+ /* recovery read */
+ /* page read */
+ rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
+ if (rtn) { /* if read failed or > 1-bit error corrected */
+ er_stat |= 1<<1; /* ECC read failed */
+ }
+ kfree(buf);
+ }
+ }
+ }
+
+ rtn = status;
+ if (er_stat == 0) { /* if ECC is available */
+ rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */
+ }
+
+ return rtn;
+}
#endif
+
/*
* Main initialization routine
*/
@@ -432,6 +541,7 @@
{
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
+ int i;
/* Allocate memory for MTD device structure and private data */
rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
@@ -483,6 +593,8 @@
this->eccmode = NAND_ECC_HW8_512;
this->options |= NAND_HWECC_SYNDROME;
+ /* return the status of extra status and ECC checks */
+ this->errstat = rtc_from4_errstat;
/* set the nand_oobinfo to support FPGA H/W error detection */
this->autooob = &rtc_from4_nand_oobinfo;
this->enable_hwecc = rtc_from4_enable_hwecc;
@@ -504,6 +616,18 @@
return -ENXIO;
}
+ /* Perform 'device recovery' for each chip in case there was a power loss. */
+ for (i=0; i < this->numchips; i++) {
+ deplete(rtc_from4_mtd, i);
+ }
+
+#if RTC_FROM4_NO_VIRTBLOCKS
+ /* use a smaller erase block to minimize wasted space when a block is bad */
+ /* note: this uses eight times as much RAM as using the default and makes */
+ /* mounts take four times as long. */
+ rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS;
+#endif
+
/* Register the partitions */
add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
diff -wur linux-2.6.10/drivers/mtd/nand/s3c2410.c linux-2.6.10-lab/drivers/mtd/nand/s3c2410.c
--- linux-2.6.10/drivers/mtd/nand/s3c2410.c 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nand/s3c2410.c 2007-10-04 19:10:17.000000000 -0400
@@ -11,7 +11,7 @@
* 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
* 12-Oct-2004 BJD Fixed errors in use of platform data
*
- * $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $
+ * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $
*
* 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
@@ -117,12 +117,12 @@
static struct s3c2410_nand_info *to_nand_info(struct device *dev)
{
- return (struct s3c2410_nand_info *)dev_get_drvdata(dev);
+ return dev_get_drvdata(dev);
}
static struct s3c2410_platform_nand *to_nand_plat(struct device *dev)
{
- return (struct s3c2410_platform_nand *)dev->platform_data;
+ return dev->platform_data;
}
/* timing calculations */
@@ -167,7 +167,7 @@
if (plat != NULL) {
tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
- twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
+ twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
} else {
/* default timings */
tacls = 8;
@@ -205,7 +205,7 @@
struct nand_chip *this = mtd->priv;
unsigned long cur;
- nmtd = (struct s3c2410_nand_mtd *)this->priv;
+ nmtd = this->priv;
info = nmtd->info;
cur = readl(info->regs + S3C2410_NFCONF);
@@ -424,14 +424,14 @@
static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
- struct nand_chip *this = (struct nand_chip *)mtd->priv;
+ struct nand_chip *this = mtd->priv;
readsb(this->IO_ADDR_R, buf, len);
}
static void s3c2410_nand_write_buf(struct mtd_info *mtd,
const u_char *buf, int len)
{
- struct nand_chip *this = (struct nand_chip *)mtd->priv;
+ struct nand_chip *this = mtd->priv;
writesb(this->IO_ADDR_W, buf, len);
}
diff -wur linux-2.6.10/drivers/mtd/nftlmount.c linux-2.6.10-lab/drivers/mtd/nftlmount.c
--- linux-2.6.10/drivers/mtd/nftlmount.c 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/nftlmount.c 2007-10-04 19:10:17.000000000 -0400
@@ -4,7 +4,7 @@
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
- * $Id: nftlmount.c,v 1.39 2004/11/05 22:51:41 kalev Exp $
+ * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $
*
* 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
@@ -31,7 +31,7 @@
#define SECTORSIZE 512
-char nftlmountrev[]="$Revision: 1.39 $";
+char nftlmountrev[]="$Revision: 1.40 $";
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
* various device information of the NFTL partition and Bad Unit Table. Update
@@ -302,8 +302,6 @@
struct nftl_uci1 uci;
struct erase_info *instr = &nftl->instr;
- instr->mtd = nftl->mbd.mtd;
-
/* Read the Unit Control Information #1 for Wear-Leveling */
if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
8, &retlen, (char *)&uci) < 0)
@@ -320,6 +318,7 @@
memset(instr, 0, sizeof(struct erase_info));
/* XXX: use async erase interface, XXX: test return code */
+ instr->mtd = nftl->mbd.mtd;
instr->addr = block * nftl->EraseSize;
instr->len = nftl->EraseSize;
MTD_ERASE(nftl->mbd.mtd, instr);
diff -wur linux-2.6.10/drivers/mtd/redboot.c linux-2.6.10-lab/drivers/mtd/redboot.c
--- linux-2.6.10/drivers/mtd/redboot.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mtd/redboot.c 2007-10-04 19:10:17.000000000 -0400
@@ -1,5 +1,5 @@
/*
- * $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $
+ * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
*
* Parse RedBoot-style Flash Image System (FIS) tables and
* produce a Linux partition array to match.
@@ -30,6 +30,9 @@
struct fis_list *next;
};
+static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
+module_param(directory, int, 0);
+
static inline int redboot_checksum(struct fis_image_desc *img)
{
/* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
@@ -50,6 +53,8 @@
char *nullname;
int namelen = 0;
int nulllen = 0;
+ int numslots;
+ unsigned long offset;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
static char nullstring[] = "unallocated";
#endif
@@ -59,8 +64,15 @@
if (!buf)
return -ENOMEM;
- /* Read the start of the last erase block */
- ret = master->read(master, master->size - master->erasesize,
+ if ( directory < 0 )
+ offset = master->size + directory*master->erasesize;
+ else
+ offset = directory*master->erasesize;
+
+ printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+ master->name, offset);
+
+ ret = master->read(master, offset,
master->erasesize, &retlen, (void *)buf);
if (ret)
@@ -71,12 +83,16 @@
goto out;
}
- /* RedBoot image could appear in any of the first three slots */
- for (i = 0; i < 3; i++) {
- if (!memcmp(buf[i].name, "RedBoot", 8))
+ numslots = (master->erasesize / sizeof(struct fis_image_desc));
+ for (i = 0; i < numslots; i++) {
+ if (buf[i].name[0] == 0xff) {
+ i = numslots;
+ break;
+ }
+ if (!memcmp(buf[i].name, "FIS directory", 14))
break;
}
- if (i == 3) {
+ if (i == numslots) {
/* Didn't find it */
printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
master->name);
@@ -84,7 +100,7 @@
goto out;
}
- for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
+ for (i = 0; i < numslots; i++) {
struct fis_list *new_fl, **prev;
if (buf[i].name[0] == 0xff)
diff -wur linux-2.6.10/drivers/net/Kconfig linux-2.6.10-lab/drivers/net/Kconfig
--- linux-2.6.10/drivers/net/Kconfig 2004-12-24 16:35:25.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/Kconfig 2007-10-04 19:10:20.000000000 -0400
@@ -831,6 +831,18 @@
module, say M here and read as well
as .
+config SMC91X_GUMSTIX
+ tristate
+ default m if SMC91X=m
+ default y if SMC91X=y
+ depends on SMC91X && ARCH_GUMSTIX
+
+
+config SMSC911X
+ tristate "SMSC 911X support"
+ depends on NET_ETHERNET && (ARCH_GUMSTIX || ARCH_FIONA)
+
+
config SMC9194
tristate "SMC 9194 support"
depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -2193,7 +2205,7 @@
endmenu
-source "drivers/net/tokenring/Kconfig"
+# source "drivers/net/tokenring/Kconfig"
source "drivers/net/wireless/Kconfig"
@@ -2201,9 +2213,9 @@
source "drivers/net/wan/Kconfig"
-source "drivers/atm/Kconfig"
+# source "drivers/atm/Kconfig"
-source "drivers/s390/net/Kconfig"
+# source "drivers/s390/net/Kconfig"
config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
diff -wur linux-2.6.10/drivers/net/Makefile linux-2.6.10-lab/drivers/net/Makefile
--- linux-2.6.10/drivers/net/Makefile 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/Makefile 2007-10-04 19:10:20.000000000 -0400
@@ -7,6 +7,7 @@
endif
obj-$(CONFIG_E1000) += e1000/
+obj-$(CONFIG_SMSC911X) += smsc/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_BONDING) += bonding/
@@ -183,6 +184,7 @@
obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_SMC91X_GUMSTIX) += gumstix-smc91x.o
obj-$(CONFIG_ARM) += arm/
obj-$(CONFIG_NET_FC) += fc/
obj-$(CONFIG_DEV_APPLETALK) += appletalk/
diff -wur linux-2.6.10/drivers/net/mii.c linux-2.6.10-lab/drivers/net/mii.c
--- linux-2.6.10/drivers/net/mii.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/mii.c 2007-10-04 19:10:20.000000000 -0400
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
@@ -181,6 +182,8 @@
/* if autoneg is off, it's an error */
bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
+ msleep(10);
+
if (bmcr & BMCR_ANENABLE) {
bmcr |= BMCR_ANRESTART;
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
diff -wur linux-2.6.10/drivers/net/smc91x.c linux-2.6.10-lab/drivers/net/smc91x.c
--- linux-2.6.10/drivers/net/smc91x.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/smc91x.c 2007-10-04 19:10:20.000000000 -0400
@@ -1759,6 +1759,30 @@
return probe_irq_off(cookie);
}
+/**
+ * gen_serial_ether_addr - Generate software assigned Ethernet address
+ * based on the system_serial number
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Generate an Ethernet address (MAC) that is not multicast
+ * and has the local assigned bit set, keyed on the system_serial
+ */
+static inline void gen_serial_ether_addr(u8 *addr)
+{
+ static u8 ether_serial_digit = 1;
+ addr [0] = system_serial_high >> 8;
+ addr [1] = system_serial_high;
+ addr [2] = system_serial_low >> 24;
+ addr [3] = system_serial_low >> 16;
+ addr [4] = system_serial_low >> 8;
+ addr [5] = (system_serial_low & 0xc0) | /* top bits are from system serial */
+ (1 << 4) | /* 2 bits identify interface type 1=ether, 2=usb, 3&4 undef */
+ ((ether_serial_digit++) & 0x0f); /* 15 possible interfaces of each type */
+ addr [0] &= 0xfe; /* clear multicast bit */
+ addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
+}
+
+
/*
* Function: smc_probe(unsigned long ioaddr)
*
@@ -1969,15 +1993,13 @@
THROTTLE_TX_PKTS ? " [throttle_tx]" : "");
if (!is_valid_ether_addr(dev->dev_addr)) {
- printk("%s: Invalid ethernet MAC address. Please "
- "set using ifconfig\n", dev->name);
- } else {
+ gen_serial_ether_addr(dev->dev_addr);
+ }
/* Print the Ethernet address */
printk("%s: Ethernet addr: ", dev->name);
for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x\n", dev->dev_addr[5]);
- }
if (lp->phy_type == 0) {
PRINTK("%s: No PHY found\n", dev->name);
@@ -2215,6 +2237,10 @@
.resume = smc_drv_resume,
};
+#ifdef CONFIG_ARCH_GUMSTIX
+extern void gumstix_smc91x_load(void);
+#endif
+
static int __init smc_init(void)
{
#ifdef MODULE
@@ -2226,6 +2252,10 @@
#endif
#endif
+#ifdef CONFIG_ARCH_GUMSTIX
+ gumstix_smc91x_load();
+#endif
+
return driver_register(&smc_driver);
}
diff -wur linux-2.6.10/drivers/net/smc91x.h linux-2.6.10-lab/drivers/net/smc91x.h
--- linux-2.6.10/drivers/net/smc91x.h 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/smc91x.h 2007-10-04 19:10:20.000000000 -0400
@@ -55,6 +55,21 @@
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
+#elif defined(CONFIG_ARCH_GUMSTIX)
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_NOWAIT 1
+#define SMC_USE_PXA_DMA 1
+#define SMC_IO_SHIFT 0
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
+#define RPC_LSA_DEFAULT RPC_LED_100_10
+#define RPC_LSB_DEFAULT RPC_LED_TX_RX
+
+
#elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6)
/* We can only do 16-bit reads and writes in the static memory space. */
diff -wur linux-2.6.10/drivers/net/wan/Kconfig linux-2.6.10-lab/drivers/net/wan/Kconfig
--- linux-2.6.10/drivers/net/wan/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/wan/Kconfig 2007-10-04 19:10:17.000000000 -0400
@@ -23,6 +23,13 @@
If unsure, say N.
+# Configuration for the AnyData modules (for Fiona)
+config ANYDATA_DTG
+ tristate "AnyData DTG series WAN support (Fiona)"
+ depends on WAN
+ help
+ Driver for the AnyData DTG series WAN modules (used on Fiona)
+
# There is no way to detect a comtrol sv11 - force it modular for now.
config HOSTESS_SV11
tristate "Comtrol Hostess SV-11 support"
diff -wur linux-2.6.10/drivers/net/wan/Makefile linux-2.6.10-lab/drivers/net/wan/Makefile
--- linux-2.6.10/drivers/net/wan/Makefile 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/wan/Makefile 2007-10-04 19:10:17.000000000 -0400
@@ -5,6 +5,8 @@
# Rewritten to use lists instead of if-statements.
#
+obj-$(CONFIG_ANYDATA_DTG) += anydata.o
+
wanpipe-y := sdlamain.o sdla_ft1.o
wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o
wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o
@@ -61,6 +63,8 @@
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
+obj-$(CONFIG_FIONA_PM_WAN) += wan_pm.o
+
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff -wur linux-2.6.10/drivers/net/wireless/Kconfig linux-2.6.10-lab/drivers/net/wireless/Kconfig
--- linux-2.6.10/drivers/net/wireless/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/wireless/Kconfig 2007-10-04 19:10:18.000000000 -0400
@@ -355,6 +355,74 @@
say M here and read . The module
will be called prism54.ko.
+config HOSTAP
+ tristate "Host AP support for Prism2/2.5/3 IEEE 802.11b"
+ depends on NET_RADIO
+ ---help---
+ A driver for 802.11b wireless cards based on Intersil Prism2/2.5/3
+ chipset. This driver supports so called Host AP mode that allows
+ the card to act as an IEEE 802.11 access point.
+
+ See for more information about the
+ Host AP driver configuration and tools.
+
+ This option includes the base Host AP driver code that is shared by
+ different hardware models. You will also need to enable support for
+ PLX/PCI/CS version of the driver to actually use the driver.
+
+ The driver can be compiled as modules and they will be called
+ "hostap.o" and "hostap_crypt_wep.o".
+
+config HOSTAP_FIRMWARE
+ bool "Support downloading firmware images with Host AP driver"
+ depends on HOSTAP
+ ---help---
+ Configure Host AP driver to include support for firmware image
+ download. Current version supports only downloading to volatile, i.e.,
+ RAM memory. Flash upgrade is not yet supported.
+
+ Firmware image downloading needs user space tool, prism2_srec. It is
+ available from http://hostap.epitest.fi/.
+
+config HOSTAP_PLX
+ tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
+ depends on PCI && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
+ PCI adaptors.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named
+ "hostap_plx.o".
+
+config HOSTAP_PCI
+ tristate "Host AP driver for Prism2.5 PCI adaptors"
+ depends on PCI && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2.5 PCI adaptors.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named
+ "hostap_pci.o".
+
+config HOSTAP_CS
+ tristate "Host AP driver for Prism2/2.5/3 PC Cards"
+ depends on PCMCIA!=n && HOSTAP
+ ---help---
+ Host AP driver's version for Prism2/2.5/3 PC Cards.
+
+ "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
+ driver and its help text includes more information about the Host AP
+ driver.
+
+ The driver can be compiled as a module and will be named "hostap_cs.o".
+
# yes, this works even when no drivers are selected
config NET_WIRELESS
bool
diff -wur linux-2.6.10/drivers/net/wireless/Makefile linux-2.6.10-lab/drivers/net/wireless/Makefile
--- linux-2.6.10/drivers/net/wireless/Makefile 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/net/wireless/Makefile 2007-10-04 19:10:18.000000000 -0400
@@ -28,6 +28,12 @@
obj-$(CONFIG_PRISM54) += prism54/
+obj-$(CONFIG_HOSTAP) += hostap.o hostap_crypt_wep.o \
+ hostap_crypt_tkip.o hostap_crypt_ccmp.o
+obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
+obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
+obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
+
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
diff -wur linux-2.6.10/drivers/pcmcia/Makefile linux-2.6.10-lab/drivers/pcmcia/Makefile
--- linux-2.6.10/drivers/pcmcia/Makefile 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/pcmcia/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -46,4 +46,5 @@
pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o
pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
-
+pxa2xx_cs-$(CONFIG_ARCH_GUMSTIX) += pxa2xx_gumstix.o
+pxa2xx_cs-$(CONFIG_ARCH_FIONA) += pxa2xx_fiona.o
diff -wur linux-2.6.10/drivers/serial/pxa.c linux-2.6.10-lab/drivers/serial/pxa.c
--- linux-2.6.10/drivers/serial/pxa.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/serial/pxa.c 2007-10-04 19:10:16.000000000 -0400
@@ -49,6 +49,16 @@
#include
#include
+#if defined(CONFIG_IOC) && defined(CONFIG_ARCH_FIONA)
+#define FFUART_LINE 0
+#define HWUART_LINE 1
+#define STUART_LINE 2
+#else
+#define FFUART_LINE 0
+#define BTUART_LINE 1
+#define STUART_LINE 2
+#define HWUART_LINE 3
+#endif
struct uart_pxa_port {
struct uart_port port;
@@ -58,6 +68,8 @@
unsigned int lsr_break_flag;
unsigned int cken;
char *name;
+ unsigned int msr; //djf
+ unsigned int lsr; //djf
};
static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
@@ -177,6 +189,7 @@
}
ignore_char:
*status = serial_in(up, UART_LSR);
+ up->lsr = *status;
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty);
}
@@ -229,7 +242,7 @@
int status;
status = serial_in(up, UART_MSR);
-
+ up->msr = status;
if ((status & UART_MSR_ANY_DELTA) == 0)
return;
@@ -254,15 +267,20 @@
struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id;
unsigned int iir, lsr;
+ serial_out(up, UART_MCR, serial_in(up, UART_MCR) & ~UART_MCR_RTS); // Clear RTS
iir = serial_in(up, UART_IIR);
if (iir & UART_IIR_NO_INT)
- return IRQ_NONE;
+ {
+ //printk(KERN_WARNING "serial_pxa_irq: odd -- interrupt triggered, but no interrupt in IIR: %08x\n",iir);
+ }
lsr = serial_in(up, UART_LSR);
+ up->lsr = lsr;
if (lsr & UART_LSR_DR)
receive_chars(up, &lsr, regs);
check_modem_status(up);
if (lsr & UART_LSR_THRE)
transmit_chars(up);
+ serial_out(up, UART_MCR, serial_in(up, UART_MCR) | UART_MCR_RTS); // Assert RTS
return IRQ_HANDLED;
}
@@ -273,7 +291,8 @@
unsigned int ret;
spin_lock_irqsave(&up->port.lock, flags);
- ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ //ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+ ret = up->lsr * UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
return ret;
@@ -286,9 +305,9 @@
unsigned char status;
unsigned int ret;
-return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
spin_lock_irqsave(&up->port.lock, flags);
- status = serial_in(up, UART_MSR);
+ //status = serial_in(up, UART_MSR);
+ status = up->msr;
spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
@@ -318,6 +337,10 @@
mcr |= UART_MCR_OUT2;
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
+ if (port->line == HWUART_LINE) // HWUART
+ {
+ mcr |= UART_MCR_AFE;
+ }
mcr |= up->mcr;
@@ -416,10 +439,10 @@
/*
* And clear the interrupt registers again for luck.
*/
- (void) serial_in(up, UART_LSR);
+ up->lsr = serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
- (void) serial_in(up, UART_MSR);
+ up->msr = serial_in(up, UART_MSR);
return 0;
}
@@ -493,7 +516,7 @@
if ((up->port.uartclk / quot) < (2400 * 16))
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
/*
* Ok, we're now changing the port state. Do it with
@@ -565,9 +588,10 @@
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
pxa_set_cken(up->cken, !state);
- if (!state)
+ if (!state) {
udelay(1);
}
+}
static void serial_pxa_release_port(struct uart_port *port)
{
@@ -740,6 +764,55 @@
.verify_port = serial_pxa_verify_port,
};
+#if defined(CONFIG_IOC) && defined(CONFIG_ARCH_FIONA)
+static struct uart_pxa_port serial_pxa_ports[] = {
+ { /* FFUART */
+ .name = "FFUART",
+ .cken = CKEN6_FFUART,
+ .port = {
+ .type = PORT_PXA,
+ .iotype = UPIO_MEM,
+ .membase = (void *)&FFUART,
+ .mapbase = __PREG(FFUART),
+ .irq = IRQ_FFUART,
+ .uartclk = 921600 * 16,
+ .fifosize = 64,
+ .ops = &serial_pxa_pops,
+ .line = FFUART_LINE,
+ },
+ }, { /* HWUART */
+ .name = "HWUART",
+ .cken = CKEN4_HWUART,
+ .port = {
+ .type = PORT_PXA,
+ .iotype = UPIO_MEM,
+ .membase = (void *)&HWUART,
+ .mapbase = __PREG(HWUART),
+ .irq = IRQ_HWUART,
+ .uartclk = 921600 * 16,
+ .fifosize = 64,
+ .ops = &serial_pxa_pops,
+ .line = HWUART_LINE,
+ },
+ }, { /* STUART */
+ .name = "STUART",
+ .cken = CKEN5_STUART,
+ .port = {
+ .type = PORT_PXA,
+ .iotype = UPIO_MEM,
+ .membase = (void *)&STUART,
+ .mapbase = __PREG(STUART),
+ .irq = IRQ_STUART,
+ .uartclk = 921600 * 16,
+ .fifosize = 64,
+ .ops = &serial_pxa_pops,
+ .line = STUART_LINE,
+ },
+ }
+};
+
+#else
+
static struct uart_pxa_port serial_pxa_ports[] = {
{ /* FFUART */
.name = "FFUART",
@@ -753,7 +826,7 @@
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
- .line = 0,
+ .line = FFUART_LINE,
},
}, { /* BTUART */
.name = "BTUART",
@@ -767,7 +840,7 @@
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
- .line = 1,
+ .line = BTUART_LINE,
},
}, { /* STUART */
.name = "STUART",
@@ -781,10 +854,25 @@
.uartclk = 921600 * 16,
.fifosize = 64,
.ops = &serial_pxa_pops,
- .line = 2,
+ .line = STUART_LINE,
+ },
+ }, { /* HWUART */
+ .name = "HWUART",
+ .cken = CKEN4_HWUART,
+ .port = {
+ .type = PORT_PXA,
+ .iotype = UPIO_MEM,
+ .membase = (void *)&HWUART,
+ .mapbase = __PREG(HWUART),
+ .irq = IRQ_HWUART,
+ .uartclk = 921600 * 16,
+ .fifosize = 64,
+ .ops = &serial_pxa_pops,
+ .line = HWUART_LINE,
},
}
};
+#endif
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
@@ -821,6 +909,18 @@
{
struct platform_device *dev = to_platform_device(_dev);
+#if defined(CONFIG_ARCH_FIONA) && defined(CONFIG_IOC)
+ /* There's a bug here for Fiona. If the serial port list is pruned down to 3 entries,
+ * there still seems to be 4 dev->id's tied to serial ports, which means that we
+ * get a request to probe dev->id = 3, but we don't have 4 serial ports, only 3.
+ * To "fix" this, we make sure that we have enough serial ports to match the request.
+ * (i.e. if dev->id >= number of ports, bail out as we don't want to add this port.
+ */
+ if (dev->id >= serial_pxa_reg.nr) {
+ return(0);
+ }
+#endif
+
serial_pxa_ports[dev->id].port.dev = _dev;
uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
dev_set_drvdata(_dev, &serial_pxa_ports[dev->id]);
diff -wur linux-2.6.10/drivers/usb/Makefile linux-2.6.10-lab/drivers/usb/Makefile
--- linux-2.6.10/drivers/usb/Makefile 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -7,6 +7,7 @@
obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_EHCI_HCD) += host/
+obj-$(CONFIG_USB_PHCI_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811HS) += host/
diff -wur linux-2.6.10/drivers/usb/core/devices.c linux-2.6.10-lab/drivers/usb/core/devices.c
--- linux-2.6.10/drivers/usb/core/devices.c 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/devices.c 2007-10-04 19:10:28.000000000 -0400
@@ -149,7 +149,7 @@
/*****************************************************************/
-void usbfs_conn_disc_event(void)
+void usbdevfs_conn_disc_event(void)
{
conndiscevcnt++;
wake_up(&deviceconndiscwq);
@@ -451,7 +451,7 @@
* nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion
- * The caller must own the device lock.
+ * The caller must own the usbdev->serialize semaphore.
*/
static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
@@ -569,6 +569,7 @@
static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
+ struct list_head *buslist;
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
@@ -580,15 +581,18 @@
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
+ /* enumerate busses */
down (&usb_bus_list_lock);
- /* print devices for all busses */
- list_for_each_entry(bus, &usb_bus_list, bus_list) {
+ list_for_each(buslist, &usb_bus_list) {
+ /* print devices for this bus */
+ bus = list_entry(buslist, struct usb_bus, bus_list);
+
/* recurse through all children of the root hub */
if (!bus->root_hub)
continue;
- usb_lock_device(bus->root_hub);
+ down(&bus->root_hub->serialize);
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
- usb_unlock_device(bus->root_hub);
+ up(&bus->root_hub->serialize);
if (ret < 0) {
up(&usb_bus_list_lock);
return ret;
@@ -678,7 +682,7 @@
return ret;
}
-struct file_operations usbfs_devices_fops = {
+struct file_operations usbdevfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
diff -wur linux-2.6.10/drivers/usb/core/devio.c linux-2.6.10-lab/drivers/usb/core/devio.c
--- linux-2.6.10/drivers/usb/core/devio.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/devio.c 2007-10-04 19:10:28.000000000 -0400
@@ -21,7 +21,7 @@
*
* $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
*
- * This file implements the usbfs/x/y files, where
+ * This file implements the usbdevfs/x/y files, where
* x is the bus number and y the device number.
*
* It allows user space programs/"drivers" to communicate directly
@@ -113,7 +113,7 @@
int i;
pos = *ppos;
- usb_lock_device(dev);
+ down(&dev->serialize);
if (!connected(dev)) {
ret = -ENODEV;
goto err;
@@ -175,7 +175,7 @@
}
err:
- usb_unlock_device(dev);
+ up(&dev->serialize);
return ret;
}
@@ -286,10 +286,9 @@
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
-
- /* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
- usb_kill_urb(as->urb);
+ /* usb_unlink_urb calls the completion handler with status == -ENOENT */
+ usb_unlink_urb(as->urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
@@ -354,7 +353,7 @@
destroy_async_on_interface(ps, ifnum);
}
-struct usb_driver usbfs_driver = {
+struct usb_driver usbdevfs_driver = {
.owner = THIS_MODULE,
.name = "usbfs",
.probe = driver_probe,
@@ -379,7 +378,7 @@
if (!intf)
err = -ENOENT;
else
- err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
+ err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps);
up_write(&usb_bus_type.subsys.rwsem);
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
@@ -402,7 +401,7 @@
if (!intf)
err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
- usb_driver_release_interface(&usbfs_driver, intf);
+ usb_driver_release_interface(&usbdevfs_driver, intf);
err = 0;
}
up_write(&usb_bus_type.subsys.rwsem);
@@ -411,8 +410,6 @@
static int checkintf(struct dev_state *ps, unsigned int ifnum)
{
- if (ps->dev->state != USB_STATE_CONFIGURED)
- return -EHOSTUNREACH;
if (ifnum >= 8*sizeof(ps->ifclaimed))
return -EINVAL;
if (test_bit(ifnum, &ps->ifclaimed))
@@ -452,8 +449,6 @@
{
int ret = 0;
- if (ps->dev->state != USB_STATE_CONFIGURED)
- return -EHOSTUNREACH;
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0;
@@ -521,15 +516,16 @@
struct usb_device *dev = ps->dev;
unsigned int ifnum;
- usb_lock_device(dev);
+ down(&dev->serialize);
list_del_init(&ps->list);
- for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
- ifnum++) {
+
+ if (connected(dev)) {
+ for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); ifnum++)
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
- }
destroy_all_async(ps);
- usb_unlock_device(dev);
+ }
+ up(&dev->serialize);
usb_put_dev(dev);
ps->dev = NULL;
kfree(ps);
@@ -561,10 +557,10 @@
snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n",
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
- usb_unlock_device(dev);
+ up(&dev->serialize);
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
- usb_lock_device(dev);
+ down(&dev->serialize);
if ((i > 0) && ctrl.wLength) {
if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data ");
@@ -592,13 +588,13 @@
printk ("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
- usb_unlock_device(dev);
+ up(&dev->serialize);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
- usb_lock_device(dev);
+ down(&dev->serialize);
}
free_page((unsigned long)tbuf);
- if (i<0 && i != -EPIPE) {
+ if (i<0) {
dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
"failed cmd %s rqt %u rq %u len %u ret %d\n",
current->comm, ctrl.bRequestType, ctrl.bRequest,
@@ -639,9 +635,9 @@
kfree(tbuf);
return -EINVAL;
}
- usb_unlock_device(dev);
+ up(&dev->serialize);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
- usb_lock_device(dev);
+ down(&dev->serialize);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf);
@@ -655,9 +651,9 @@
return -EFAULT;
}
}
- usb_unlock_device(dev);
+ up(&dev->serialize);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
- usb_lock_device(dev);
+ down(&dev->serialize);
}
kfree(tbuf);
if (i < 0) {
@@ -738,7 +734,7 @@
static int proc_resetdevice(struct dev_state *ps)
{
- return usb_reset_device(ps->dev);
+ return __usb_reset_device(ps->dev);
}
@@ -980,7 +976,7 @@
as = async_getpending(ps, arg);
if (!as)
return -EINVAL;
- usb_kill_urb(as->urb);
+ usb_unlink_urb(as->urb);
return 0;
}
@@ -1022,15 +1018,15 @@
int ret;
add_wait_queue(&ps->wait, &wait);
- for (;;) {
+ while (connected(dev)) {
__set_current_state(TASK_INTERRUPTIBLE);
if ((as = async_getcompleted(ps)))
break;
if (signal_pending(current))
break;
- usb_unlock_device(dev);
+ up(&dev->serialize);
schedule();
- usb_lock_device(dev);
+ down(&dev->serialize);
}
remove_wait_queue(&ps->wait, &wait);
set_current_state(TASK_RUNNING);
@@ -1134,7 +1130,7 @@
}
if (ps->dev->state != USB_STATE_CONFIGURED)
- retval = -EHOSTUNREACH;
+ retval = -ENODEV;
else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
retval = -EINVAL;
else switch (ctrl.ioctl_code) {
@@ -1153,11 +1149,7 @@
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
- usb_unlock_device(ps->dev);
- usb_lock_all_devices();
bus_rescan_devices(intf->dev.bus);
- usb_unlock_all_devices();
- usb_lock_device(ps->dev);
break;
/* talk directly to the interface's driver */
@@ -1200,9 +1192,9 @@
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
- usb_lock_device(dev);
+ down(&dev->serialize);
if (!connected(dev)) {
- usb_unlock_device(dev);
+ up(&dev->serialize);
return -ENODEV;
}
@@ -1302,7 +1294,7 @@
ret = proc_ioctl(ps, p);
break;
}
- usb_unlock_device(dev);
+ up(&dev->serialize);
if (ret >= 0)
inode->i_atime = CURRENT_TIME;
return ret;
@@ -1322,7 +1314,7 @@
return mask;
}
-struct file_operations usbfs_device_file_operations = {
+struct file_operations usbdevfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
diff -wur linux-2.6.10/drivers/usb/core/hcd-pci.c linux-2.6.10-lab/drivers/usb/core/hcd-pci.c
--- linux-2.6.10/drivers/usb/core/hcd-pci.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/hcd-pci.c 2007-10-04 19:10:28.000000000 -0400
@@ -38,6 +38,14 @@
/*-------------------------------------------------------------------------*/
+static void hcd_pci_release(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = bus->hcpriv;
+
+ if (hcd)
+ hcd->driver->hcd_free(hcd);
+}
+
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -70,15 +78,12 @@
if (pci_enable_device (dev) < 0)
return -ENODEV;
- dev->current_state = 0;
- dev->dev.power.power_state = 0;
if (!dev->irq) {
dev_err (&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
- retval = -ENODEV;
- goto done;
+ return -ENODEV;
}
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
@@ -87,8 +92,7 @@
len = pci_resource_len (dev, 0);
if (!request_mem_region (resource, len, driver->description)) {
dev_dbg (&dev->dev, "controller already in use\n");
- retval = -EBUSY;
- goto done;
+ return -EBUSY;
}
base = ioremap_nocache (resource, len);
if (base == NULL) {
@@ -98,7 +102,7 @@
release_mem_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- goto done;
+ return retval;
}
} else { // UHCI
@@ -115,8 +119,7 @@
}
if (region == PCI_ROM_RESOURCE) {
dev_dbg (&dev->dev, "no i/o regions available\n");
- retval = -EBUSY;
- goto done;
+ return -EBUSY;
}
base = (void __iomem *) resource;
}
@@ -136,7 +139,7 @@
release_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- goto done;
+ return retval;
}
}
// hcd zeroed everything
@@ -157,7 +160,7 @@
if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3:
- kfree (hcd);
+ driver->hcd_free (hcd);
goto clean_2;
}
@@ -185,14 +188,14 @@
}
hcd->irq = dev->irq;
- dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
+ dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
- resource);
+ base);
usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations;
- hcd->self.release = &usb_hcd_release;
hcd->self.hcpriv = (void *) hcd;
+ hcd->self.release = &hcd_pci_release;
init_timer (&hcd->rh_timer);
INIT_LIST_HEAD (&hcd->dev_list);
@@ -204,9 +207,6 @@
usb_hcd_pci_remove (dev);
}
-done:
- if (retval != 0)
- pci_disable_device (dev);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -260,26 +260,12 @@
}
usb_deregister_bus (&hcd->self);
-
- pci_disable_device(dev);
}
EXPORT_SYMBOL (usb_hcd_pci_remove);
#ifdef CONFIG_PM
-static char __attribute_used__ *pci_state(u32 state)
-{
- switch (state) {
- case 0: return "D0";
- case 1: return "D1";
- case 2: return "D2";
- case 3: return "D3hot";
- case 4: return "D3cold";
- }
- return NULL;
-}
-
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
@@ -300,82 +286,45 @@
* PM-sensitive HCDs may already have done this.
*/
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- if (state > 4)
- state = 4;
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "suspend D%d --> D%d\n",
+ dev->current_state, state);
switch (hcd->state) {
-
- /* entry if root hub wasn't yet suspended ... from sysfs,
- * without autosuspend, or if USB_SUSPEND isn't configured.
- */
- case USB_STATE_RUNNING:
- hcd->state = USB_STATE_QUIESCING;
+ case USB_STATE_HALT:
+ dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
+ break;
+ case HCD_STATE_SUSPENDED:
+ dev_dbg (hcd->self.controller, "hcd already suspended\n");
+ break;
+ default:
retval = hcd->driver->suspend (hcd, state);
- if (retval) {
+ if (retval)
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
- break;
- }
+ else {
hcd->state = HCD_STATE_SUSPENDED;
- /* FALLTHROUGH */
-
- /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
- * controller and/or root hub will already have been suspended,
- * but it won't be ready for a PCI resume call.
- *
- * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
- * have been called, otherwise root hub timers still run ...
- */
- case HCD_STATE_SUSPENDED:
- if (state <= dev->current_state)
- break;
-
+ pci_save_state (dev, hcd->pci_state);
+#ifdef CONFIG_USB_SUSPEND
+ pci_enable_wake (dev, state, hcd->remote_wakeup);
+ pci_enable_wake (dev, 4, hcd->remote_wakeup);
+#endif
/* no DMA or IRQs except in D0 */
- if (!dev->current_state) {
- pci_save_state (dev);
pci_disable_device (dev);
free_irq (hcd->irq, hcd);
- }
-
- if (!has_pci_pm) {
- dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
- break;
- }
- /* POLICY: ignore D1/D2/D3hot differences;
- * we know D3hot will always work.
- */
+ if (has_pci_pm)
retval = pci_set_power_state (dev, state);
- if (retval < 0 && state < 3) {
- retval = pci_set_power_state (dev, 3);
- if (retval == 0)
- state = 3;
- }
- if (retval == 0) {
- dev_dbg (hcd->self.controller, "--> PCI %s\n",
- pci_state(dev->current_state));
-#ifdef CONFIG_USB_SUSPEND
- pci_enable_wake (dev, state, hcd->remote_wakeup);
- pci_enable_wake (dev, 4, hcd->remote_wakeup);
-#endif
- } else if (retval < 0) {
- dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
- pci_state(state), retval);
+ dev->dev.power.power_state = state;
+ if (retval < 0) {
+ dev_dbg (&dev->dev,
+ "PCI suspend fail, %d\n",
+ retval);
(void) usb_hcd_pci_resume (dev);
- break;
}
- break;
- default:
- dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
- hcd->state);
- retval = -EINVAL;
- break;
}
-
- /* update power_state **ONLY** to make sysfs happier */
- if (retval == 0)
- dev->dev.power.power_state = state;
+ }
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -393,18 +342,16 @@
int has_pci_pm;
hcd = pci_get_drvdata(dev);
+ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "resume from state D%d\n",
+ dev->current_state);
+
if (hcd->state != HCD_STATE_SUSPENDED) {
dev_dbg (hcd->self.controller,
"can't resume, not suspended!\n");
- return 0;
+ return -EL3HLT;
}
- has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
- /* D3cold resume isn't usually reported this way... */
- dev_dbg(hcd->self.controller, "resume from PCI %s%s\n",
- pci_state(dev->current_state),
- has_pci_pm ? "" : " (legacy)");
-
hcd->state = USB_STATE_RESUMING;
if (has_pci_pm)
@@ -417,8 +364,8 @@
"can't restore IRQ after resume!\n");
return retval;
}
- hcd->saw_irq = 0;
- pci_restore_state (dev);
+ pci_set_master (dev);
+ pci_restore_state (dev, hcd->pci_state);
#ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, dev->current_state, 0);
pci_enable_wake (dev, 4, 0);
diff -wur linux-2.6.10/drivers/usb/core/hcd.c linux-2.6.10-lab/drivers/usb/core/hcd.c
--- linux-2.6.10/drivers/usb/core/hcd.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/hcd.c 2007-10-04 19:10:28.000000000 -0400
@@ -435,6 +435,8 @@
/* non-generic request */
if (HCD_IS_SUSPENDED (hcd->state))
urb->status = -EAGAIN;
+ else if (!HCD_IS_RUNNING (hcd->state))
+ urb->status = -ENODEV;
else
urb->status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex,
@@ -443,16 +445,13 @@
error:
/* "protocol stall" on error */
urb->status = -EPIPE;
+ dev_dbg (hcd->self.controller, "unsupported hub control message (maxchild %d)\n",
+ urb->dev->maxchild);
}
if (urb->status) {
urb->actual_length = 0;
- if (urb->status != -EPIPE) {
- dev_dbg (hcd->self.controller,
- "CTRL: TypeReq=0x%x val=0x%x "
- "idx=0x%x len=%d ==> %d\n",
- typeReq, wValue, wIndex,
- wLength, urb->status);
- }
+ dev_dbg (hcd->self.controller, "CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d\n",
+ typeReq, wValue, wIndex, wLength, urb->status);
}
if (bufp) {
if (urb->transfer_buffer_length < len)
@@ -479,11 +478,6 @@
/*
* Root Hub interrupt transfers are synthesized with a timer.
* Completions are called in_interrupt() but not in_irq().
- *
- * Note: some root hubs (including common UHCI based designs) can't
- * correctly issue port change IRQs. They're the ones that _need_ a
- * timer; most other root hubs don't. Some systems could save a
- * lot of battery power by eliminating these root hub timer IRQs.
*/
static void rh_report_status (unsigned long ptr);
@@ -493,7 +487,10 @@
int len = 1 + (urb->dev->maxchild / 8);
/* rh_timer protected by hcd_data_lock */
- if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
+ if (hcd->rh_timer.data
+ || urb->status != -EINPROGRESS
+ || urb->transfer_buffer_length < len
+ || !HCD_IS_RUNNING (hcd->state)) {
dev_dbg (hcd->self.controller,
"not queuing rh status urb, stat %d\n",
urb->status);
@@ -532,11 +529,12 @@
return;
}
- /* complete the status urb, or retrigger the timer */
- spin_lock (&hcd_data_lock);
- if (urb->dev->state == USB_STATE_CONFIGURED) {
+ if (!HCD_IS_SUSPENDED (hcd->state))
length = hcd->driver->hub_status_data (
hcd, urb->transfer_buffer);
+
+ /* complete the status urb, or retrigger the timer */
+ spin_lock (&hcd_data_lock);
if (length > 0) {
hcd->rh_timer.data = 0;
urb->actual_length = length;
@@ -544,7 +542,6 @@
urb->hcpriv = NULL;
} else
mod_timer (&hcd->rh_timer, jiffies + HZ/4);
- }
spin_unlock (&hcd_data_lock);
spin_unlock (&urb->lock);
@@ -575,12 +572,11 @@
/*-------------------------------------------------------------------------*/
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
/* note: always a synchronous unlink */
- if ((unsigned long) urb == hcd->rh_timer.data) {
del_timer_sync (&hcd->rh_timer);
hcd->rh_timer.data = 0;
@@ -588,21 +584,6 @@
urb->hcpriv = NULL;
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_restore (flags);
-
- } else if (usb_pipeendpoint(urb->pipe) == 0) {
- spin_lock_irq(&urb->lock); /* from usb_kill_urb */
- ++urb->reject;
- spin_unlock_irq(&urb->lock);
-
- wait_event(usb_kill_urb_queue,
- atomic_read(&urb->use_count) == 0);
-
- spin_lock_irq(&urb->lock);
- --urb->reject;
- spin_unlock_irq(&urb->lock);
- } else
- return -EINVAL;
-
return 0;
}
@@ -747,7 +728,10 @@
usbfs_add_bus (bus);
+#ifdef DEBUG
dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+#endif
+
return 0;
}
EXPORT_SYMBOL (usb_register_bus);
@@ -762,7 +746,9 @@
*/
void usb_deregister_bus (struct usb_bus *bus)
{
+#ifdef DEBUG
dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum);
+#endif
/*
* NOTE: make sure that all the devices are removed by the
@@ -817,9 +803,9 @@
return (retval < 0) ? retval : -EMSGSIZE;
}
- usb_lock_device (usb_dev);
+ down (&usb_dev->serialize);
retval = usb_new_device (usb_dev);
- usb_unlock_device (usb_dev);
+ up (&usb_dev->serialize);
if (retval) {
usb_dev->bus->root_hub = NULL;
dev_err (parent_dev, "can't register root hub for %s, %d\n",
@@ -1105,17 +1091,13 @@
spin_lock_irqsave (&hcd_data_lock, flags);
if (unlikely (urb->reject))
status = -EPERM;
- else switch (hcd->state) {
- case USB_STATE_RUNNING:
- case USB_STATE_RESUMING:
+ else if (HCD_IS_RUNNING (hcd->state) &&
+ hcd->state != USB_STATE_QUIESCING) {
usb_get_dev (urb->dev);
list_add_tail (&urb->urb_list, &dev->urb_list);
status = 0;
- break;
- default:
+ } else
status = -ESHUTDOWN;
- break;
- }
spin_unlock_irqrestore (&hcd_data_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
@@ -1198,8 +1180,8 @@
{
int value;
- if (urb->dev == hcd->self.root_hub)
- value = usb_rh_urb_dequeue (hcd, urb);
+ if (urb == (struct urb *) hcd->rh_timer.data)
+ value = usb_rh_status_dequeue (hcd, urb);
else {
/* The only reason an HCD might fail this call is if
@@ -1287,7 +1269,7 @@
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address().
*/
- if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) {
+ if (!hcd->saw_irq) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Different ACPI or APIC settings may help."
"\n");
@@ -1596,12 +1578,13 @@
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
- if (start == USB_STATE_HALT)
+ if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return IRQ_NONE;
+
+ hcd->saw_irq = 1;
if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE;
- hcd->saw_irq = 1;
if (hcd->state != start && hcd->state == USB_STATE_HALT)
usb_hc_died (hcd);
return IRQ_HANDLED;
@@ -1610,6 +1593,22 @@
/*-------------------------------------------------------------------------*/
+static void hcd_panic (void *_hcd)
+{
+ struct usb_hcd *hcd = _hcd;
+ struct usb_device *hub = hcd->self.root_hub;
+ unsigned i;
+
+ /* hc's root hub is removed later removed in hcd->stop() */
+ down (&hub->serialize);
+ usb_set_device_state(hub, USB_STATE_NOTATTACHED);
+ for (i = 0; i < hub->maxchild; i++) {
+ if (hub->children [i])
+ usb_disconnect (&hub->children [i]);
+ }
+ up (&hub->serialize);
+}
+
/**
* usb_hc_died - report abnormal shutdown of a host controller (bus glue)
* @hcd: pointer to the HCD representing the controller
@@ -1622,19 +1621,9 @@
{
dev_err (hcd->self.controller, "HC died; cleaning up\n");
- /* make khubd clean up old urbs and devices */
- usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED);
- mod_timer(&hcd->rh_timer, jiffies);
+ /* clean up old urbs and devices; needs a task context */
+ INIT_WORK (&hcd->work, hcd_panic, hcd);
+ (void) schedule_work (&hcd->work);
}
EXPORT_SYMBOL (usb_hc_died);
-/*-------------------------------------------------------------------------*/
-
-void usb_hcd_release(struct usb_bus *bus)
-{
- struct usb_hcd *hcd;
-
- hcd = container_of (bus, struct usb_hcd, self);
- kfree(hcd);
-}
-EXPORT_SYMBOL (usb_hcd_release);
diff -wur linux-2.6.10/drivers/usb/core/hcd.h linux-2.6.10-lab/drivers/usb/core/hcd.h
--- linux-2.6.10/drivers/usb/core/hcd.h 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/hcd.h 2007-10-04 19:10:28.000000000 -0400
@@ -67,6 +67,7 @@
struct timer_list rh_timer; /* drives root hub */
struct list_head dev_list; /* devices on this bus */
+ struct work_struct work;
/*
* hardware info/state
@@ -80,6 +81,7 @@
#ifdef CONFIG_PCI
int region; /* pci region for regs */
+ u32 pci_state [16]; /* for PM state save */
#endif
#define HCD_BUFFER_POOLS 4
@@ -191,13 +193,8 @@
int (*get_frame_number) (struct usb_hcd *hcd);
/* memory lifecycle */
- /* Note: The absence of hcd_free reflects a temporary situation;
- * in the near future hcd_alloc will disappear as well and all
- * allocations/deallocations will be handled by usbcore. For the
- * moment, drivers are required to return a pointer that the core
- * can pass to kfree, i.e., the struct usb_hcd must be the _first_
- * member of a larger driver-specific structure. */
struct usb_hcd *(*hcd_alloc) (void);
+ void (*hcd_free) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
@@ -220,6 +217,7 @@
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
extern void usb_bus_init (struct usb_bus *bus);
+extern int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
#ifdef CONFIG_PCI
struct pci_dev;
@@ -365,11 +363,6 @@
return usb_register_root_hub (usb_dev, hcd->self.controller);
}
-extern void usb_hcd_release (struct usb_bus *);
-
-extern void usb_set_device_state(struct usb_device *udev,
- enum usb_device_state new_state);
-
/*-------------------------------------------------------------------------*/
/* exported only within usbcore */
diff -wur linux-2.6.10/drivers/usb/core/hub.c linux-2.6.10-lab/drivers/usb/core/hub.c
--- linux-2.6.10/drivers/usb/core/hub.c 2004-12-24 16:34:44.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/hub.c 2007-10-04 19:10:28.000000000 -0400
@@ -36,18 +36,17 @@
#include "hcd.h"
#include "hub.h"
-/* Protect struct usb_device->state and ->children members
- * Note: Both are also protected by ->serialize, except that ->state can
- * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
+static int over_current_reported = 0;
+
+/* Protect struct usb_device state and children members */
static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED;
-/* khubd's worklist and its lock */
+/* Wakes up khubd */
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+
static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
-/* Wakes up khubd */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
-
static pid_t khubd_pid = 0; /* PID of khubd */
static DECLARE_COMPLETION(khubd_exited);
@@ -56,31 +55,6 @@
module_param (blinkenlights, bool, S_IRUGO);
MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
-/*
- * As of 2.6.10 we introduce a new USB device initialization scheme which
- * closely resembles the way Windows works. Hopefully it will be compatible
- * with a wider range of devices than the old scheme. However some previously
- * working devices may start giving rise to "device not accepting address"
- * errors; if that happens the user can try the old scheme by adjusting the
- * following module parameters.
- *
- * For maximum flexibility there are two boolean parameters to control the
- * hub driver's behavior. On the first initialization attempt, if the
- * "old_scheme_first" parameter is set then the old scheme will be used,
- * otherwise the new scheme is used. If that fails and "use_both_schemes"
- * is set, then the driver will make another attempt, using the other scheme.
- */
-static int old_scheme_first = 0;
-module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(old_scheme_first,
- "start with the old device initialization scheme");
-
-static int use_both_schemes = 0;
-module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(use_both_schemes,
- "try the other device initialization scheme if the "
- "first one fails");
-
#ifdef DEBUG
static inline char *portspeed (int portstatus)
@@ -103,17 +77,9 @@
/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
{
- int i, ret;
-
- for (i = 0; i < 3; i++) {
- ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
+ return usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
- USB_DT_HUB << 8, 0, data, size,
- HZ * USB_CTRL_GET_TIMEOUT);
- if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
- return ret;
- }
- return -EINVAL;
+ USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);
}
/*
@@ -262,19 +228,6 @@
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
}
-static void kick_khubd(struct usb_hub *hub)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&hub_event_lock, flags);
- if (list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- wake_up(&khubd_wait);
- }
- spin_unlock_irqrestore(&hub_event_lock, flags);
-}
-
-
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
@@ -310,7 +263,12 @@
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
- kick_khubd(hub);
+ spin_lock(&hub_event_lock);
+ if (list_empty(&hub->event_list)) {
+ list_add_tail(&hub->event_list, &hub_event_list);
+ wake_up(&khubd_wait);
+ }
+ spin_unlock(&hub_event_lock);
resubmit:
if (hub->quiescing)
@@ -428,33 +386,6 @@
msleep(hub->descriptor->bPwrOn2PwrGood * 2);
}
-static void hub_quiesce(struct usb_hub *hub)
-{
- /* stop khubd and related activity */
- hub->quiescing = 1;
- usb_kill_urb(hub->urb);
- if (hub->has_indicators)
- cancel_delayed_work(&hub->leds);
- if (hub->has_indicators || hub->tt.hub)
- flush_scheduled_work();
-}
-
-static void hub_activate(struct usb_hub *hub)
-{
- int status;
-
- hub->quiescing = 0;
- status = usb_submit_urb(hub->urb, GFP_NOIO);
- if (status < 0)
- dev_err(&hub->intf->dev, "activate --> %d\n", status);
- if (hub->has_indicators && blinkenlights)
- schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
-
- /* scan all ports ASAP */
- hub->event_bits[0] = ~0;
- kick_khubd(hub);
-}
-
static int hub_hub_status(struct usb_hub *hub,
u16 *status, u16 *change)
{
@@ -520,8 +451,13 @@
}
hdev->maxchild = hub->descriptor->bNbrPorts;
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg (hub_dev, "%d port%s detected\n", hdev->maxchild,
+ (hdev->maxchild == 1) ? "" : "s");
+#else
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s");
+#endif
le16_to_cpus(&hub->descriptor->wHubCharacteristics);
@@ -650,7 +586,7 @@
dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
- /* set up the interrupt endpoint */
+ /* Start the interrupt endpoint */
pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
@@ -668,14 +604,24 @@
hub, endpoint->bInterval);
hub->urb->transfer_dma = hub->buffer_dma;
hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ ret = usb_submit_urb(hub->urb, GFP_KERNEL);
+ if (ret) {
+ message = "couldn't submit status urb";
+ goto fail;
+ }
- /* maybe cycle the hub leds */
- if (hub->has_indicators && blinkenlights)
+ /* Wake up khubd */
+ wake_up(&khubd_wait);
+
+ /* maybe start cycling the hub leds */
+ if (hub->has_indicators && blinkenlights) {
+ set_port_led(hdev, 1, HUB_LED_GREEN);
hub->indicator [0] = INDICATOR_CYCLE;
+ schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
+ }
hub_power_on(hub);
- hub->change_bits[0] = ~0;
- hub_activate(hub);
+
return 0;
fail:
@@ -687,6 +633,33 @@
static unsigned highspeed_hubs;
+static void hub_quiesce(struct usb_hub *hub)
+{
+ /* stop khubd and related activity */
+ hub->quiescing = 1;
+ usb_kill_urb(hub->urb);
+ if (hub->has_indicators)
+ cancel_delayed_work(&hub->leds);
+ if (hub->has_indicators || hub->tt.hub)
+ flush_scheduled_work();
+}
+
+#ifdef CONFIG_USB_SUSPEND
+
+static void hub_reactivate(struct usb_hub *hub)
+{
+ int status;
+
+ hub->quiescing = 0;
+ status = usb_submit_urb(hub->urb, GFP_NOIO);
+ if (status < 0)
+ dev_err(&hub->intf->dev, "reactivate --> %d\n", status);
+ if (hub->has_indicators && blinkenlights)
+ schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
+}
+
+#endif
+
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
@@ -766,7 +739,11 @@
goto descriptor_error;
/* We found a hub */
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg (hub_dev, "USB hub found\n");
+#else
dev_info (hub_dev, "USB hub found\n");
+#endif
hub = kmalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) {
@@ -828,29 +805,68 @@
}
}
-/* caller has locked the hub device */
-static void hub_pre_reset(struct usb_device *hdev)
+/* caller has locked the hub and must own the device lock */
+static int hub_reset(struct usb_hub *hub)
{
- struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
+ struct usb_device *hdev = hub->hdev;
int i;
- for (i = 0; i < hdev->maxchild; ++i) {
+ /* Disconnect any attached devices */
+ for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
if (hdev->children[i])
usb_disconnect(&hdev->children[i]);
}
- hub_quiesce(hub);
+
+ /* Attempt to reset the hub */
+ if (hub->urb)
+ usb_kill_urb(hub->urb);
+ else
+ return -1;
+
+ if (__usb_reset_device(hdev))
+ return -1;
+
+ hub->urb->dev = hdev;
+ if (usb_submit_urb(hub->urb, GFP_KERNEL))
+ return -1;
+
+ hub_power_on(hub);
+
+ return 0;
}
-/* caller has locked the hub device */
-static void hub_post_reset(struct usb_device *hdev)
+/* caller has locked the hub */
+/* FIXME! This routine should be subsumed into hub_reset */
+static void hub_start_disconnect(struct usb_device *hdev)
{
- struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
+ struct usb_device *parent = hdev->parent;
+ int i;
- hub_activate(hub);
- hub_power_on(hub);
+ /* Find the device pointer to disconnect */
+ if (parent) {
+ for (i = 0; i < parent->maxchild; i++) {
+ if (parent->children[i] == hdev) {
+ usb_disconnect(&parent->children[i]);
+ return;
+ }
+ }
+ }
+
+ dev_err(&hdev->dev, "cannot disconnect hub!\n");
}
+static void recursively_mark_NOTATTACHED(struct usb_device *udev)
+{
+ int i;
+
+ for (i = 0; i < udev->maxchild; ++i) {
+ if (udev->children[i])
+ recursively_mark_NOTATTACHED(udev->children[i]);
+ }
+ udev->state = USB_STATE_NOTATTACHED;
+}
+
/* grab device/port lock, returning index of that port (zero based).
* protects the upstream link used by this device from concurrent
* tree operations like suspend, resume, reset, and disconnect, which
@@ -867,16 +883,21 @@
/* root hub is always the first lock in the series */
hdev = udev->parent;
if (!hdev) {
- usb_lock_device(udev);
+ down(&udev->serialize);
return 0;
}
/* on the path from root to us, lock everything from
* top down, dropping parent locks when not needed
+ *
+ * NOTE: if disconnect were to ignore the locking, we'd need
+ * to get extra refcounts to everything since hdev->children
+ * and udev->parent could be invalidated while we work...
*/
t = locktree(hdev);
if (t < 0)
return t;
+ spin_lock_irq(&device_state_lock);
for (t = 0; t < hdev->maxchild; t++) {
if (hdev->children[t] == udev) {
/* everything is fail-fast once disconnect
@@ -888,45 +909,33 @@
/* when everyone grabs locks top->bottom,
* non-overlapping work may be concurrent
*/
+ spin_unlock_irq(&device_state_lock);
down(&udev->serialize);
up(&hdev->serialize);
return t;
}
}
- usb_unlock_device(hdev);
+ spin_unlock_irq(&device_state_lock);
+ up(&hdev->serialize);
return -ENODEV;
}
-static void recursively_mark_NOTATTACHED(struct usb_device *udev)
-{
- int i;
-
- for (i = 0; i < udev->maxchild; ++i) {
- if (udev->children[i])
- recursively_mark_NOTATTACHED(udev->children[i]);
- }
- udev->state = USB_STATE_NOTATTACHED;
-}
-
/**
- * usb_set_device_state - change a device's current state (usbcore, hcds)
+ * usb_set_device_state - change a device's current state (usbcore-internal)
* @udev: pointer to device whose state should be changed
* @new_state: new state value to be stored
*
- * udev->state is _not_ fully protected by the device lock. Although
- * most transitions are made only while holding the lock, the state can
- * can change to USB_STATE_NOTATTACHED at almost any time. This
+ * udev->state is _not_ protected by the device lock. This
* is so that devices can be marked as disconnected as soon as possible,
- * without having to wait for any semaphores to be released. As a result,
- * all changes to any device's state must be protected by the
- * device_state_lock spinlock.
+ * without having to wait for the semaphore to be released. Instead,
+ * changes to the state must be protected by the device_state_lock spinlock.
*
* Once a device has been added to the device tree, all changes to its state
* should be made using this routine. The state should _not_ be set directly.
*
* If udev->state is already USB_STATE_NOTATTACHED then no change is made.
* Otherwise udev->state is set to new_state, and if new_state is
- * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set
+ * USB_STATE_NOTATTACHED then all of udev's descendant's states are also set
* to USB_STATE_NOTATTACHED.
*/
void usb_set_device_state(struct usb_device *udev,
@@ -943,7 +952,6 @@
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
-EXPORT_SYMBOL(usb_set_device_state);
static void choose_address(struct usb_device *udev)
@@ -977,12 +985,11 @@
/**
* usb_disconnect - disconnect a device (usbcore-internal)
- * @pdev: pointer to device being disconnected
+ * @pdev: pointer to device being disconnected, into a locked hub
* Context: !in_interrupt ()
*
- * Something got disconnected. Get rid of it and all of its children.
- *
- * If *pdev is a normal device then the parent hub must already be locked.
+ * Something got disconnected. Get rid of it, and all of its children.
+ * If *pdev is a normal device then the parent hub should be locked.
* If *pdev is a root hub then this routine will acquire the
* usb_bus_list_lock on behalf of the caller.
*
@@ -1008,13 +1015,15 @@
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
/* lock the bus list on behalf of HCDs unregistering their root hubs */
- if (!udev->parent) {
+ if (!udev->parent)
down(&usb_bus_list_lock);
- usb_lock_device(udev);
- } else
down(&udev->serialize);
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
+#else
dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
+#endif
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
@@ -1037,16 +1046,14 @@
usbfs_remove_device(udev);
usb_remove_sysfs_dev_files(udev);
- /* Avoid races with recursively_mark_NOTATTACHED() */
+ /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */
spin_lock_irq(&device_state_lock);
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
- if (!udev->parent) {
- usb_unlock_device(udev);
- up(&usb_bus_list_lock);
- } else
up(&udev->serialize);
+ if (!udev->parent)
+ up(&usb_bus_list_lock);
device_unregister(&udev->dev);
}
@@ -1069,19 +1076,11 @@
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
- /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS.
- * MSFT needs this to be the first config; never use
- * it as the default unless Linux has host-side RNDIS.
- * A second config would ideally be CDC-Ethernet, but
- * may instead be the "vendor specific" CDC subset
- * long used by ARM Linux for sa1100 or pxa255.
- */
+ /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff) {
- c = udev->config[1].desc.bConfigurationValue;
+ && desc->bInterfaceProtocol == 0xff)
continue;
- }
c = udev->config[i].desc.bConfigurationValue;
break;
}
@@ -1299,8 +1298,7 @@
#define PORT_RESET_TRIES 5
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
-#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
-#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first)
+#define SET_CONFIG_TRIES 2
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
@@ -1370,13 +1368,14 @@
dev_err(hub_dev, "cannot reset port %d (err = %d)\n",
port + 1, status);
else
+{
status = hub_port_wait_reset(hdev, port, udev, delay);
+if (status)
+printk("<1>hub_port_wait_reset returned %d\n", status);
+}
/* return on disconnect or reset */
- switch (status) {
- case 0:
- case -ENOTCONN:
- case -ENODEV:
+ if (status == -ENOTCONN || status == 0) {
clear_port_feature(hdev,
port + 1, USB_PORT_FEAT_C_RESET);
/* FIXME need disconnect() for NOTATTACHED device */
@@ -1404,6 +1403,7 @@
int ret;
if (hdev->children[port]) {
+ /* FIXME need disconnect() for NOTATTACHED device */
usb_set_device_state(hdev->children[port],
USB_STATE_NOTATTACHED);
}
@@ -1415,33 +1415,6 @@
return ret;
}
-/*
- * Disable a port and mark a logical connnect-change event, so that some
- * time later khubd will disconnect() any existing usb_device on the port
- * and will re-enumerate if there actually is a device attached.
- */
-static void hub_port_logical_disconnect(struct usb_device *hdev, int port)
-{
- struct usb_hub *hub;
-
- dev_dbg(hubdev(hdev), "logical disconnect on port %d\n", port + 1);
- hub_port_disable(hdev, port);
-
- /* FIXME let caller ask to power down the port:
- * - some devices won't enumerate without a VBUS power cycle
- * - SRP saves power that way
- * - usb_suspend_device(dev,PM_SUSPEND_DISK)
- * That's easy if this hub can switch power per-port, and
- * khubd reactivates the port later (timer, SRP, etc).
- * Powerdown must be optional, because of reset/DFU.
- */
-
- hub = usb_get_intfdata(hdev->actconfig->interface[0]);
- set_bit(port, hub->change_bits);
- kick_khubd(hub);
-}
-
-
#ifdef CONFIG_USB_SUSPEND
/*
@@ -1459,8 +1432,8 @@
int status;
struct usb_device *udev;
- udev = hdev->children[port];
- // dev_dbg(hubdev(hdev), "suspend port %d\n", port + 1);
+ udev = hdev->children[port - 1];
+ // dev_dbg(hubdev(hdev), "suspend port %d\n", port);
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
@@ -1485,11 +1458,11 @@
}
/* see 7.1.7.6 */
- status = set_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND);
+ status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(hubdev(hdev),
"can't suspend port %d, status %d\n",
- port + 1, status);
+ port, status);
/* paranoia: "should not happen" */
(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
@@ -1519,16 +1492,20 @@
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*/
-int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
+static int __usb_suspend_device (struct usb_device *udev, int port, u32 state)
{
int status;
- /* caller owns the udev device lock */
if (port < 0)
return port;
- if (udev->state == USB_STATE_SUSPENDED
+ /* NOTE: udev->serialize released on all real returns! */
+
+ if (state <= udev->dev.power.power_state
+ || state < PM_SUSPEND_MEM
+ || udev->state == USB_STATE_SUSPENDED
|| udev->state == USB_STATE_NOTATTACHED) {
+ up(&udev->serialize);
return 0;
}
@@ -1591,6 +1568,7 @@
*/
if (state > PM_SUSPEND_MEM) {
dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
+ state = PM_SUSPEND_MEM;
}
/* "global suspend" of the HC-to-USB interface (root hub), or
@@ -1598,19 +1576,18 @@
*/
if (!udev->parent) {
struct usb_bus *bus = udev->bus;
- if (bus && bus->op->hub_suspend) {
+ if (bus && bus->op->hub_suspend)
status = bus->op->hub_suspend (bus);
- if (status == 0)
- usb_set_device_state(udev,
- USB_STATE_SUSPENDED);
- } else
+ else
status = -EOPNOTSUPP;
} else
- status = hub_port_suspend(udev->parent, port);
+ status = hub_port_suspend(udev->parent, port + 1);
+ if (status == 0)
+ udev->dev.power.power_state = state;
+ up(&udev->serialize);
return status;
}
-EXPORT_SYMBOL(__usb_suspend_device);
/**
* usb_suspend_device - suspend a usb device
@@ -1632,15 +1609,7 @@
*/
int usb_suspend_device(struct usb_device *udev, u32 state)
{
- int port, status;
-
- port = locktree(udev);
- if (port < 0)
- return port;
-
- status = __usb_suspend_device(udev, port, state);
- usb_unlock_device(udev);
- return status;
+ return __usb_suspend_device(udev, locktree(udev), state);
}
/*
@@ -1653,8 +1622,9 @@
int status;
u16 devstatus;
- /* caller owns the udev device lock */
+ /* caller owns udev->serialize */
dev_dbg(&udev->dev, "usb resume\n");
+ udev->dev.power.power_state = PM_SUSPEND_ON;
/* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the
@@ -1736,15 +1706,15 @@
int status;
struct usb_device *udev;
- udev = hdev->children[port];
- // dev_dbg(hubdev(hdev), "resume port %d\n", port + 1);
+ udev = hdev->children[port - 1];
+ // dev_dbg(hubdev(hdev), "resume port %d\n", port);
/* see 7.1.7.7; affects power usage, but not budgeting */
- status = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND);
+ status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(&hdev->actconfig->interface[0]->dev,
"can't resume port %d, status %d\n",
- port + 1, status);
+ port, status);
} else {
u16 devstatus;
u16 portchange;
@@ -1762,7 +1732,7 @@
* sequence.
*/
devstatus = portchange = 0;
- status = hub_port_status(hdev, port,
+ status = hub_port_status(hdev, port - 1,
&devstatus, &portchange);
if (status < 0
|| (devstatus & LIVE_FLAGS) != LIVE_FLAGS
@@ -1770,7 +1740,7 @@
) {
dev_dbg(&hdev->actconfig->interface[0]->dev,
"port %d status %04x.%04x after resume, %d\n",
- port + 1, portchange, devstatus, status);
+ port, portchange, devstatus, status);
} else {
/* TRSMRCY = 10 msec */
msleep(10);
@@ -1778,7 +1748,7 @@
}
}
if (status < 0)
- hub_port_logical_disconnect(hdev, port);
+ status = hub_port_disable(hdev, port);
return status;
}
@@ -1811,36 +1781,32 @@
*/
if (!udev->parent) {
struct usb_bus *bus = udev->bus;
- if (bus && bus->op->hub_resume) {
+ if (bus && bus->op->hub_resume)
status = bus->op->hub_resume (bus);
- } else
+ else
status = -EOPNOTSUPP;
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
- usb_set_device_state (udev, USB_STATE_CONFIGURED);
- status = hub_resume (udev
+ status = hub_resume (bus->root_hub
->actconfig->interface[0]);
}
} else if (udev->state == USB_STATE_SUSPENDED) {
- // NOTE this fails if parent is also suspended...
- status = hub_port_resume(udev->parent, port);
+ status = hub_port_resume(udev->parent, port + 1);
} else {
status = 0;
+ udev->dev.power.power_state = PM_SUSPEND_ON;
}
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n",
status);
}
- usb_unlock_device(udev);
+ up(&udev->serialize);
/* rebind drivers that had no suspend() */
- if (status == 0) {
- usb_lock_all_devices();
bus_rescan_devices(&usb_bus_type);
- usb_unlock_all_devices();
- }
+
return status;
}
@@ -1881,7 +1847,6 @@
continue;
down(&udev->serialize);
status = __usb_suspend_device(udev, port, state);
- up(&udev->serialize);
if (status < 0)
dev_dbg(&intf->dev, "suspend port %d --> %d\n",
port, status);
@@ -1898,9 +1863,6 @@
unsigned port;
int status;
- if (intf->dev.power.power_state == PM_SUSPEND_ON)
- return 0;
-
for (port = 0; port < hdev->maxchild; port++) {
struct usb_device *udev;
u16 portstat, portchange;
@@ -1919,24 +1881,24 @@
continue;
}
- if (!udev || status < 0)
+ if (!udev)
continue;
down (&udev->serialize);
if (portstat & USB_PORT_STAT_SUSPEND)
- status = hub_port_resume(hdev, port);
+ status = hub_port_resume(hdev, port + 1);
else {
status = finish_port_resume(udev);
- if (status < 0) {
+ if (status < 0)
+ status = hub_port_disable(hdev, port);
+ if (status < 0)
dev_dbg(&intf->dev, "resume port %d --> %d\n",
- port + 1, status);
- hub_port_logical_disconnect(hdev, port);
- }
+ port, status);
}
up(&udev->serialize);
}
intf->dev.power.power_state = PM_SUSPEND_ON;
- hub_activate(hub);
+ hub_reactivate(hub);
return 0;
}
@@ -2024,30 +1986,20 @@
return portstatus;
}
-#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
-#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-
static int hub_set_address(struct usb_device *udev)
{
int retval;
if (udev->devnum == 0)
return -EINVAL;
- if (udev->state == USB_STATE_ADDRESS)
- return 0;
- if (udev->state != USB_STATE_DEFAULT)
+ if (udev->state != USB_STATE_DEFAULT &&
+ udev->state != USB_STATE_ADDRESS)
return -EINVAL;
- retval = usb_control_msg(udev, usb_sndaddr0pipe(),
+ retval = usb_control_msg(udev, (PIPE_CONTROL << 30) /* Address 0 */,
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
- if (retval == 0) {
- int m = udev->epmaxpacketin[0];
-
+ if (retval == 0)
usb_set_device_state(udev, USB_STATE_ADDRESS);
- usb_disable_endpoint(udev, 0 + USB_DIR_IN);
- usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->epmaxpacketin[0] = udev->epmaxpacketout[0] = m;
- }
return retval;
}
@@ -2061,12 +2013,11 @@
* pointers, it's not necessary to lock the device.
*/
static int
-hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port,
- int retry_counter)
+hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
{
static DECLARE_MUTEX(usb_address0_sem);
- int i, j, retval;
+ int i, j, retval, retval2;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
@@ -2079,6 +2030,10 @@
hdev->bus->b_hnp_enable = 0;
}
+ retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND);
+ if (retval < 0 && retval != -EPIPE)
+ dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval);
+
/* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */
if (oldspeed == USB_SPEED_LOW)
@@ -2097,7 +2052,6 @@
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
- oldspeed = udev->speed;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
@@ -2107,22 +2061,26 @@
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
- /* to determine the ep0 maxpacket size, try to read
- * the device descriptor to get bMaxPacketSize0 and
- * then correct our initial guess.
+ /* to determine the ep0 maxpacket size, read the first 8
+ * bytes from the device descriptor to get bMaxPacketSize0;
+ * then correct our initial (small) guess.
*/
- i = 64;
- break;
+ // FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
- udev->epmaxpacketin[0] = udev->epmaxpacketout[0] = i;
+ udev->epmaxpacketin [0] = i;
+ udev->epmaxpacketout[0] = i;
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg (&udev->dev,
+#else
dev_info (&udev->dev,
- "%s %s speed USB device using %s and address %d\n",
+#endif
+ "%s %s speed USB device using address %d\n",
(udev->config) ? "reset" : "new",
({ char *speed; switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
@@ -2130,7 +2088,6 @@
case USB_SPEED_HIGH: speed = "high"; break;
default: speed = "?"; break;
}; speed;}),
- udev->bus->controller->driver->name,
udev->devnum);
/* Set up TT records, if needed */
@@ -2151,64 +2108,21 @@
* this area, and this is how Linux has done it for ages.
* Change it cautiously.
*
- * NOTE: If USE_NEW_SCHEME() is true we will start by issuing
- * a 64-byte GET_DESCRIPTOR request. This is what Windows does,
- * so it may help with some non-standards-compliant devices.
- * Otherwise we start with SET_ADDRESS and then try to read the
- * first 8 bytes of the device descriptor to get the ep0 maxpacket
- * value.
- */
- for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
- if (USE_NEW_SCHEME(retry_counter)) {
- struct usb_device_descriptor *buf;
-
-#define GET_DESCRIPTOR_BUFSIZE 64
- buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
- if (!buf) {
- retval = -ENOMEM;
- continue;
- }
- buf->bMaxPacketSize0 = 0;
-
- /* Use a short timeout the first time through,
- * so that recalcitrant full-speed devices with
- * 8- or 16-byte ep0-maxpackets won't slow things
- * down tremendously by NAKing the unexpectedly
- * early status stage.
- */
- j = usb_control_msg(udev, usb_rcvaddr0pipe(),
- USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
- USB_DT_DEVICE << 8, 0,
- buf, GET_DESCRIPTOR_BUFSIZE,
- (i ? HZ * USB_CTRL_GET_TIMEOUT : HZ));
- udev->descriptor.bMaxPacketSize0 =
- buf->bMaxPacketSize0;
- kfree(buf);
-
- retval = hub_port_reset(hdev, port, udev, delay);
- if (retval < 0) /* error or disconnect */
- goto fail;
- if (oldspeed != udev->speed) {
- dev_dbg(&udev->dev,
- "device reset changed speed!\n");
- retval = -ENODEV;
- goto fail;
- }
- if (udev->descriptor.bMaxPacketSize0 == 0) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
- "64", j);
- retval = -EMSGSIZE;
- continue;
- }
-#undef GET_DESCRIPTOR_BUFSIZE
- }
-
+ * NOTE: Windows gets the descriptor first, seemingly to help
+ * work around device bugs like "can't use addresses with bit 3
+ * set in certain configurations". Yes, really.
+ */
+ for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = hub_set_address(udev);
- if (retval >= 0)
+ if (retval == 0)
break;
msleep(200);
+ retval2 = hub_port_reset(hdev, port, udev, delay);
+ if (retval2 < 0) {
+ printk("<1>set_addr and port_reset failed!\n");
+ goto fail;
+ }
}
if (retval < 0) {
dev_err(&udev->dev,
@@ -2222,31 +2136,25 @@
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
- if (USE_NEW_SCHEME(retry_counter))
- break;
-
retval = usb_get_device_descriptor(udev, 8);
- if (retval < 8) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
+ if (retval >= 8)
+ break;
+ msleep(100);
+ }
+ if (retval != 8) {
+ dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
"8", retval);
if (retval >= 0)
retval = -EMSGSIZE;
- } else {
- retval = 0;
- break;
- }
- }
- if (retval)
goto fail;
-
- /* Should we verify that the value is valid? */
- i = udev->descriptor.bMaxPacketSize0;
- if (udev->epmaxpacketin[0] != i) {
- dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
+ }
+ if (udev->speed == USB_SPEED_FULL
+ && (udev->epmaxpacketin [0]
+ != udev->descriptor.bMaxPacketSize0)) {
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->epmaxpacketin[0] = udev->epmaxpacketout[0] = i;
+ udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0;
+ udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0;
}
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
@@ -2392,15 +2300,6 @@
return;
}
-#ifdef CONFIG_USB_SUSPEND
- /* If something is connected, but the port is suspended, wake it up.. */
- if (portstatus & USB_PORT_STAT_SUSPEND) {
- status = hub_port_resume(hdev, port);
- if (status < 0)
- dev_dbg(hub_dev, "can't clear suspend on port %d; %d\n", port+1, status);
- }
-#endif
-
for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *udev;
@@ -2425,7 +2324,7 @@
}
/* reset and get descriptor */
- status = hub_port_init(hdev, udev, port, i);
+ status = hub_port_init(hdev, udev, port);
if (status < 0)
goto loop;
@@ -2558,14 +2457,6 @@
usb_get_dev(hdev);
spin_unlock_irq(&hub_event_lock);
- dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
- hdev->state, hub->descriptor
- ? hub->descriptor->bNbrPorts
- : 0,
- /* NOTE: expects max 15 ports... */
- (u16) hub->change_bits[0],
- (u16) hub->event_bits[0]);
-
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
if (locktree(hdev) < 0)
@@ -2580,10 +2471,10 @@
dev_dbg (hub_dev, "resetting for error %d\n",
hub->error);
- ret = usb_reset_device(hdev);
- if (ret) {
+ if (hub_reset(hub)) {
dev_dbg (hub_dev,
- "error resetting hub: %d\n", ret);
+ "can't reset; disconnecting\n");
+ hub_start_disconnect(hdev);
goto loop;
}
@@ -2639,23 +2530,24 @@
if (portchange & USB_PORT_STAT_C_SUSPEND) {
clear_port_feature(hdev, i + 1,
USB_PORT_FEAT_C_SUSPEND);
- if (hdev->children[i]) {
+ if (hdev->children[i])
ret = remote_wakeup(hdev->children[i]);
- if (ret < 0)
- connect_change = 1;
- } else {
+ else
ret = -ENODEV;
- hub_port_disable(hdev, i);
- }
dev_dbg (hub_dev,
"resume on port %d, status %d\n",
i + 1, ret);
+ if (ret < 0)
+ ret = hub_port_disable(hdev, i);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+if (!over_current_reported) {
dev_err (hub_dev,
"over-current change on port %d\n",
i + 1);
+over_current_reported = 1;
+}
clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
hub_power_on(hub);
@@ -2693,7 +2585,7 @@
}
loop:
- usb_unlock_device(hdev);
+ up(&hdev->serialize);
usb_put_dev(hdev);
} /* end while (1) */
@@ -2846,15 +2738,13 @@
*
* The caller must own the device lock. For example, it's safe to use
* this from a driver probe() routine after downloading new firmware.
- * For calls that might not occur during probe(), drivers should lock
- * the device using usb_lock_device_for_reset().
*/
-int usb_reset_device(struct usb_device *udev)
+int __usb_reset_device(struct usb_device *udev)
{
struct usb_device *parent = udev->parent;
struct usb_device_descriptor descriptor = udev->descriptor;
- int i, ret = 0, port = -1;
- int udev_is_a_hub = 0;
+ int i, ret, port = -1;
+ struct usb_hub *hub;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED) {
@@ -2863,9 +2753,13 @@
return -EINVAL;
}
- if (!parent) {
- /* this requires hcd-specific logic; see OHCI hc_restart() */
- dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__);
+ /* FIXME: This should be legal for regular hubs. Root hubs may
+ * have special requirements. */
+ if (udev->maxchild) {
+ /* this requires hub- or hcd-specific logic;
+ * see hub_reset() and OHCI hc_restart()
+ */
+ dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__);
return -EISDIR;
}
@@ -2881,24 +2775,7 @@
return -ENOENT;
}
- /* If we're resetting an active hub, take some special actions */
- if (udev->actconfig &&
- udev->actconfig->interface[0]->dev.driver ==
- &hub_driver.driver) {
- udev_is_a_hub = 1;
- hub_pre_reset(udev);
- }
-
- for (i = 0; i < SET_CONFIG_TRIES; ++i) {
-
- /* ep0 maxpacket size may change; let the HCD know about it.
- * Other endpoints will be handled by re-enumeration. */
- usb_disable_endpoint(udev, 0 + USB_DIR_IN);
- usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- ret = hub_port_init(parent, udev, port, i);
- if (ret >= 0)
- break;
- }
+ ret = hub_port_init(parent, udev, port);
if (ret < 0)
goto re_enumerate;
@@ -2911,7 +2788,7 @@
}
if (!udev->actconfig)
- goto done;
+ return 0;
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_CONFIGURATION, 0,
@@ -2945,12 +2822,32 @@
}
}
-done:
- if (udev_is_a_hub)
- hub_post_reset(udev);
return 0;
re_enumerate:
- hub_port_logical_disconnect(parent, port);
+ hub_port_disable(parent, port);
+
+ hub = usb_get_intfdata(parent->actconfig->interface[0]);
+ set_bit(port, hub->change_bits);
+
+ spin_lock_irq(&hub_event_lock);
+ if (list_empty(&hub->event_list)) {
+ list_add_tail(&hub->event_list, &hub_event_list);
+ wake_up(&khubd_wait);
+ }
+ spin_unlock_irq(&hub_event_lock);
+
return -ENODEV;
}
+EXPORT_SYMBOL(__usb_reset_device);
+
+int usb_reset_device(struct usb_device *udev)
+{
+ int r;
+
+ down(&udev->serialize);
+ r = __usb_reset_device(udev);
+ up(&udev->serialize);
+
+ return r;
+}
diff -wur linux-2.6.10/drivers/usb/core/inode.c linux-2.6.10-lab/drivers/usb/core/inode.c
--- linux-2.6.10/drivers/usb/core/inode.c 2004-12-24 16:33:51.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/inode.c 2007-10-04 19:10:28.000000000 -0400
@@ -4,7 +4,7 @@
* inode.c -- Inode/Dentry functions for the USB device file system.
*
* Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,15 +40,17 @@
#include
#include
#include
-#include "usb.h"
static struct super_operations usbfs_ops;
static struct file_operations default_file_operations;
static struct inode_operations usbfs_dir_inode_operations;
+static struct vfsmount *usbdevfs_mount;
static struct vfsmount *usbfs_mount;
+static int usbdevfs_mount_count; /* = 0 */
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
+static struct dentry *devices_usbdevfs_dentry;
static struct dentry *devices_usbfs_dentry;
static int num_buses; /* = 0 */
@@ -238,6 +240,9 @@
if (usbfs_mount && usbfs_mount->mnt_sb)
update_sb(usbfs_mount->mnt_sb);
+ if (usbdevfs_mount && usbdevfs_mount->mnt_sb)
+ update_sb(usbdevfs_mount->mnt_sb);
+
return 0;
}
@@ -556,12 +561,28 @@
/* --------------------------------------------------------------------- */
+
+
+/*
+ * The usbdevfs name is now deprecated (as of 2.5.1).
+ * It will be removed when the 2.7.x development cycle is started.
+ * You have been warned :)
+ */
+static struct file_system_type usbdevice_fs_type;
+
static struct super_block *usb_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, usbfs_fill_super);
}
+static struct file_system_type usbdevice_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "usbdevfs",
+ .get_sb = usb_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
static struct file_system_type usb_fs_type = {
.owner = THIS_MODULE,
.name = "usbfs",
@@ -582,10 +603,16 @@
ignore_mount = 1;
/* create the devices special file */
+ retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count);
+ if (retval) {
+ err ("Unable to get usbdevfs mount");
+ goto exit;
+ }
+
retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
- goto exit;
+ goto error_clean_usbdevfs_mount;
}
ignore_mount = 0;
@@ -593,7 +620,7 @@
parent = usbfs_mount->mnt_sb->s_root;
devices_usbfs_dentry = fs_create_file ("devices",
listmode | S_IFREG, parent,
- NULL, &usbfs_devices_fops,
+ NULL, &usbdevfs_devices_fops,
listuid, listgid);
if (devices_usbfs_dentry == NULL) {
err ("Unable to create devices usbfs file");
@@ -601,19 +628,42 @@
goto error_clean_mounts;
}
+ parent = usbdevfs_mount->mnt_sb->s_root;
+ devices_usbdevfs_dentry = fs_create_file ("devices",
+ listmode | S_IFREG, parent,
+ NULL, &usbdevfs_devices_fops,
+ listuid, listgid);
+ if (devices_usbdevfs_dentry == NULL) {
+ err ("Unable to create devices usbfs file");
+ retval = -ENODEV;
+ goto error_remove_file;
+ }
+
goto exit;
+error_remove_file:
+ fs_remove_file (devices_usbfs_dentry);
+ devices_usbfs_dentry = NULL;
+
error_clean_mounts:
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
+
+error_clean_usbdevfs_mount:
+ simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
+
exit:
return retval;
}
static void remove_special_files (void)
{
+ if (devices_usbdevfs_dentry)
+ fs_remove_file (devices_usbdevfs_dentry);
if (devices_usbfs_dentry)
fs_remove_file (devices_usbfs_dentry);
+ devices_usbdevfs_dentry = NULL;
devices_usbfs_dentry = NULL;
+ simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count);
simple_release_fs(&usbfs_mount, &usbfs_mount_count);
}
@@ -621,6 +671,11 @@
{
struct inode *inode;
+ if (devices_usbdevfs_dentry) {
+ inode = devices_usbdevfs_dentry->d_inode;
+ if (inode)
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
if (devices_usbfs_dentry) {
inode = devices_usbfs_dentry->d_inode;
if (inode)
@@ -652,16 +707,29 @@
return;
}
+ parent = usbdevfs_mount->mnt_sb->s_root;
+ bus->usbdevfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
+ bus, NULL, busuid, busgid);
+ if (bus->usbdevfs_dentry == NULL) {
+ err ("error creating usbdevfs bus entry");
+ return;
+ }
+
usbfs_update_special();
- usbfs_conn_disc_event();
+ usbdevfs_conn_disc_event();
}
+
void usbfs_remove_bus(struct usb_bus *bus)
{
if (bus->usbfs_dentry) {
fs_remove_file (bus->usbfs_dentry);
bus->usbfs_dentry = NULL;
}
+ if (bus->usbdevfs_dentry) {
+ fs_remove_file (bus->usbdevfs_dentry);
+ bus->usbdevfs_dentry = NULL;
+ }
--num_buses;
if (num_buses <= 0) {
@@ -670,7 +738,7 @@
}
usbfs_update_special();
- usbfs_conn_disc_event();
+ usbdevfs_conn_disc_event();
}
void usbfs_add_device(struct usb_device *dev)
@@ -682,12 +750,20 @@
sprintf (name, "%03d", dev->devnum);
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbfs_dentry, dev,
- &usbfs_device_file_operations,
+ &usbdevfs_device_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
err ("error creating usbfs device entry");
return;
}
+ dev->usbdevfs_dentry = fs_create_file (name, devmode | S_IFREG,
+ dev->bus->usbdevfs_dentry, dev,
+ &usbdevfs_device_file_operations,
+ devuid, devgid);
+ if (dev->usbdevfs_dentry == NULL) {
+ err ("error creating usbdevfs device entry");
+ return;
+ }
/* Set the size of the device's file to be
* equal to the size of the device descriptors. */
@@ -695,13 +771,15 @@
for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
struct usb_config_descriptor *config =
(struct usb_config_descriptor *)dev->rawdescriptors[i];
- i_size += le16_to_cpu ((__force __le16)config->wTotalLength);
+ i_size += le16_to_cpu (config->wTotalLength);
}
if (dev->usbfs_dentry->d_inode)
dev->usbfs_dentry->d_inode->i_size = i_size;
+ if (dev->usbdevfs_dentry->d_inode)
+ dev->usbdevfs_dentry->d_inode->i_size = i_size;
usbfs_update_special();
- usbfs_conn_disc_event();
+ usbdevfs_conn_disc_event();
}
void usbfs_remove_device(struct usb_device *dev)
@@ -713,9 +791,12 @@
fs_remove_file (dev->usbfs_dentry);
dev->usbfs_dentry = NULL;
}
+ if (dev->usbdevfs_dentry) {
+ fs_remove_file (dev->usbdevfs_dentry);
+ dev->usbdevfs_dentry = NULL;
+ }
while (!list_empty(&dev->filelist)) {
ds = list_entry(dev->filelist.next, struct dev_state, list);
- wake_up_all(&ds->wait);
list_del_init(&ds->list);
if (ds->discsignr) {
sinfo.si_signo = SIGPIPE;
@@ -726,38 +807,51 @@
}
}
usbfs_update_special();
- usbfs_conn_disc_event();
+ usbdevfs_conn_disc_event();
}
/* --------------------------------------------------------------------- */
+#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *usbdir = NULL;
+#endif
int __init usbfs_init(void)
{
int retval;
- retval = usb_register(&usbfs_driver);
+ retval = usb_register(&usbdevfs_driver);
if (retval)
return retval;
retval = register_filesystem(&usb_fs_type);
if (retval) {
- usb_deregister(&usbfs_driver);
+ usb_deregister(&usbdevfs_driver);
+ return retval;
+ }
+ retval = register_filesystem(&usbdevice_fs_type);
+ if (retval) {
+ unregister_filesystem(&usb_fs_type);
+ usb_deregister(&usbdevfs_driver);
return retval;
}
- /* create mount point for usbfs */
+#ifdef CONFIG_PROC_FS
+ /* create mount point for usbdevfs */
usbdir = proc_mkdir("usb", proc_bus);
+#endif
return 0;
}
void usbfs_cleanup(void)
{
- usb_deregister(&usbfs_driver);
+ usb_deregister(&usbdevfs_driver);
unregister_filesystem(&usb_fs_type);
+ unregister_filesystem(&usbdevice_fs_type);
+#ifdef CONFIG_PROC_FS
if (usbdir)
remove_proc_entry("usb", proc_bus);
+#endif
}
diff -wur linux-2.6.10/drivers/usb/core/message.c linux-2.6.10-lab/drivers/usb/core/message.c
--- linux-2.6.10/drivers/usb/core/message.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/message.c 2007-10-04 19:10:28.000000000 -0400
@@ -17,13 +17,16 @@
#include
#include
#include
-#include
-#include
#include
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
+#ifdef CONFIG_ARCH_FIONA
+atomic_t pehci_error_counter = ATOMIC_INIT(0);
+EXPORT_SYMBOL(pehci_error_counter);
+#endif
+
static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
{
complete((struct completion *)urb->context);
@@ -34,7 +37,14 @@
{
struct urb *urb = (struct urb *) data;
+ dev_warn(&urb->dev->dev, "%s timeout on ep%d%s\n",
+ usb_pipecontrol(urb->pipe) ? "control" : "bulk",
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out");
usb_unlink_urb(urb);
+#ifdef CONFIG_ARCH_FIONA
+ atomic_inc(&pehci_error_counter);
+#endif
}
// Starts urb and waits for completion or timeout
@@ -46,6 +56,13 @@
struct timer_list timer;
int status;
+#ifdef CONFIG_ARCH_FIONA
+ if (timeout <= 0) {
+ printk("%s(timeout=%d)\n", __FUNCTION__, timeout);
+ timeout = 5 * HZ;
+ }
+#endif
+
init_completion(&done);
urb->context = &done;
urb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -64,14 +81,8 @@
wait_for_completion(&done);
status = urb->status;
/* note: HCDs return ETIMEDOUT for other reasons too */
- if (status == -ECONNRESET) {
- dev_warn(&urb->dev->dev,
- "%s timed out on ep%d%s\n",
- current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out");
+ if (status == -ECONNRESET)
status = -ETIMEDOUT;
- }
if (timeout > 0)
del_timer_sync(&timer);
}
@@ -243,16 +254,14 @@
// BUG ();
}
- if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
+ if (urb->status && urb->status != -ECONNRESET) {
int i, found, status;
io->status = urb->status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
- * careful: unlink can sometimes be synchronous...
*/
- spin_unlock (&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs [i] || !io->urbs [i]->dev)
continue;
@@ -265,7 +274,6 @@
} else if (urb == io->urbs [i])
found = 1;
}
- spin_lock (&io->lock);
}
urb->dev = NULL;
@@ -527,7 +535,6 @@
int i;
io->status = -ECONNRESET;
- spin_unlock (&io->lock);
for (i = 0; i < io->entries; i++) {
int retval;
@@ -538,7 +545,6 @@
dev_warn (&io->dev->dev, "%s, unlink --> %d\n",
__FUNCTION__, retval);
}
- spin_lock (&io->lock);
}
spin_unlock_irqrestore (&io->lock, flags);
}
@@ -556,7 +562,8 @@
*
* Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use
- * usb_get_string() or usb_string() for USB_DT_STRING.
+ * usb_get_device_descriptor() for USB_DT_DEVICE (not exported),
+ * and usb_get_string() or usb_string() for USB_DT_STRING.
* Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)
* are part of the device structure.
* In addition to a number of USB-standard descriptors, some
@@ -631,20 +638,6 @@
return result;
}
-static void usb_try_string_workarounds(unsigned char *buf, int *length)
-{
- int newlength, oldlength = *length;
-
- for (newlength = 2; newlength + 1 < oldlength; newlength += 2)
- if (!isprint(buf[newlength]) || buf[newlength + 1])
- break;
-
- if (newlength > 2) {
- buf[0] = newlength;
- *length = newlength;
- }
-}
-
static int usb_string_sub(struct usb_device *dev, unsigned int langid,
unsigned int index, unsigned char *buf)
{
@@ -656,26 +649,19 @@
/* If that failed try to read the descriptor length, then
* ask for just that many bytes */
- if (rc < 2) {
+ if (rc < 0) {
rc = usb_get_string(dev, langid, index, buf, 2);
if (rc == 2)
rc = usb_get_string(dev, langid, index, buf, buf[0]);
}
- if (rc >= 2) {
- if (!buf[0] && !buf[1])
- usb_try_string_workarounds(buf, &rc);
-
+ if (rc >= 0) {
/* There might be extra junk at the end of the descriptor */
if (buf[0] < rc)
rc = buf[0];
-
- rc = rc - (rc & 1); /* force a multiple of two */
- }
-
if (rc < 2)
- rc = (rc < 0 ? rc : -EINVAL);
-
+ rc = -EINVAL;
+ }
return rc;
}
@@ -709,8 +695,6 @@
int err;
unsigned int u, idx;
- if (dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
if (size <= 0 || !buf || !index)
return -EINVAL;
buf[0] = 0;
@@ -755,16 +739,13 @@
buf[idx] = 0;
err = idx;
- if (tbuf[1] != USB_DT_STRING)
- dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf);
-
errout:
kfree(tbuf);
return err;
}
-/*
- * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
+/**
+ * usb_get_device_descriptor - (re)reads the device descriptor
* @dev: the device whose device descriptor is being updated
* @size: how much of the descriptor to read
* Context: !in_interrupt ()
@@ -831,19 +812,9 @@
*/
int usb_get_status(struct usb_device *dev, int type, int target, void *data)
{
- int ret;
- u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
-
- if (!status)
- return -ENOMEM;
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
- sizeof(*status), HZ * USB_CTRL_GET_TIMEOUT);
-
- *(u16 *)data = *status;
- kfree(status);
- return ret;
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2,
+ HZ * USB_CTRL_GET_TIMEOUT);
}
/**
@@ -1176,8 +1147,6 @@
* use usb_set_interface() on the interfaces it claims. Resetting the whole
* configuration would affect other drivers' interfaces.
*
- * The caller must own the device lock.
- *
* Returns zero on success, else a negative error code.
*/
int usb_reset_configuration(struct usb_device *dev)
@@ -1188,9 +1157,9 @@
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
- /* caller must have locked the device and must own
- * the usb bus readlock (so driver bindings are stable);
- * calls during probe() are fine
+ /* caller must own dev->serialize (config won't change)
+ * and the usb bus readlock (so driver bindings are stable);
+ * so calls during probe() are fine
*/
for (i = 1; i < 16; ++i) {
@@ -1245,7 +1214,7 @@
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
* @configuration: the configuration being chosen.
- * Context: !in_interrupt(), caller owns the device lock
+ * Context: !in_interrupt(), caller holds dev->serialize
*
* This is used to enable non-default device modes. Not all devices
* use this kind of configurability; many devices only have one
@@ -1266,8 +1235,8 @@
* usb_set_interface().
*
* This call is synchronous. The calling context must be able to sleep,
- * must own the device lock, and must not hold the driver model's USB
- * bus rwsem; usb device driver probe() methods cannot use this routine.
+ * and must not hold the driver model lock for USB; usb device driver
+ * probe() methods may not use this routine.
*
* Returns zero on success, or else the status code returned by the
* underlying call that failed. On succesful completion, each interface
@@ -1282,6 +1251,8 @@
struct usb_interface **new_interfaces = NULL;
int n, nintf;
+ /* dev->serialize guards all config changes */
+
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue == configuration) {
cp = &dev->config[i];
diff -wur linux-2.6.10/drivers/usb/core/sysfs.c linux-2.6.10-lab/drivers/usb/core/sysfs.c
--- linux-2.6.10/drivers/usb/core/sysfs.c 2004-12-24 16:34:27.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/sysfs.c 2007-10-04 19:10:28.000000000 -0400
@@ -27,13 +27,11 @@
static ssize_t show_##field (struct device *dev, char *buf) \
{ \
struct usb_device *udev; \
- struct usb_host_config *actconfig; \
\
udev = to_usb_device (dev); \
- actconfig = udev->actconfig; \
- if (actconfig) \
+ if (udev->actconfig) \
return sprintf (buf, format_string, \
- actconfig->desc.field * multiplier); \
+ udev->actconfig->desc.field * multiplier); \
else \
return 0; \
} \
@@ -46,28 +44,6 @@
usb_actconfig_attr (bmAttributes, 1, "%2x\n")
usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
-#define usb_actconfig_str(name, field) \
-static ssize_t show_##name(struct device *dev, char *buf) \
-{ \
- struct usb_device *udev; \
- struct usb_host_config *actconfig; \
- int len; \
- \
- udev = to_usb_device (dev); \
- actconfig = udev->actconfig; \
- if (!actconfig) \
- return 0; \
- len = usb_string(udev, actconfig->desc.field, buf, PAGE_SIZE); \
- if (len < 0) \
- return 0; \
- buf[len] = '\n'; \
- buf[len+1] = 0; \
- return len+1; \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-usb_actconfig_str (configuration, iConfiguration)
-
/* configuration value is always present, and r/w */
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
@@ -79,9 +55,9 @@
if (sscanf (buf, "%u", &config) != 1 || config > 255)
return -EINVAL;
- usb_lock_device(udev);
+ down(&udev->serialize);
value = usb_set_configuration (udev, config);
- usb_unlock_device(udev);
+ up(&udev->serialize);
return (value < 0) ? value : count;
}
@@ -222,7 +198,6 @@
device_create_file (dev, &dev_attr_product);
if (udev->descriptor.iSerialNumber)
device_create_file (dev, &dev_attr_serial);
- device_create_file (dev, &dev_attr_configuration);
}
void usb_remove_sysfs_dev_files (struct usb_device *udev)
@@ -237,7 +212,6 @@
device_remove_file(dev, &dev_attr_product);
if (udev->descriptor.iSerialNumber)
device_remove_file(dev, &dev_attr_serial);
- device_remove_file (dev, &dev_attr_configuration);
}
/* Interface fields */
@@ -257,26 +231,7 @@
usb_intf_attr (bInterfaceClass, "%02x\n")
usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n")
-
-#define usb_intf_str(name, field) \
-static ssize_t show_##name(struct device *dev, char *buf) \
-{ \
- struct usb_interface *intf; \
- struct usb_device *udev; \
- int len; \
- \
- intf = to_usb_interface (dev); \
- udev = interface_to_usbdev (intf); \
- len = usb_string(udev, intf->cur_altsetting->desc.field, buf, PAGE_SIZE);\
- if (len < 0) \
- return 0; \
- buf[len] = '\n'; \
- buf[len+1] = 0; \
- return len+1; \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-usb_intf_str (interface, iInterface);
+usb_intf_attr (iInterface, "%02x\n")
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
@@ -285,6 +240,7 @@
&dev_attr_bInterfaceClass.attr,
&dev_attr_bInterfaceSubClass.attr,
&dev_attr_bInterfaceProtocol.attr,
+ &dev_attr_iInterface.attr,
NULL,
};
static struct attribute_group intf_attr_grp = {
@@ -294,17 +250,9 @@
void usb_create_sysfs_intf_files (struct usb_interface *intf)
{
sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
-
- if (intf->cur_altsetting->desc.iInterface)
- device_create_file(&intf->dev, &dev_attr_interface);
-
}
void usb_remove_sysfs_intf_files (struct usb_interface *intf)
{
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
-
- if (intf->cur_altsetting->desc.iInterface)
- device_remove_file(&intf->dev, &dev_attr_interface);
-
}
diff -wur linux-2.6.10/drivers/usb/core/urb.c linux-2.6.10-lab/drivers/usb/core/urb.c
--- linux-2.6.10/drivers/usb/core/urb.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/urb.c 2007-10-04 19:10:28.000000000 -0400
@@ -264,10 +264,11 @@
max = usb_maxpacket (dev, pipe, is_out);
if (max <= 0) {
- dev_dbg(&dev->dev,
- "bogus endpoint ep%d%s in %s (bad maxpacket %d)",
- usb_pipeendpoint (pipe), is_out ? "out" : "in",
- __FUNCTION__, max);
+ dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)",
+ __FUNCTION__,
+ usb_pipeendpoint (pipe), is_out ? "OUT" : "IN",
+ dev->bus->bus_name, dev->devpath,
+ max);
return -EMSGSIZE;
}
@@ -450,13 +451,6 @@
if (!urb)
return -EINVAL;
if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
-#ifdef CONFIG_DEBUG_KERNEL
- if (printk_ratelimit()) {
- printk(KERN_NOTICE "usb_unlink_urb() is deprecated for "
- "synchronous unlinks. Use usb_kill_urb() instead.\n");
- WARN_ON(1);
- }
-#endif
usb_kill_urb(urb);
return 0;
}
diff -wur linux-2.6.10/drivers/usb/core/usb.c linux-2.6.10-lab/drivers/usb/core/usb.c
--- linux-2.6.10/drivers/usb/core/usb.c 2004-12-24 16:34:46.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/usb.c 2007-10-04 19:10:28.000000000 -0400
@@ -39,7 +39,6 @@
#include
#include
#include
-#include
#include
#include
@@ -63,9 +62,6 @@
int nousb; /* Disable USB when built into kernel image */
/* Not honored on modular build */
-DECLARE_RWSEM(usb_all_devices_rwsem);
-EXPORT_SYMBOL(usb_all_devices_rwsem);
-
static int generic_probe (struct device *dev)
{
@@ -77,7 +73,6 @@
}
static struct device_driver usb_generic_driver = {
- .owner = THIS_MODULE,
.name = "usb",
.bus = &usb_bus_type,
.probe = generic_probe,
@@ -98,17 +93,13 @@
if (!driver->probe)
return error;
- /* FIXME we'd much prefer to just resume it ... */
if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
- intf->condition = USB_INTERFACE_BINDING;
error = driver->probe (intf, id);
- intf->condition = error ? USB_INTERFACE_UNBOUND :
- USB_INTERFACE_BOUND;
}
return error;
@@ -120,8 +111,6 @@
struct usb_interface *intf = to_usb_interface(dev);
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
- intf->condition = USB_INTERFACE_UNBINDING;
-
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
@@ -133,7 +122,6 @@
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
- intf->condition = USB_INTERFACE_UNBOUND;
return 0;
}
@@ -162,11 +150,8 @@
new_driver->driver.bus = &usb_bus_type;
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
- new_driver->driver.owner = new_driver->owner;
- usb_lock_all_devices();
retval = driver_register(&new_driver->driver);
- usb_unlock_all_devices();
if (!retval) {
pr_info("%s: registered new driver %s\n",
@@ -195,9 +180,7 @@
{
pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
- usb_lock_all_devices();
driver_unregister (&driver->driver);
- usb_unlock_all_devices();
usbfs_update_special();
}
@@ -219,7 +202,7 @@
* alternate settings available for this interfaces.
*
* Don't call this function unless you are bound to one of the interfaces
- * on this device or you have locked the device!
+ * on this device or you own the dev->serialize semaphore!
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
@@ -252,7 +235,7 @@
* drivers avoid such mistakes.
*
* Don't call this function unless you are bound to the intf interface
- * or you have locked the device!
+ * or you own the device's ->serialize semaphore!
*/
struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
unsigned int altnum)
@@ -320,12 +303,11 @@
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver probe() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
+ * Callers must own the driver model's usb bus writelock. So driver
+ * probe() entries don't need extra locking, but other call contexts
+ * may need to explicitly claim that lock.
*/
-int usb_driver_claim_interface(struct usb_driver *driver,
- struct usb_interface *iface, void* priv)
+int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
struct device *dev = &iface->dev;
@@ -334,7 +316,6 @@
dev->driver = &driver->driver;
usb_set_intfdata(iface, priv);
- iface->condition = USB_INTERFACE_BOUND;
/* if interface was already added, bind now; else let
* the future device_add() bind it, bypassing probe()
@@ -355,8 +336,8 @@
* also causes the driver disconnect() method to be called.
*
* This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver disconnect() entries don't need extra locking,
+ * Callers must own the usb_device serialize semaphore and the driver model's
+ * usb bus writelock. So driver disconnect() entries don't need extra locking,
* but other call contexts may need to explicitly claim those locks.
*/
void usb_driver_release_interface(struct usb_driver *driver,
@@ -374,7 +355,6 @@
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
- iface->condition = USB_INTERFACE_UNBOUND;
}
/**
@@ -552,7 +532,9 @@
return 0;
intf = to_usb_interface(dev);
+
usb_drv = to_usb_driver(drv);
+ id = usb_drv->id_table;
id = usb_match_id (intf, usb_drv->id_table);
if (id)
@@ -582,6 +564,7 @@
{
struct usb_interface *intf;
struct usb_device *usb_dev;
+ char *scratch;
int i = 0;
int length = 0;
@@ -608,6 +591,8 @@
return -ENODEV;
}
+ scratch = buffer;
+
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
@@ -615,30 +600,37 @@
*
* FIXME reduce hardwired intelligence here
*/
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ envp [i++] = scratch;
+ length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum))
+ usb_dev->bus->busnum, usb_dev->devnum);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
+ ++length;
+ scratch += length;
#endif
/* per-device configurations are common */
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ envp [i++] = scratch;
+ length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor,
usb_dev->descriptor.idProduct,
- usb_dev->descriptor.bcdDevice))
+ usb_dev->descriptor.bcdDevice);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
+ ++length;
+ scratch += length;
/* class-based driver binding models */
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ envp [i++] = scratch;
+ length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol))
+ usb_dev->descriptor.bDeviceProtocol);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
+ ++length;
+ scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
struct usb_host_interface *alt = intf->cur_altsetting;
@@ -647,16 +639,19 @@
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
- if (add_hotplug_env_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ envp [i++] = scratch;
+ length += snprintf (scratch, buffer_size - length,
"INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
+ alt->desc.bInterfaceProtocol);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
- }
+ ++length;
+ scratch += length;
- envp[i] = NULL;
+ }
+ envp[i++] = NULL;
return 0;
}
@@ -764,11 +759,7 @@
init_MUTEX(&dev->serialize);
if (dev->bus->op->allocate)
- if (dev->bus->op->allocate(dev)) {
- usb_bus_put(bus);
- kfree(dev);
- return NULL;
- }
+ dev->bus->op->allocate(dev);
return dev;
}
@@ -839,160 +830,6 @@
put_device(&intf->dev);
}
-
-/* USB device locking
- *
- * Although locking USB devices should be straightforward, it is
- * complicated by the way the driver-model core works. When a new USB
- * driver is registered or unregistered, the core will automatically
- * probe or disconnect all matching interfaces on all USB devices while
- * holding the USB subsystem writelock. There's no good way for us to
- * tell which devices will be used or to lock them beforehand; our only
- * option is to effectively lock all the USB devices.
- *
- * We do that by using a private rw-semaphore, usb_all_devices_rwsem.
- * When locking an individual device you must first acquire the rwsem's
- * readlock. When a driver is registered or unregistered the writelock
- * must be held. These actions are encapsulated in the subroutines
- * below, so all a driver needs to do is call usb_lock_device() and
- * usb_unlock_device().
- *
- * Complications arise when several devices are to be locked at the same
- * time. Only hub-aware drivers that are part of usbcore ever have to
- * do this; nobody else needs to worry about it. The problem is that
- * usb_lock_device() must not be called to lock a second device since it
- * would acquire the rwsem's readlock reentrantly, leading to deadlock if
- * another thread was waiting for the writelock. The solution is simple:
- *
- * When locking more than one device, call usb_lock_device()
- * to lock the first one. Lock the others by calling
- * down(&udev->serialize) directly.
- *
- * When unlocking multiple devices, use up(&udev->serialize)
- * to unlock all but the last one. Unlock the last one by
- * calling usb_unlock_device().
- *
- * When locking both a device and its parent, always lock the
- * the parent first.
- */
-
-/**
- * usb_lock_device - acquire the lock for a usb device structure
- * @udev: device that's being locked
- *
- * Use this routine when you don't hold any other device locks;
- * to acquire nested inner locks call down(&udev->serialize) directly.
- * This is necessary for proper interaction with usb_lock_all_devices().
- */
-void usb_lock_device(struct usb_device *udev)
-{
- down_read(&usb_all_devices_rwsem);
- down(&udev->serialize);
-}
-
-/**
- * usb_trylock_device - attempt to acquire the lock for a usb device structure
- * @udev: device that's being locked
- *
- * Don't use this routine if you already hold a device lock;
- * use down_trylock(&udev->serialize) instead.
- * This is necessary for proper interaction with usb_lock_all_devices().
- *
- * Returns 1 if successful, 0 if contention.
- */
-int usb_trylock_device(struct usb_device *udev)
-{
- if (!down_read_trylock(&usb_all_devices_rwsem))
- return 0;
- if (down_trylock(&udev->serialize)) {
- up_read(&usb_all_devices_rwsem);
- return 0;
- }
- return 1;
-}
-
-/**
- * usb_lock_device_for_reset - cautiously acquire the lock for a
- * usb device structure
- * @udev: device that's being locked
- * @iface: interface bound to the driver making the request (optional)
- *
- * Attempts to acquire the device lock, but fails if the device is
- * NOTATTACHED or SUSPENDED, or if iface is specified and the interface
- * is neither BINDING nor BOUND. Rather than sleeping to wait for the
- * lock, the routine polls repeatedly. This is to prevent deadlock with
- * disconnect; in some drivers (such as usb-storage) the disconnect()
- * callback will block waiting for a device reset to complete.
- *
- * Returns a negative error code for failure, otherwise 1 or 0 to indicate
- * that the device will or will not have to be unlocked. (0 can be
- * returned when an interface is given and is BINDING, because in that
- * case the driver already owns the device lock.)
- */
-int usb_lock_device_for_reset(struct usb_device *udev,
- struct usb_interface *iface)
-{
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
- if (udev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
- if (iface) {
- switch (iface->condition) {
- case USB_INTERFACE_BINDING:
- return 0;
- case USB_INTERFACE_BOUND:
- break;
- default:
- return -EINTR;
- }
- }
-
- while (!usb_trylock_device(udev)) {
- msleep(15);
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
- if (udev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
- if (iface && iface->condition != USB_INTERFACE_BOUND)
- return -EINTR;
- }
- return 1;
-}
-
-/**
- * usb_unlock_device - release the lock for a usb device structure
- * @udev: device that's being unlocked
- *
- * Use this routine when releasing the only device lock you hold;
- * to release inner nested locks call up(&udev->serialize) directly.
- * This is necessary for proper interaction with usb_lock_all_devices().
- */
-void usb_unlock_device(struct usb_device *udev)
-{
- up(&udev->serialize);
- up_read(&usb_all_devices_rwsem);
-}
-
-/**
- * usb_lock_all_devices - acquire the lock for all usb device structures
- *
- * This is necessary when registering a new driver or probing a bus,
- * since the driver-model core may try to use any usb_device.
- */
-void usb_lock_all_devices(void)
-{
- down_write(&usb_all_devices_rwsem);
-}
-
-/**
- * usb_unlock_all_devices - release the lock for all usb device structures
- */
-void usb_unlock_all_devices(void)
-{
- up_write(&usb_all_devices_rwsem);
-}
-
-
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
{
@@ -1014,10 +851,8 @@
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
- down(&dev->children[child]->serialize);
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
- up(&dev->children[child]->serialize);
if (ret_dev)
goto exit;
}
@@ -1052,9 +887,7 @@
bus = container_of(buslist, struct usb_bus, bus_list);
if (!bus->root_hub)
continue;
- usb_lock_device(bus->root_hub);
dev = match_device(bus->root_hub, vendor_id, product_id);
- usb_unlock_device(bus->root_hub);
if (dev)
goto exit;
}
@@ -1405,10 +1238,6 @@
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
- /* there's only one USB suspend state */
- if (intf->dev.power.power_state)
- return 0;
-
if (driver->suspend)
return driver->suspend(intf, state);
return 0;
@@ -1544,11 +1373,6 @@
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
-EXPORT_SYMBOL(usb_lock_device);
-EXPORT_SYMBOL(usb_trylock_device);
-EXPORT_SYMBOL(usb_lock_device_for_reset);
-EXPORT_SYMBOL(usb_unlock_device);
-
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
diff -wur linux-2.6.10/drivers/usb/core/usb.h linux-2.6.10-lab/drivers/usb/core/usb.h
--- linux-2.6.10/drivers/usb/core/usb.h 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/core/usb.h 2007-10-04 19:10:28.000000000 -0400
@@ -22,29 +22,8 @@
unsigned int size);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
-extern void usb_lock_all_devices(void);
-extern void usb_unlock_all_devices(void);
+extern void usb_set_device_state(struct usb_device *udev,
+ enum usb_device_state new_state);
/* for labeling diagnostics */
extern const char *usbcore_name;
-
-/* usbfs stuff */
-extern struct usb_driver usbfs_driver;
-extern struct file_operations usbfs_devices_fops;
-extern struct file_operations usbfs_device_file_operations;
-extern void usbfs_conn_disc_event(void);
-
-struct dev_state {
- struct list_head list; /* state list */
- struct usb_device *dev;
- struct file *file;
- spinlock_t lock; /* protects the async urb lists */
- struct list_head async_pending;
- struct list_head async_completed;
- wait_queue_head_t wait; /* wake up if a request completed */
- unsigned int discsignr;
- struct task_struct *disctask;
- void __user *disccontext;
- unsigned long ifclaimed;
-};
-
diff -wur linux-2.6.10/drivers/usb/gadget/Kconfig linux-2.6.10-lab/drivers/usb/gadget/Kconfig
--- linux-2.6.10/drivers/usb/gadget/Kconfig 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -39,17 +39,6 @@
If in doubt, say "N" and don't enable these drivers; most people
don't have this kind of hardware (except maybe inside Linux PDAs).
-config USB_GADGET_DEBUG_FILES
- boolean "Debugging information files"
- depends on USB_GADGET && PROC_FS
- help
- Some of the drivers in the "gadget" framework can expose
- debugging information in files such as /proc/driver/udc
- (for a peripheral controller). The information in these
- files may help when you're troubleshooting or bringing up a
- driver on a new board. Enable these files by choosing "Y"
- here. If in doubt, or to conserve kernel memory, say "N".
-
#
# USB Peripheral Controller Support
#
@@ -60,6 +49,22 @@
A USB device uses a controller to talk to its host.
Systems should have only one such upstream link.
+config USB_GADGET_ISP1761
+ boolean "Philips ISP1761"
+ select USB_GADGET_DUALSPEED
+ help
+ Philips 1761 is a USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "asdfasdf" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_ISP1761
+ tristate
+ depends on USB_GADGET_ISP1761
+ default USB_GADGET
+
config USB_GADGET_NET2280
boolean "NetChip 2280"
depends on PCI
@@ -217,6 +222,10 @@
Select this only if your OMAP board has a Mini-AB connector.
+config USB_OMAP_PROC
+ boolean "/proc/driver/udc file"
+ depends on USB_GADGET_OMAP
+
endchoice
config USB_GADGET_DUALSPEED
diff -wur linux-2.6.10/drivers/usb/gadget/Makefile linux-2.6.10-lab/drivers/usb/gadget/Makefile
--- linux-2.6.10/drivers/usb/gadget/Makefile 2004-12-24 16:33:59.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -7,13 +7,14 @@
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
+obj-$(CONFIG_USB_ISP1761) += pdc.o
#
# USB gadget drivers
#
g_zero-objs := zero.o usbstring.o config.o epautoconf.o
g_ether-objs := ether.o usbstring.o config.o epautoconf.o
-g_serial-objs := serial.o usbstring.o config.o epautoconf.o
+g_serial-objs := serial.o usbstring.o epautoconf.o
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o config.o \
epautoconf.o
diff -wur linux-2.6.10/drivers/usb/gadget/dummy_hcd.c linux-2.6.10-lab/drivers/usb/gadget/dummy_hcd.c
--- linux-2.6.10/drivers/usb/gadget/dummy_hcd.c 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/dummy_hcd.c 2007-10-04 19:10:29.000000000 -0400
@@ -65,7 +65,7 @@
#define DRIVER_DESC "USB Host+Gadget Emulator"
-#define DRIVER_VERSION "29 Oct 2004"
+#define DRIVER_VERSION "14 Mar 2004"
static const char driver_name [] = "dummy_hcd";
static const char driver_desc [] = "USB Host+Gadget Emulator";
@@ -95,17 +95,6 @@
struct usb_request req;
};
-static inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
-{
- return container_of (_ep, struct dummy_ep, ep);
-}
-
-static inline struct dummy_request *usb_request_to_dummy_request
- (struct usb_request *_req)
-{
- return container_of (_req, struct dummy_request, req);
-}
-
/*-------------------------------------------------------------------------*/
/*
@@ -144,7 +133,6 @@
#define FIFO_SIZE 64
struct dummy {
- struct usb_hcd hcd; /* must come first! */
spinlock_t lock;
/*
@@ -161,49 +149,37 @@
/*
* MASTER/HOST side support
*/
+ struct usb_hcd hcd;
+ struct platform_device pdev;
struct timer_list timer;
u32 port_status;
- unsigned started:1;
+ int started;
+ struct completion released;
unsigned resuming:1;
unsigned long re_timeout;
struct usb_device *udev;
};
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
-{
- return container_of(hcd, struct dummy, hcd);
-}
-
-static inline struct device *dummy_dev (struct dummy *dum)
-{
- return dum->hcd.self.controller;
-}
+static struct dummy *the_controller;
static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
{
return container_of (ep->gadget, struct dummy, gadget);
}
-static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
-{
- return container_of (gadget, struct dummy, gadget);
-}
-
static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
{
return container_of (dev, struct dummy, gadget.dev);
}
-static struct dummy *the_controller;
-
-/*-------------------------------------------------------------------------*/
-
/*
* This "hardware" may look a bit odd in diagnostics since it's got both
* host and device sides; and it binds different drivers to each side.
*/
-static struct platform_device the_pdev;
+#define hardware (&the_controller->pdev.dev)
+
+/*-------------------------------------------------------------------------*/
static struct device_driver dummy_driver = {
.name = (char *) driver_name,
@@ -219,8 +195,8 @@
* drivers would do real i/o using dma, fifos, irqs, timers, etc.
*/
-#define is_enabled(dum) \
- (dum->port_status & USB_PORT_STAT_ENABLE)
+#define is_enabled() \
+ (the_controller->port_status & USB_PORT_STAT_ENABLE)
static int
dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
@@ -230,12 +206,10 @@
unsigned max;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
- dum = ep_to_dummy (ep);
- if (!dum->driver || !is_enabled (dum))
+ if (!the_controller->driver || !is_enabled ())
return -ESHUTDOWN;
max = desc->wMaxPacketSize & 0x3ff;
@@ -247,6 +221,7 @@
* have some extra sanity checks. (there could be more though,
* especially for "ep9out" style fixed function ones.)
*/
+ dum = container_of (ep->gadget, struct dummy, gadget);
retval = -EINVAL;
switch (desc->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
@@ -315,7 +290,7 @@
_ep->maxpacket = max;
ep->desc = desc;
- dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+ dev_dbg (hardware, "enabled %s (ep%d%s-%s) maxpacket %d\n",
_ep->name,
desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
@@ -359,7 +334,7 @@
unsigned long flags;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || !ep->desc || _ep->name == ep0name)
return -EINVAL;
dum = ep_to_dummy (ep);
@@ -370,7 +345,7 @@
nuke (dum, ep);
spin_unlock_irqrestore (&dum->lock, flags);
- dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+ dev_dbg (hardware, "disabled %s\n", _ep->name);
return retval;
}
@@ -380,9 +355,9 @@
struct dummy_ep *ep;
struct dummy_request *req;
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep)
return 0;
- ep = usb_ep_to_dummy_ep (_ep);
req = kmalloc (sizeof *req, mem_flags);
if (!req)
@@ -398,11 +373,11 @@
struct dummy_ep *ep;
struct dummy_request *req;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
return;
- req = usb_request_to_dummy_request (_req);
+ req = container_of (_req, struct dummy_request, req);
WARN_ON (!list_empty (&req->queue));
kfree (req);
}
@@ -415,13 +390,8 @@
int mem_flags
) {
char *retval;
- struct dummy_ep *ep;
- struct dummy *dum;
-
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
- if (!dum->driver)
+ if (!the_controller->driver)
return 0;
retval = kmalloc (bytes, mem_flags);
*dma = (dma_addr_t) retval;
@@ -442,6 +412,9 @@
static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{
+#if 0
+ dev_dbg (hardware, "fifo_complete: %d\n", req->status);
+#endif
}
static int
@@ -452,20 +425,21 @@
struct dummy *dum;
unsigned long flags;
- req = usb_request_to_dummy_request (_req);
+ req = container_of (_req, struct dummy_request, req);
if (!_req || !list_empty (&req->queue) || !_req->complete)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!_ep || (!ep->desc && _ep->name != ep0name))
return -EINVAL;
- dum = ep_to_dummy (ep);
- if (!dum->driver || !is_enabled (dum))
+ if (!the_controller->driver || !is_enabled ())
return -ESHUTDOWN;
+ dum = container_of (ep->gadget, struct dummy, gadget);
+
#if 0
- dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+ dev_dbg (hardware, "ep %p queue req %p to %s, len %d buf %p\n",
ep, _req, _ep->name, _req->length, _req->buf);
#endif
@@ -508,13 +482,13 @@
unsigned long flags;
struct dummy_request *req = 0;
+ if (!the_controller->driver)
+ return -ESHUTDOWN;
+
if (!_ep || !_req)
return retval;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
-
- if (!dum->driver)
- return -ESHUTDOWN;
+ ep = container_of (_ep, struct dummy_ep, ep);
+ dum = container_of (ep->gadget, struct dummy, gadget);
spin_lock_irqsave (&dum->lock, flags);
list_for_each_entry (req, &ep->queue, queue) {
@@ -528,9 +502,9 @@
spin_unlock_irqrestore (&dum->lock, flags);
if (retval == 0) {
- dev_dbg (dummy_dev(dum),
- "dequeued req %p from %s, len %d buf %p\n",
+ dev_dbg (hardware, "dequeued req %p from %s, len %d buf %p\n",
req, _ep->name, _req->length, _req->buf);
+
_req->complete (_ep, _req);
}
return retval;
@@ -540,14 +514,12 @@
dummy_set_halt (struct usb_ep *_ep, int value)
{
struct dummy_ep *ep;
- struct dummy *dum;
if (!_ep)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
- if (!dum->driver)
+ if (!the_controller->driver)
return -ESHUTDOWN;
+ ep = container_of (_ep, struct dummy_ep, ep);
if (!value)
ep->halted = 0;
else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
@@ -591,7 +563,7 @@
{
struct dummy *dum;
- dum = gadget_to_dummy (_gadget);
+ dum = container_of (_gadget, struct dummy, gadget);
if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
|| !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
return -EINVAL;
@@ -606,7 +578,7 @@
{
struct dummy *dum;
- dum = gadget_to_dummy (_gadget);
+ dum = container_of (_gadget, struct dummy, gadget);
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
@@ -653,11 +625,17 @@
static void
dummy_udc_release (struct device *dev)
{
+ struct dummy *dum = gadget_dev_to_dummy (dev);
+
+ complete (&dum->released);
}
static void
-dummy_pdev_release (struct device *dev)
+dummy_hc_release (struct device *dev)
{
+ struct dummy *dum = dev_get_drvdata (dev);
+
+ complete (&dum->released);
}
static int
@@ -666,7 +644,7 @@
int rc;
strcpy (dum->gadget.dev.bus_id, "udc");
- dum->gadget.dev.parent = dummy_dev(dum);
+ dum->gadget.dev.parent = &dum->pdev.dev;
dum->gadget.dev.release = dummy_udc_release;
rc = device_register (&dum->gadget.dev);
@@ -679,7 +657,9 @@
dummy_unregister_udc (struct dummy *dum)
{
device_remove_file (&dum->gadget.dev, &dev_attr_function);
+ init_completion (&dum->released);
device_unregister (&dum->gadget.dev);
+ wait_for_completion (&dum->released);
}
int
@@ -731,8 +711,7 @@
dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
- dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
- driver->driver.name);
+ dev_dbg (hardware, "binding gadget driver '%s'\n", driver->driver.name);
if ((retval = driver->bind (&dum->gadget)) != 0) {
dum->driver = 0;
dum->gadget.dev.driver = 0;
@@ -740,7 +719,7 @@
}
// FIXME: Check these calls for errors and re-order
- driver->driver.bus = dum->gadget.dev.parent->bus;
+ driver->driver.bus = dum->pdev.dev.bus;
driver_register (&driver->driver);
device_bind_driver (&dum->gadget.dev);
@@ -786,13 +765,12 @@
if (!driver || driver != dum->driver)
return -EINVAL;
- dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+ dev_dbg (hardware, "unregister gadget driver '%s'\n",
driver->driver.name);
spin_lock_irqsave (&dum->lock, flags);
stop_activity (dum, driver);
- dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE |
- USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
+ dum->port_status &= ~USB_PORT_STAT_CONNECTION;
dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
spin_unlock_irqrestore (&dum->lock, flags);
@@ -837,17 +815,17 @@
struct dummy *dum;
unsigned long flags;
- if (!urb->transfer_buffer && urb->transfer_buffer_length)
- return -EINVAL;
+ /* patch to usb_sg_init() is in 2.5.60 */
+ BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length);
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) {
dum->udev = urb->dev;
usb_get_dev (dum->udev);
} else if (unlikely (dum->udev != urb->dev))
- dev_err (dummy_dev(dum), "usb_device address has changed!\n");
+ dev_err (hardware, "usb_device address has changed!\n");
urb->hcpriv = dum;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
@@ -1073,7 +1051,7 @@
total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
break;
default:
- dev_err (dummy_dev(dum), "bogus device speed\n");
+ dev_err (hardware, "bogus device speed\n");
return;
}
@@ -1083,8 +1061,7 @@
spin_lock_irqsave (&dum->lock, flags);
if (!dum->udev) {
- dev_err (dummy_dev(dum),
- "timer fired with no URBs pending?\n");
+ dev_err (hardware, "timer fired with no URBs pending?\n");
spin_unlock_irqrestore (&dum->lock, flags);
return;
}
@@ -1125,10 +1102,10 @@
ep = find_endpoint(dum, address);
if (!ep) {
/* set_configuration() disagreement */
- dev_dbg (dummy_dev(dum),
+ dev_err (hardware,
"no ep configured for urb %p\n",
urb);
- maybe_set_status (urb, -EPROTO);
+ maybe_set_status (urb, -ETIMEDOUT);
goto return_urb;
}
@@ -1141,7 +1118,7 @@
}
if (ep->halted && !ep->setup_stage) {
/* NOTE: must not be iso! */
- dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+ dev_dbg (hardware, "ep %s halted, urb %p\n",
ep->ep.name, urb);
maybe_set_status (urb, -EPIPE);
goto return_urb;
@@ -1167,8 +1144,7 @@
list_for_each_entry (req, &ep->queue, queue) {
list_del_init (&req->queue);
req->req.status = -EOVERFLOW;
- dev_dbg (dummy_dev(dum), "stale req = %p\n",
- req);
+ dev_dbg (hardware, "stale req = %p\n", req);
spin_unlock (&dum->lock);
req->req.complete (&ep->ep, &req->req);
@@ -1190,7 +1166,7 @@
break;
dum->address = setup.wValue;
maybe_set_status (urb, 0);
- dev_dbg (dummy_dev(dum), "set_address = %d\n",
+ dev_dbg (hardware, "set_address = %d\n",
setup.wValue);
value = 0;
break;
@@ -1306,7 +1282,7 @@
if (value < 0) {
if (value != -EOPNOTSUPP)
- dev_dbg (dummy_dev(dum),
+ dev_dbg (hardware,
"setup --> %d\n",
value);
maybe_set_status (urb, -EPIPE);
@@ -1386,14 +1362,14 @@
unsigned long flags;
int retval;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
if (!(dum->port_status & PORT_C_MASK))
retval = 0;
else {
*buf = (1 << 1);
- dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
+ dev_dbg (hardware, "port status 0x%08x has changes\n",
dum->port_status);
retval = 1;
}
@@ -1425,7 +1401,7 @@
int retval = 0;
unsigned long flags;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags);
switch (typeReq) {
case ClearHubFeature:
@@ -1433,12 +1409,9 @@
case ClearPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {
/* 20msec resume signaling */
dum->resuming = 1;
- dum->re_timeout = jiffies +
- msecs_to_jiffies(20);
- }
+ dum->re_timeout = jiffies + ((HZ * 20)/1000);
break;
case USB_PORT_FEAT_POWER:
dum->port_status = 0;
@@ -1467,7 +1440,7 @@
dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
dum->resuming = 0;
dum->re_timeout = 0;
- if (dum->driver && dum->driver->resume) {
+ if (dum->driver->resume) {
spin_unlock (&dum->lock);
dum->driver->resume (&dum->gadget);
spin_lock (&dum->lock);
@@ -1508,16 +1481,12 @@
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))
- == 0) {
- dum->port_status |=
- (1 << USB_PORT_FEAT_SUSPEND);
- if (dum->driver && dum->driver->suspend) {
+ dum->port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+ if (dum->driver->suspend) {
spin_unlock (&dum->lock);
dum->driver->suspend (&dum->gadget);
spin_lock (&dum->lock);
}
- }
break;
case USB_PORT_FEAT_RESET:
/* if it's already running, disconnect first */
@@ -1526,15 +1495,14 @@
| USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED);
if (dum->driver) {
- dev_dbg (dummy_dev(dum),
- "disconnect\n");
+ dev_dbg (hardware, "disconnect\n");
stop_activity (dum, dum->driver);
}
/* FIXME test that code path! */
}
/* 50msec reset signaling */
- dum->re_timeout = jiffies + msecs_to_jiffies(50);
+ dum->re_timeout = jiffies + ((HZ * 50)/1000);
/* FALLTHROUGH */
default:
dum->port_status |= (1 << wValue);
@@ -1542,7 +1510,7 @@
break;
default:
- dev_dbg (dummy_dev(dum),
+ dev_dbg (hardware,
"hub control req%04x v%04x i%04x l%d\n",
typeReq, wValue, wIndex, wLength);
@@ -1562,12 +1530,20 @@
dum = kmalloc (sizeof *dum, SLAB_KERNEL);
if (dum == NULL)
- return NULL;
- the_controller = dum;
+ return 0;
memset (dum, 0, sizeof *dum);
return &dum->hcd;
}
+static void dummy_free (struct usb_hcd *hcd)
+{
+ struct dummy *dum;
+
+ dum = container_of (hcd, struct dummy, hcd);
+ WARN_ON (dum->driver != 0);
+ kfree (dum);
+}
+
/*-------------------------------------------------------------------------*/
static inline ssize_t
@@ -1599,8 +1575,7 @@
static ssize_t
show_urbs (struct device *dev, char *buf)
{
- struct usb_hcd *hcd = dev_get_drvdata (dev);
- struct dummy *dum = hcd_to_dummy (hcd);
+ struct dummy *dum = dev_get_drvdata(dev);
struct urb *urb;
size_t size = 0;
unsigned long flags;
@@ -1623,13 +1598,17 @@
}
static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
+
+static const struct hc_driver dummy_hcd;
+
static int dummy_start (struct usb_hcd *hcd)
{
struct dummy *dum;
+ struct usb_bus *bus;
struct usb_device *root;
int retval;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
/*
* MASTER side init ... we emulate a root hub that'll only ever
@@ -1638,56 +1617,121 @@
*/
spin_lock_init (&dum->lock);
+ retval = driver_register (&dummy_driver);
+ if (retval < 0)
+ return retval;
+
+ dum->pdev.name = "hc";
+ dum->pdev.dev.driver = &dummy_driver;
+ dev_set_drvdata(&dum->pdev.dev, dum);
+ dum->pdev.dev.release = dummy_hc_release;
+ retval = platform_device_register (&dum->pdev);
+ if (retval < 0) {
+ driver_unregister (&dummy_driver);
+ return retval;
+ }
+ dev_info (&dum->pdev.dev, "%s, driver " DRIVER_VERSION "\n",
+ driver_desc);
+
+ hcd->self.controller = &dum->pdev.dev;
+
+ /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+ device_create_file (hcd->self.controller, &dev_attr_urbs);
+
init_timer (&dum->timer);
dum->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum;
- root = usb_alloc_dev (0, &hcd->self, 0);
- if (!root)
- return -ENOMEM;
+ /* root hub will appear as another device */
+ dum->hcd.driver = (struct hc_driver *) &dummy_hcd;
+ dum->hcd.description = dummy_hcd.description;
+ dum->hcd.product_desc = "Dummy host controller";
+
+ bus = hcd_to_bus (&dum->hcd);
+ bus->bus_name = dum->pdev.dev.bus_id;
+ usb_bus_init (bus);
+ bus->op = &usb_hcd_operations;
+ bus->hcpriv = &dum->hcd;
+
+ /* FIXME don't require the pci-based buffer/alloc impls;
+ * the "generic dma" implementation still requires them,
+ * it's not very generic yet.
+ */
+ if ((retval = hcd_buffer_create (&dum->hcd)) != 0) {
+clean0:
+ init_completion (&dum->released);
+ platform_device_unregister (&dum->pdev);
+ wait_for_completion (&dum->released);
+ driver_unregister (&dummy_driver);
+ return retval;
+ }
+
+ INIT_LIST_HEAD (&hcd->dev_list);
+ usb_register_bus (bus);
+
+ root = usb_alloc_dev (0, bus, 0);
+ if (!root) {
+ retval = -ENOMEM;
+clean1:
+ hcd_buffer_destroy (&dum->hcd);
+ usb_deregister_bus (bus);
+ goto clean0;
+ }
/* root hub enters addressed state... */
- hcd->state = USB_STATE_RUNNING;
+ dum->hcd.state = USB_STATE_RUNNING;
root->speed = USB_SPEED_HIGH;
/* ...then configured, so khubd sees us. */
- if ((retval = hcd_register_root (root, hcd)) != 0) {
+ if ((retval = hcd_register_root (root, &dum->hcd)) != 0) {
usb_put_dev (root);
-clean:
- hcd->state = USB_STATE_QUIESCING;
- return retval;
+clean2:
+ dum->hcd.state = USB_STATE_QUIESCING;
+ goto clean1;
}
/* only show a low-power port: just 8mA */
hub_set_power_budget (root, 8);
+ dum->started = 1;
+
if ((retval = dummy_register_udc (dum)) != 0) {
- usb_disconnect (&hcd->self.root_hub);
- goto clean;
+ dum->started = 0;
+ usb_disconnect (&bus->root_hub);
+ goto clean2;
}
-
- /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
- device_create_file (dummy_dev(dum), &dev_attr_urbs);
-
- dum->started = 1;
return 0;
}
static void dummy_stop (struct usb_hcd *hcd)
{
struct dummy *dum;
+ struct usb_bus *bus;
- dum = hcd_to_dummy (hcd);
+ dum = container_of (hcd, struct dummy, hcd);
if (!dum->started)
return;
dum->started = 0;
- device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-
usb_gadget_unregister_driver (dum->driver);
dummy_unregister_udc (dum);
- dev_info (dummy_dev(dum), "stopped\n");
+ bus = hcd_to_bus (&dum->hcd);
+ hcd->state = USB_STATE_QUIESCING;
+ dev_dbg (hardware, "remove root hub\n");
+ usb_disconnect (&bus->root_hub);
+
+ hcd_buffer_destroy (&dum->hcd);
+ usb_deregister_bus (bus);
+
+ dev_info (hardware, "stopped\n");
+
+ device_remove_file (hcd->self.controller, &dev_attr_urbs);
+ init_completion (&dum->released);
+ platform_device_unregister (&dum->pdev);
+ wait_for_completion (&dum->released);
+
+ driver_unregister (&dummy_driver);
}
/*-------------------------------------------------------------------------*/
@@ -1705,6 +1749,7 @@
.stop = dummy_stop,
.hcd_alloc = dummy_alloc,
+ .hcd_free = dummy_free,
.urb_enqueue = dummy_urb_enqueue,
.urb_dequeue = dummy_urb_dequeue,
@@ -1715,128 +1760,34 @@
.hub_control = dummy_hub_control,
};
-static void dummy_remove (struct device *dev);
+/*-------------------------------------------------------------------------*/
-static int dummy_probe (struct device *dev)
+static int __init init (void)
{
struct usb_hcd *hcd;
- struct dummy *dum;
- int retval;
-
- dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
+ int value;
- hcd = dummy_alloc ();
- if (hcd == NULL) {
- dev_dbg (dev, "hcd_alloc failed\n");
+ if (usb_disabled ())
+ return -ENODEV;
+ if ((hcd = dummy_alloc ()) == 0)
return -ENOMEM;
- }
-
- dev_set_drvdata (dev, hcd);
- dum = hcd_to_dummy (hcd);
-
- hcd->driver = (struct hc_driver *) &dummy_hcd;
- hcd->description = dummy_hcd.description;
- hcd->self.controller = dev;
-
- /* FIXME don't require the pci-based buffer/alloc impls;
- * the "generic dma" implementation still requires them,
- * it's not very generic yet.
- */
- retval = hcd_buffer_create (hcd);
- if (retval != 0) {
- dev_dbg (dev, "pool alloc failed\n");
- goto err1;
- }
-
- usb_bus_init (&hcd->self);
- hcd->self.op = &usb_hcd_operations;
- hcd->self.release = &usb_hcd_release;
- hcd->self.hcpriv = hcd;
- hcd->self.bus_name = dev->bus_id;
- hcd->product_desc = "Dummy host controller";
-
- INIT_LIST_HEAD (&hcd->dev_list);
-
- usb_register_bus (&hcd->self);
-
- if ((retval = dummy_start (hcd)) < 0)
- dummy_remove (dev);
- return retval;
-
-err1:
- kfree (hcd);
- dev_set_drvdata (dev, NULL);
- return retval;
-}
-static void dummy_remove (struct device *dev)
-{
- struct usb_hcd *hcd;
- struct dummy *dum;
-
- hcd = dev_get_drvdata (dev);
- dum = hcd_to_dummy (hcd);
-
- hcd->state = USB_STATE_QUIESCING;
-
- dev_dbg (dev, "roothub graceful disconnect\n");
- usb_disconnect (&hcd->self.root_hub);
-
- hcd->driver->stop (hcd);
- hcd->state = USB_STATE_HALT;
-
- hcd_buffer_destroy (hcd);
-
- dev_set_drvdata (dev, NULL);
- usb_deregister_bus (&hcd->self);
- the_controller = NULL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int dummy_pdev_detect (void)
-{
- int retval;
-
- retval = driver_register (&dummy_driver);
- if (retval < 0)
- return retval;
+ the_controller = container_of (hcd, struct dummy, hcd);
+ value = dummy_start (hcd);
- the_pdev.name = "hc";
- the_pdev.dev.driver = &dummy_driver;
- the_pdev.dev.release = dummy_pdev_release;
-
- retval = platform_device_register (&the_pdev);
- if (retval < 0)
- driver_unregister (&dummy_driver);
- return retval;
-}
-
-static void dummy_pdev_remove (void)
-{
- platform_device_unregister (&the_pdev);
- driver_unregister (&dummy_driver);
+ if (value != 0) {
+ dummy_free (hcd);
+ the_controller = 0;
}
-
-/*-------------------------------------------------------------------------*/
-
-static int __init init (void)
-{
- int retval;
-
- if (usb_disabled ())
- return -ENODEV;
- if ((retval = dummy_pdev_detect ()) != 0)
- return retval;
- if ((retval = dummy_probe (&the_pdev.dev)) != 0)
- dummy_pdev_remove ();
- return retval;
+ return value;
}
module_init (init);
static void __exit cleanup (void)
{
- dummy_remove (&the_pdev.dev);
- dummy_pdev_remove ();
+ dummy_stop (&the_controller->hcd);
+ dummy_free (&the_controller->hcd);
+ the_controller = 0;
}
module_exit (cleanup);
+
diff -wur linux-2.6.10/drivers/usb/gadget/ether.c linux-2.6.10-lab/drivers/usb/gadget/ether.c
--- linux-2.6.10/drivers/usb/gadget/ether.c 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/ether.c 2007-10-04 19:10:29.000000000 -0400
@@ -84,7 +84,7 @@
*/
#define DRIVER_DESC "Ethernet Gadget"
-#define DRIVER_VERSION "Equinox 2004"
+#define DRIVER_VERSION "St Patrick's Day 2004"
static const char shortname [] = "ether";
static const char driver_desc [] = DRIVER_DESC;
@@ -223,10 +223,6 @@
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_LH7A40X
-#define DEV_CONFIG_CDC
-#endif
-
#ifdef CONFIG_USB_GADGET_MQ11XX
#define DEV_CONFIG_CDC
#endif
@@ -235,14 +231,6 @@
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_N9604
-#define DEV_CONFIG_CDC
-#endif
-
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define DEV_CONFIG_CDC
-#endif
-
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -255,6 +243,10 @@
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_LH7A40X
+#define DEV_CONFIG_CDC
+#endif
+
#ifdef CONFIG_USB_GADGET_SA1100
/* use non-CDC for backwards compatibility */
#define DEV_CONFIG_SUBSET
@@ -395,7 +387,7 @@
.bConfigurationValue = DEV_CONFIG_VALUE,
.iConfiguration = STRING_CDC,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 50,
+ .bMaxPower = 1,
};
#ifdef CONFIG_USB_ETH_RNDIS
@@ -409,7 +401,7 @@
.bConfigurationValue = DEV_RNDIS_CONFIG_VALUE,
.iConfiguration = STRING_RNDIS,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 50,
+ .bMaxPower = 1,
};
#endif
@@ -860,7 +852,7 @@
/* descriptors that are built on-demand */
-static char manufacturer [50];
+static char manufacturer [40];
static char product_desc [40] = DRIVER_DESC;
#ifdef DEV_CONFIG_CDC
@@ -1206,20 +1198,13 @@
result = -EINVAL;
/* FALL THROUGH */
case 0:
- break;
+ return result;
}
- if (result) {
- if (number)
+ if (result)
eth_reset_config (dev);
- usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
- } else {
+ else {
char *speed;
- unsigned power;
-
- power = 2 * eth_config.bMaxPower;
- usb_gadget_vbus_draw(dev->gadget, power);
switch (gadget->speed) {
case USB_SPEED_FULL: speed = "full"; break;
@@ -1230,8 +1215,8 @@
}
dev->config = number;
- INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
- speed, number, power, driver_desc,
+ INFO (dev, "%s speed config #%d: %s, using %s\n",
+ speed, number, driver_desc,
dev->rndis
? "RNDIS"
: (dev->cdc
@@ -1390,8 +1375,7 @@
static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
- DEBUG ((struct eth_dev *) ep->driver_data,
- "rndis response complete --> %d, %d/%d\n",
+ DEBUG (dev, "rndis response complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
/* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
@@ -1686,7 +1670,7 @@
static int eth_change_mtu (struct net_device *net, int new_mtu)
{
- struct eth_dev *dev = netdev_priv(net);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
// FIXME if rndis, don't change while link's live
@@ -1701,28 +1685,57 @@
static struct net_device_stats *eth_get_stats (struct net_device *net)
{
- return &((struct eth_dev *)netdev_priv(net))->stats;
+ return &((struct eth_dev *) net->priv)->stats;
}
-static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
+static int eth_ethtool_ioctl (struct net_device *net, void __user *useraddr)
{
- struct eth_dev *dev = netdev_priv(net);
- strlcpy(p->driver, shortname, sizeof p->driver);
- strlcpy(p->version, DRIVER_VERSION, sizeof p->version);
- strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
- strlcpy (p->bus_info, dev->gadget->dev.bus_id, sizeof p->bus_info);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+ u32 cmd;
+
+ if (get_user (cmd, (u32 __user *)useraddr))
+ return -EFAULT;
+ switch (cmd) {
+
+ case ETHTOOL_GDRVINFO: { /* get driver info */
+ struct ethtool_drvinfo info;
+
+ memset (&info, 0, sizeof info);
+ info.cmd = ETHTOOL_GDRVINFO;
+ strlcpy (info.driver, shortname, sizeof info.driver);
+ strlcpy (info.version, DRIVER_VERSION, sizeof info.version);
+ strlcpy (info.fw_version, dev->gadget->name,
+ sizeof info.fw_version);
+ strlcpy (info.bus_info, dev->gadget->dev.bus_id,
+ sizeof info.bus_info);
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
}
-static u32 eth_get_link(struct net_device *net)
-{
- struct eth_dev *dev = netdev_priv(net);
- return dev->gadget->speed != USB_SPEED_UNKNOWN;
+ case ETHTOOL_GLINK: { /* get link status */
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+
+ edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN);
+ if (copy_to_user (useraddr, &edata, sizeof (edata)))
+ return -EFAULT;
+ return 0;
}
-static struct ethtool_ops ops = {
- .get_drvinfo = eth_get_drvinfo,
- .get_link = eth_get_link
-};
+ }
+ /* Note that the ethtool user space code requires EOPNOTSUPP */
+ return -EOPNOTSUPP;
+}
+
+static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+ switch (cmd) {
+ case SIOCETHTOOL:
+ return eth_ethtool_ioctl(net, rq->ifr_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
static void defer_kevent (struct eth_dev *dev, int flag)
{
@@ -1984,7 +1997,7 @@
static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
{
- struct eth_dev *dev = netdev_priv(net);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
int length = skb->len;
int retval;
struct usb_request *req = NULL;
@@ -2085,12 +2098,10 @@
}
}
-static void
-rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
+static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
- DEBUG ((struct eth_dev *) ep->driver_data,
- "rndis control ack complete --> %d, %d/%d\n",
+ DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
usb_ep_free_buffer(ep, req->buf, req->dma, 8);
@@ -2099,7 +2110,7 @@
static int rndis_control_ack (struct net_device *net)
{
- struct eth_dev *dev = netdev_priv(net);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
u32 length;
struct usb_request *resp;
@@ -2166,7 +2177,7 @@
static int eth_open (struct net_device *net)
{
- struct eth_dev *dev = netdev_priv(net);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
DEBUG (dev, "%s\n", __FUNCTION__);
if (netif_carrier_ok (dev->net))
@@ -2176,7 +2187,7 @@
static int eth_stop (struct net_device *net)
{
- struct eth_dev *dev = netdev_priv(net);
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
VDEBUG (dev, "%s\n", __FUNCTION__);
netif_stop_queue (net);
@@ -2187,7 +2198,7 @@
);
/* ensure there are no more active requests */
- if (dev->config) {
+ if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
usb_ep_disable (dev->in_ep);
usb_ep_disable (dev->out_ep);
if (netif_carrier_ok (dev->net)) {
@@ -2323,10 +2334,6 @@
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
- } else if (gadget_is_n9604(gadget)) {
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
- } else if (gadget_is_pxa27x(gadget)) {
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
} else {
/* can't assume CDC works. don't want to default to
* anything less functional on CDC-capable hardware,
@@ -2459,17 +2466,15 @@
if (gadget->is_otg) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- eth_config.bMaxPower = 4;
#ifdef CONFIG_USB_ETH_RNDIS
rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- rndis_config.bMaxPower = 4;
#endif
}
net = alloc_etherdev (sizeof *dev);
if (!net)
return status;
- dev = netdev_priv(net);
+ dev = net->priv;
spin_lock_init (&dev->lock);
INIT_WORK (&dev->work, eth_work, dev);
INIT_LIST_HEAD (&dev->tx_reqs);
@@ -2513,7 +2518,7 @@
net->stop = eth_stop;
// watchdog_timeo, tx_timeout ...
// set_multicast_list
- SET_ETHTOOL_OPS(net, &ops);
+ net->do_ioctl = eth_ioctl;
/* preallocate control response and buffer */
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
diff -wur linux-2.6.10/drivers/usb/gadget/file_storage.c linux-2.6.10-lab/drivers/usb/gadget/file_storage.c
--- linux-2.6.10/drivers/usb/gadget/file_storage.c 2004-12-24 16:36:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/file_storage.c 2007-10-04 19:10:29.000000000 -0400
@@ -95,6 +95,7 @@
* USB device controller (usually true),
* boolean to permit the driver to halt
* bulk endpoints
+ * max_current Default 100 (mA), max current draw (e.g. 500)
*
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
* "removable", and "luns" options are available; default values are used
@@ -217,7 +218,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -235,7 +235,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -245,12 +244,19 @@
#include "gadget_chips.h"
+#ifdef CONFIG_ARCH_FIONA
+#include
+#include
+#include
+#include
+#endif
+
/*-------------------------------------------------------------------------*/
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "20 October 2004"
+#define DRIVER_VERSION "28 July 2004"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -259,6 +265,18 @@
MODULE_AUTHOR("Alan Stern");
MODULE_LICENSE("Dual BSD/GPL");
+#ifdef CONFIG_ARCH_FIONA
+
+#define DRIVER_VENDOR_ID 0x1949 // Lab126
+#define DRIVER_PRODUCT_ID 0x0001 // Fiona
+
+#define DRIVER_VENDOR_ID_STR "Kindle"
+#define DRIVER_PROD_STR_FLASH "Internal Storage"
+#define DRIVER_PROD_STR_CARD "Card Storage"
+static const char productname[] = "Amazon Kindle";
+
+#else
+
/* Thanks to NetChip Technologies for donating this product ID.
*
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
@@ -266,6 +284,7 @@
#define DRIVER_VENDOR_ID 0x0525 // NetChip
#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
+#endif
/*
* This driver assumes self-powered hardware and has no way for users to
@@ -283,11 +302,11 @@
#ifdef DEBUG
#define DBG(fsg,fmt,args...) \
- xprintk(fsg , KERN_DEBUG , fmt , ## args)
+ xprintk(fsg , KERN_CRIT , fmt , ## args)
#define LDBG(lun,fmt,args...) \
- yprintk(lun , KERN_DEBUG , fmt , ## args)
+ yprintk(lun , KERN_CRIT , fmt , ## args)
#define MDBG(fmt,args...) \
- printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
+ printk(KERN_CRIT DRIVER_NAME ": " fmt , ## args)
#else
#define DBG(fsg,fmt,args...) \
do { } while (0)
@@ -334,13 +353,13 @@
#define MAX_LUNS 8
- /* Arggh! There should be a module_param_array_named macro! */
-static char *file[MAX_LUNS] = {NULL, };
-static int ro[MAX_LUNS] = {0, };
+static const char *file[MAX_LUNS] = {NULL, };
+static const int ro[MAX_LUNS] = {0, };
static struct {
int num_filenames;
int num_ros;
+
unsigned int nluns;
char *transport_parm;
@@ -356,7 +375,10 @@
char *transport_name;
int protocol_type;
char *protocol_name;
-
+#ifdef CONFIG_ARCH_FIONA
+ char *serial_number;
+ unsigned int max_current;
+#endif
} mod_data = { // Default values
.transport_parm = "BBB",
.protocol_parm = "SCSI",
@@ -366,13 +388,17 @@
.release = 0xffff, // Use controller chip type
.buflen = 16384,
.can_stall = 1,
+#ifdef CONFIG_ARCH_FIONA
+ .serial_number = "Unknown",
+ .max_current = 100,
+#endif
};
-module_param_array(file, charp, &mod_data.num_filenames, S_IRUGO);
+module_param_array_named(file, file, charp, &mod_data.num_filenames, S_IRUGO);
MODULE_PARM_DESC(file, "names of backing files or devices");
-module_param_array(ro, bool, &mod_data.num_ros, S_IRUGO);
+module_param_array_named(ro, &ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only");
module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
@@ -408,6 +434,14 @@
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+#ifdef CONFIG_ARCH_FIONA
+module_param_named(serial_number, mod_data.serial_number, charp, S_IRUGO);
+MODULE_PARM_DESC(serial_number, "device serial number string");
+
+module_param_named(max_current, mod_data.max_current, uint, S_IRUGO);
+MODULE_PARM_DESC(max_current, "maximum current draw (in mA)");
+#endif
+
#endif /* CONFIG_USB_FILE_STORAGE_TEST */
@@ -430,9 +464,9 @@
/* Command Block Wrapper */
struct bulk_cb_wrap {
- __le32 Signature; // Contains 'USBC'
+ u32 Signature; // Contains 'USBC'
u32 Tag; // Unique per command id
- __le32 DataTransferLength; // Size of the data
+ u32 DataTransferLength; // Size of the data
u8 Flags; // Direction in bit 7
u8 Lun; // LUN (normally 0)
u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE
@@ -445,9 +479,9 @@
/* Command Status Wrapper */
struct bulk_cs_wrap {
- __le32 Signature; // Should = 'USBS'
+ u32 Signature; // Should = 'USBS'
u32 Tag; // Same as original command
- __le32 Residue; // Amount not transferred
+ u32 Residue; // Amount not transferred
u8 Status; // See below
};
@@ -554,6 +588,10 @@
unsigned int ro : 1;
unsigned int prevent_medium_removal : 1;
unsigned int registered : 1;
+#ifdef CONFIG_ARCH_FIONA
+ unsigned int syncwrite : 1;
+ unsigned int activity : 1;
+#endif
u32 sense_data;
u32 sense_data_info;
@@ -711,9 +749,11 @@
unsigned int rem;
bh->bulk_out_intended_length = length;
+ if (length != 31) {
rem = length % fsg->bulk_out_maxpacket;
if (rem > 0)
length += fsg->bulk_out_maxpacket - rem;
+ }
bh->outreq->length = length;
}
@@ -865,15 +905,7 @@
.bNumInterfaces = 1,
.bConfigurationValue = CONFIG_VALUE,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1, // self-powered
-};
-
-static struct usb_otg_descriptor
-otg_desc = {
- .bLength = sizeof(otg_desc),
- .bDescriptorType = USB_DT_OTG,
-
- .bmAttributes = USB_OTG_SRP,
+ .bMaxPower = (100/2), // module init overrides this
};
/* There is only one interface. */
@@ -924,14 +956,12 @@
};
static const struct usb_descriptor_header *fs_function[] = {
- (struct usb_descriptor_header *) &otg_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_bulk_in_desc,
(struct usb_descriptor_header *) &fs_bulk_out_desc,
(struct usb_descriptor_header *) &fs_intr_in_desc,
NULL,
};
-#define FS_FUNCTION_PRE_EP_ENTRIES 2
#ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -988,14 +1018,12 @@
};
static const struct usb_descriptor_header *hs_function[] = {
- (struct usb_descriptor_header *) &otg_desc,
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_bulk_in_desc,
(struct usb_descriptor_header *) &hs_bulk_out_desc,
(struct usb_descriptor_header *) &hs_intr_in_desc,
NULL,
};
-#define HS_FUNCTION_PRE_EP_ENTRIES 2
/* Maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
@@ -1010,14 +1038,23 @@
/* The CBI specification limits the serial string to 12 uppercase hexadecimal
* characters. */
-static char manufacturer[50];
+static char manufacturer[40];
+#ifdef CONFIG_ARCH_FIONA
+static char serial[40];
+#else
static char serial[13];
+#endif
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
static struct usb_string strings[] = {
{STRING_MANUFACTURER, manufacturer},
+#ifdef CONFIG_ARCH_FIONA
+ {STRING_PRODUCT, productname},
+ {STRING_SERIAL, serial},
+#else
{STRING_PRODUCT, longname},
{STRING_SERIAL, serial},
+#endif
{}
};
@@ -1032,12 +1069,9 @@
* and with code managing interfaces and their altsettings. They must
* also handle different speeds and other-speed requests.
*/
-static int populate_config_buf(struct usb_gadget *gadget,
+static int populate_config_buf(enum usb_device_speed speed,
u8 *buf, u8 type, unsigned index)
{
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- enum usb_device_speed speed = gadget->speed;
-#endif
int len;
const struct usb_descriptor_header **function;
@@ -1053,10 +1087,6 @@
#endif
function = fs_function;
- /* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
- function++;
-
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
@@ -1080,17 +1110,24 @@
unsigned long flags;
struct task_struct *thread_task;
+DBG(fsg,"<1>%s: new_state = %d\n", __FUNCTION__, new_state);
+
/* Do nothing if a higher-priority exception is already in progress.
* If a lower-or-equal priority exception is in progress, preempt it
* and notify the main thread by sending it a signal. */
spin_lock_irqsave(&fsg->lock, flags);
+DBG(fsg,"<1>%s: after spin_lock_irqsave - fsg->state = %d\n", __FUNCTION__,
+ fsg->state);
if (fsg->state <= new_state) {
+DBG(fsg,"<1>%s: interesting new_state\n", __FUNCTION__);
fsg->exception_req_tag = fsg->ep0_req_tag;
fsg->state = new_state;
thread_task = fsg->thread_task;
- if (thread_task)
+ if (thread_task) {
+DBG(fsg,"<1>%s: signaling thread_task (0x%p)\n", __FUNCTION__, thread_task);
send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task);
}
+ }
spin_unlock_irqrestore(&fsg->lock, flags);
}
@@ -1283,7 +1320,8 @@
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (ctrl->wIndex != 0) {
+ if ((ctrl->wValue != 0) || (ctrl->wIndex != 0) ||
+ (ctrl->wLength != 0)) {
value = -EDOM;
break;
}
@@ -1299,7 +1337,8 @@
if (ctrl->bRequestType != (USB_DIR_IN |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
- if (ctrl->wIndex != 0) {
+ if ((ctrl->wValue != 0) || (ctrl->wIndex != 0) ||
+ (ctrl->wLength != 1)) {
value = -EDOM;
break;
}
@@ -1387,7 +1426,7 @@
#ifdef CONFIG_USB_GADGET_DUALSPEED
get_config:
#endif
- value = populate_config_buf(fsg->gadget,
+ value = populate_config_buf(fsg->gadget->speed,
req->buf,
ctrl->wValue >> 8,
ctrl->wValue & 0xff);
@@ -1412,14 +1451,31 @@
if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
USB_RECIP_DEVICE))
break;
- VDBG(fsg, "set configuration\n");
+ DBG(fsg, "set configuration\n");
+ if (ctrl->wValue == fsg->config) {
+ /* No change in configuration, just acknowledge */
+ value = 0;
+ break;
+ }
if (ctrl->wValue == CONFIG_VALUE || ctrl->wValue == 0) {
+ unsigned int power;
+
fsg->new_config = ctrl->wValue;
/* Raise an exception to wipe out previous transaction
* state (queued bufs, etc) and set the new config. */
raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
value = DELAYED_STATUS;
+
+ if (ctrl->wValue)
+#ifdef CONFIG_ARCH_FIONA
+ power = mod_data.max_current;
+#else
+ power = 100;
+#endif
+ else
+ power = 100;
+ usb_gadget_vbus_draw(fsg->gadget, power);
}
break;
case USB_REQ_GET_CONFIGURATION:
@@ -1543,16 +1599,231 @@
/* Wait until a signal arrives or we are woken up */
rc = wait_event_interruptible(fsg->thread_wqh,
fsg->thread_wakeup_needed);
+
+#if defined(CONFIG_PM) || defined(CONFIG_FIONA_PM)
+ // Check for sleep request
+ if (current->flags & PF_FREEZE) {
+ refrigerator(PF_FREEZE);
+ }
+#endif
+
fsg->thread_wakeup_needed = 0;
+ return (rc ? -EINTR : 0);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_FIONA
+static int do_real_read(struct fsg_dev *fsg);
+static int do_real_write(struct fsg_dev *fsg);
+
+#define LUN_INTERNAL 0
+#define LUN_EXTERNAL 1
+
+#define SET_PNLCD_ACTIVITY_READ(l) (int)((LUN_INTERNAL == l) ? sp_animation_usb_internal_read : sp_animation_usb_external_read)
+#define SET_PNLCD_ACTIVITY_WRITE(l) (int)((LUN_INTERNAL == l) ? sp_animation_usb_internal_write : sp_animation_usb_external_write)
+
+#define GLOBAL_ACTIVITY(l, a) (((l << 1) | a) + 1)
+
+#define ACTIVITY_THREAD_NAME "f-s-activity"
+#define ACTIVITY_TIMEOUT HZ
+
+#define ACTIVITY_RATE 2
+
+enum activity_t
+{
+ activity_read = 0,
+ activity_write
+};
+typedef enum activity_t activity_t;
+
+enum activity_state_t
+{
+ activity_state_start = 0,
+ activity_state_stop
+};
+typedef enum activity_state_t activity_state_t;
+
+enum global_activity_t
+{
+ activity_internal_read = GLOBAL_ACTIVITY(LUN_INTERNAL, activity_read),
+ activity_internal_write = GLOBAL_ACTIVITY(LUN_INTERNAL, activity_write),
+
+ activity_external_read = GLOBAL_ACTIVITY(LUN_EXTERNAL, activity_read),
+ activity_external_write = GLOBAL_ACTIVITY(LUN_EXTERNAL, activity_write),
+
+ activity_idle = 0
+};
+typedef enum global_activity_t global_activity_t;
+
+static global_activity_t last_activity = activity_idle;
+
+static int activity_pending = 0;
+static pid_t activity_pid = 0;
+static wait_queue_head_t activity_wq;
+
+static DECLARE_COMPLETION(activity_thread_exited);
+
+static int activity_thread(void *unused)
+{
+ int thread_active = 1;
+
+ daemonize(ACTIVITY_THREAD_NAME);
+ allow_signal(SIGKILL);
+
+ while ( thread_active )
+ {
+#ifdef CONFIG_PM
if (current->flags & PF_FREEZE)
refrigerator(PF_FREEZE);
- return (rc ? -EINTR : 0);
+#endif
+
+ if ( !signal_pending(current) )
+ {
+ unsigned long timeout_time = ACTIVITY_TIMEOUT;
+
+ if ( !activity_pending )
+ {
+ if ( activity_idle != last_activity )
+ {
+ pnlcd_animation_t pnlcd_animation = { stop_animation, 0 };
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_animation);
+
+ last_activity = activity_idle;
+ }
+
+ timeout_time = MAX_SCHEDULE_TIMEOUT;
+ }
+ else
+ activity_pending = 0;
+
+ interruptible_sleep_on_timeout(&activity_wq, timeout_time);
+ }
+ else
+ thread_active = 0;
+ }
+
+ complete_and_exit(&activity_thread_exited, 0);
+}
+
+static void start_activity_thread(void)
+{
+ init_waitqueue_head(&activity_wq);
+
+ if ( 0 > (activity_pid = kernel_thread(activity_thread, NULL, CLONE_KERNEL)) )
+ activity_pid = 0;
+}
+
+static void stop_activity_thread(void)
+{
+ if ( 0 < activity_pid )
+ if ( 0 == kill_proc(activity_pid, SIGKILL, 1) )
+ wait_for_completion(&activity_thread_exited);
+}
+
+static void prime_activity_thread(void)
+{
+ activity_pending = 1;
+ wake_up(&activity_wq);
}
+static void switch_activity(unsigned int lun, activity_t which_activity, activity_state_t activity_state)
+{
+ pnlcd_animation_t pnlcd_animation = { stop_animation, 0 };
+
+ // Stop the current activity, if any.
+ //
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_animation);
+
+ // Start the new activity if specified.
+ //
+ if ( activity_state_start == activity_state )
+ {
+ // Specify the activity type.
+ //
+ pnlcd_animation.cmd = set_animation_type;
+
+ switch ( which_activity )
+ {
+ case activity_read:
+ pnlcd_animation.arg = SET_PNLCD_ACTIVITY_READ(lun);
+ break;
+
+ case activity_write:
+ pnlcd_animation.arg = SET_PNLCD_ACTIVITY_WRITE(lun);
+ break;
+ }
+
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_animation);
+
+ // Start it up.
+ //
+ pnlcd_animation.cmd = set_animation_rate;
+ pnlcd_animation.arg = ACTIVITY_RATE;
+
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_animation);
+
+ pnlcd_animation.cmd = start_animation;
+ pnlcd_animation.arg = pnlcd_animation_auto;
+
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_animation);
+ }
+}
+
+static void do_activity(unsigned int lun, activity_t which_activity, activity_state_t activity_state)
+{
+ global_activity_t next_activity = GLOBAL_ACTIVITY(lun, which_activity);
+
+ // Re-prime our activity thread so that we don't time out during actual activity.
+ //
+ prime_activity_thread();
+
+ // If the next activity isn't the same as the last one, switch activity.
+ //
+ if ( next_activity != last_activity )
+ {
+ switch_activity(lun, which_activity, activity_state);
+ last_activity = next_activity;
+ }
+}
+
+static int do_read_write_activity(struct fsg_dev *fsg, activity_t which_activity)
+{
+ struct lun *curlun = fsg->curlun;
+ unsigned int lun_id = fsg->lun,
+ activity = curlun->activity && get_drivemode_screen_ready();
+ int result;
+
+ if ( activity )
+ do_activity(lun_id, which_activity, activity_state_start);
+
+ result = (activity_read == which_activity) ? do_real_read(fsg) : do_real_write(fsg);
+
+// if ( activity )
+// do_activity(lun_id, which_activity, activity_state_stop);
+
+ return ( result );
+}
+
+static int do_read(struct fsg_dev *fsg)
+{
+ return ( do_read_write_activity(fsg, activity_read) );
+}
+
+static int do_write(struct fsg_dev *fsg)
+{
+ return ( do_read_write_activity(fsg, activity_write) );
+}
+#endif
+
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_ARCH_FIONA
+static int do_real_read(struct fsg_dev *fsg)
+#else
static int do_read(struct fsg_dev *fsg)
+#endif
{
struct lun *curlun = fsg->curlun;
u32 lba;
@@ -1584,6 +1855,8 @@
return -EINVAL;
}
file_offset = ((loff_t) lba) << 9;
+//DBG(fsg,"<1>%s: lba=0x%08X, file_offset=0x%08X\n", __FUNCTION__,
+// lba, file_offset);
/* Carry out the file reads */
amount_left = fsg->data_size_from_cmnd;
@@ -1675,7 +1948,11 @@
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_ARCH_FIONA
+static int do_real_write(struct fsg_dev *fsg)
+#else
static int do_write(struct fsg_dev *fsg)
+#endif
{
struct lun *curlun = fsg->curlun;
u32 lba;
@@ -1717,6 +1994,13 @@
return -EINVAL;
}
+#ifdef CONFIG_ARCH_FIONA
+ if (curlun->syncwrite) {
+ /* force synchronous writes to the internal flash */
+ curlun->filp->f_flags |= O_SYNC;
+ }
+#endif
+
/* Carry out the file writes */
get_some_more = 1;
file_offset = usb_offset = ((loff_t) lba) << 9;
@@ -2016,8 +2300,14 @@
{
u8 *buf = (u8 *) bh->buf;
+#ifdef CONFIG_ARCH_FIONA
+ static char vendor_id[] = DRIVER_VENDOR_ID_STR;
+ static char prod_id_flash[] = DRIVER_PROD_STR_FLASH;
+ static char prod_id_card[] = DRIVER_PROD_STR_CARD;
+#else
static char vendor_id[] = "Linux ";
static char product_id[] = "File-Stor Gadget";
+#endif
if (!fsg->curlun) { // Unsupported LUNs are okay
fsg->bad_lun_okay = 1;
@@ -2033,8 +2323,14 @@
buf[3] = 2; // SCSI-2 INQUIRY data format
buf[4] = 31; // Additional length
// No special options
+#ifdef CONFIG_ARCH_FIONA
+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
+ fsg->lun ? prod_id_card : prod_id_flash,
+ mod_data.release);
+#else
sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,
mod_data.release);
+#endif
return 36;
}
@@ -2303,8 +2599,10 @@
}
/* Wait for a short time and then try again */
- if (msleep_interruptible(100) != 0)
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (schedule_timeout(HZ / 10) != 0)
return -EINTR;
+DBG(fsg,"<1>file_storage.c:halt_bulk_in_endpoint(): usb_ep_set_halt\n");
rc = usb_ep_set_halt(fsg->bulk_in);
}
return rc;
@@ -2404,6 +2702,7 @@
case DATA_DIR_UNKNOWN:
if (mod_data.can_stall) {
fsg_set_halt(fsg, fsg->bulk_out);
+DBG(fsg,"<1>calling halt_bulk_in_endpoint case DATA_DIR_UNKNOWN\n");
rc = halt_bulk_in_endpoint(fsg);
}
break;
@@ -2432,6 +2731,7 @@
fsg->residue == fsg->data_size &&
(!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
bh->state = BUF_STATE_EMPTY;
+DBG(fsg,"<1>calling halt_bulk_in_endpoint case DATA_DIR_TO_HOST not bbb\n");
rc = halt_bulk_in_endpoint(fsg);
} else {
bh->inreq->zero = 1;
@@ -2450,6 +2750,7 @@
start_transfer(fsg, fsg->bulk_in, bh->inreq,
&bh->inreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
+DBG(fsg,"<1>calling halt_bulk_in_endpoint case DATA_DIR_TO_HOST bbb\n");
rc = halt_bulk_in_endpoint(fsg);
} else
rc = pad_with_zeros(fsg);
@@ -2520,7 +2821,7 @@
status = USB_STATUS_PHASE_ERROR;
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
- DBG(fsg, "sending command-failure status\n");
+ VDBG(fsg, "sending command-failure status\n");
status = USB_STATUS_FAIL;
VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
@@ -2654,7 +2955,7 @@
/* Check that the LUN values are oonsistent */
if (transport_is_bbb()) {
if (fsg->lun != lun)
- DBG(fsg, "using LUN %d from CBW, "
+ VDBG(fsg, "using LUN %d from CBW, "
"not LUN %d from CDB\n",
fsg->lun, lun);
} else
@@ -2962,11 +3263,28 @@
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
+DBG(fsg, "CBW: %02X %02X %02X %02X %02X %02X %02X %02X "
+ " %02X %02X %02X %02X %02X %02X %02X\n",
+ ((cbw->Signature >> 24) & 0xFF), ((cbw->Signature >> 16) & 0xFF),
+ ((cbw->Signature >> 8) & 0xFF), ((cbw->Signature ) & 0xFF),
+ ((cbw->Tag >> 24) & 0xFF), ((cbw->Tag >> 16) & 0xFF),
+ ((cbw->Tag >> 8) & 0xFF), ((cbw->Tag ) & 0xFF),
+ ((cbw->DataTransferLength>>24) & 0xFF),((cbw->DataTransferLength>>16) & 0xFF),
+ ((cbw->DataTransferLength>> 8) & 0xFF),((cbw->DataTransferLength ) & 0xFF),
+ cbw->Flags, cbw->Lun, cbw->Length);
+
+DBG(fsg, "CBW: %02X %02X %02X %02X %02X %02X %02X %02X "
+ " %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ cbw->CDB[0], cbw->CDB[1], cbw->CDB[2], cbw->CDB[3],
+ cbw->CDB[4], cbw->CDB[5], cbw->CDB[6], cbw->CDB[7],
+ cbw->CDB[8], cbw->CDB[9], cbw->CDB[10], cbw->CDB[11],
+ cbw->CDB[12], cbw->CDB[13], cbw->CDB[14], cbw->CDB[15]);
/* We can do anything we want here, so let's stall the
* bulk pipes if we are allowed to. */
if (mod_data.can_stall) {
fsg_set_halt(fsg, fsg->bulk_out);
+DBG(fsg,"calling halt_bulk_in_endpoint meaningless CBW\n");
halt_bulk_in_endpoint(fsg);
}
return -EINVAL;
@@ -3352,7 +3670,10 @@
if (rc != 0) // STALL on errors
fsg_set_halt(fsg, fsg->ep0);
else // Complete the status stage
+{
+DBG(fsg,"<1>%s: completing CONFIG_CHANGE handling\n", __FUNCTION__);
ep0_queue(fsg);
+}
break;
case FSG_STATE_DISCONNECT:
@@ -3376,12 +3697,18 @@
static int fsg_main_thread(void *fsg_)
{
struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
+#ifdef CONFIG_ARCH_FIONA
+ int rc;
+#endif
fsg->thread_task = current;
/* Release all our userspace resources */
+#ifdef CONFIG_ARCH_FIONA
+ daemonize("f-s-gadget");
+#else
daemonize("file-storage-gadget");
-
+#endif
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
@@ -3399,6 +3726,7 @@
/* The main loop */
while (fsg->state != FSG_STATE_TERMINATED) {
+
if (exception_in_progress(fsg) || signal_pending(current)) {
handle_exception(fsg);
continue;
@@ -3409,8 +3737,18 @@
continue;
}
+#ifndef CONFIG_ARCH_FIONA
if (get_next_command(fsg))
continue;
+#else
+ rc = get_next_command(fsg);
+ if (rc != 0) {
+ if (rc < 0)
+ continue;
+ else
+ DBG(fsg, "rc = %d\n", rc);
+ }
+#endif
spin_lock_irq(&fsg->lock);
if (!exception_in_progress(fsg))
@@ -3544,6 +3882,8 @@
}
+/*-------------------------------------------------------------------------*/
+
static ssize_t show_ro(struct device *dev, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
@@ -3551,6 +3891,7 @@
return sprintf(buf, "%d\n", curlun->ro);
}
+
static ssize_t show_file(struct device *dev, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
@@ -3579,7 +3920,24 @@
}
-static ssize_t store_ro(struct device *dev, const char *buf, size_t count)
+#ifdef CONFIG_ARCH_FIONA
+static ssize_t show_syncwrite(struct device *dev, char *buf)
+{
+ struct lun *curlun = dev_to_lun(dev);
+
+ return sprintf(buf, "%d\n", curlun->syncwrite);
+}
+
+static ssize_t show_activity(struct device *dev, char *buf)
+{
+ struct lun *curlun = dev_to_lun(dev);
+
+ return sprintf(buf, "%d\n", curlun->activity);
+}
+#endif
+
+
+ssize_t store_ro(struct device *dev, const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@@ -3603,7 +3961,8 @@
return rc;
}
-static ssize_t store_file(struct device *dev, const char *buf, size_t count)
+
+ssize_t store_file(struct device *dev, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
@@ -3637,10 +3996,75 @@
}
+#ifdef CONFIG_ARCH_FIONA
+ssize_t store_syncwrite(struct device *dev, const char *buf, size_t count)
+{
+ ssize_t rc = count;
+ struct lun *curlun = dev_to_lun(dev);
+ struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%d", &i) != 1)
+ return -EINVAL;
+
+ /* Allow the sync status to change only while the backing file
+ * is closed. */
+ down_read(&fsg->filesem);
+ if (backing_file_is_open(curlun)) {
+ LDBG(curlun, "sync status change prevented\n");
+ rc = -EBUSY;
+ } else {
+ curlun->syncwrite = !!i;
+ LDBG(curlun, "sync status set to %d\n", curlun->ro);
+ }
+ up_read(&fsg->filesem);
+ return rc;
+}
+
+
+ssize_t store_activity(struct device *dev, const char *buf, size_t count)
+{
+ struct lun *curlun = dev_to_lun(dev);
+ int i;
+
+ if (sscanf(buf, "%d", &i) != 1)
+ return -EINVAL;
+
+ /* Change states only if the passed-in state is different from the
+ * current state. */
+ if (i != curlun->activity) {
+ curlun->activity = i;
+
+ /* Open PNLCD driver to show activity; otherwise stop any
+ * pending activity, close the PNLCD driver, and say we're
+ * idle. */
+ if (curlun->activity) {
+ pnlcd_sys_open();
+ } else {
+ pnlcd_animation_t pnlcd_stop_animation = { stop_animation, 0 };
+
+ pnlcd_sys_ioctl(PNLCD_ANIMATE_IOCTL, &pnlcd_stop_animation);
+ pnlcd_sys_close();
+
+ last_activity = activity_idle;
+ activity_pending = 0;
+ }
+ }
+
+ return count;
+}
+#endif
+
+
/* The write permissions and store_xxx pointers are set in fsg_bind() */
static DEVICE_ATTR(ro, 0444, show_ro, NULL);
static DEVICE_ATTR(file, 0444, show_file, NULL);
+#ifdef CONFIG_ARCH_FIONA
+static DEVICE_ATTR(syncwrite, 0444, show_syncwrite, NULL);
+static DEVICE_ATTR(activity, 0444, show_activity, NULL);
+#endif
+
/*-------------------------------------------------------------------------*/
@@ -3668,6 +4092,10 @@
if (curlun->registered) {
device_remove_file(&curlun->dev, &dev_attr_ro);
device_remove_file(&curlun->dev, &dev_attr_file);
+#ifdef CONFIG_ARCH_FIONA
+ device_remove_file(&curlun->dev, &dev_attr_syncwrite);
+ device_remove_file(&curlun->dev, &dev_attr_activity);
+#endif
device_unregister(&curlun->dev);
wait_for_completion(&fsg->lun_released);
curlun->registered = 0;
@@ -3719,32 +4147,28 @@
if (mod_data.release == 0xffff) { // Parameter wasn't set
if (gadget_is_net2280(fsg->gadget))
- mod_data.release = 0x0301;
+ mod_data.release = __constant_cpu_to_le16(0x0301);
else if (gadget_is_dummy(fsg->gadget))
- mod_data.release = 0x0302;
+ mod_data.release = __constant_cpu_to_le16(0x0302);
else if (gadget_is_pxa(fsg->gadget))
- mod_data.release = 0x0303;
+ mod_data.release = __constant_cpu_to_le16(0x0303);
else if (gadget_is_sh(fsg->gadget))
- mod_data.release = 0x0304;
+ mod_data.release = __constant_cpu_to_le16(0x0304);
/* The sa1100 controller is not supported */
else if (gadget_is_goku(fsg->gadget))
- mod_data.release = 0x0306;
+ mod_data.release = __constant_cpu_to_le16(0x0306);
else if (gadget_is_mq11xx(fsg->gadget))
- mod_data.release = 0x0307;
+ mod_data.release = __constant_cpu_to_le16(0x0307);
else if (gadget_is_omap(fsg->gadget))
- mod_data.release = 0x0308;
- else if (gadget_is_lh7a40x(fsg->gadget))
- mod_data.release = 0x0309;
- else if (gadget_is_n9604(fsg->gadget))
- mod_data.release = 0x0310;
- else if (gadget_is_pxa27x(fsg->gadget))
- mod_data.release = 0x0311;
+ mod_data.release = __constant_cpu_to_le16(0x0308);
+ else if (gadget_is_lh7a40x(gadget))
+ mod_data.release = __constant_cpu_to_le16 (0x0309);
else {
WARN(fsg, "controller '%s' not recognized\n",
fsg->gadget->name);
- mod_data.release = 0x0399;
+ mod_data.release = __constant_cpu_to_le16(0x0399);
}
}
@@ -3826,6 +4250,13 @@
dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;
dev_attr_ro.store = store_ro;
dev_attr_file.store = store_file;
+#ifdef CONFIG_ARCH_FIONA
+ dev_attr_syncwrite.attr.mode = 0644;
+ dev_attr_syncwrite.store = store_syncwrite;
+
+ dev_attr_activity.attr.mode = 0644;
+ dev_attr_activity.store = store_activity;
+#endif
}
/* Find out how many LUNs there should be */
@@ -3864,6 +4295,10 @@
curlun->dev.release = lun_release;
device_create_file(&curlun->dev, &dev_attr_ro);
device_create_file(&curlun->dev, &dev_attr_file);
+#ifdef CONFIG_ARCH_FIONA
+ device_create_file(&curlun->dev, &dev_attr_syncwrite);
+ device_create_file(&curlun->dev, &dev_attr_activity);
+#endif
}
if (file[i] && *file[i]) {
@@ -3899,6 +4334,10 @@
}
/* Fix up the descriptors */
+#ifdef CONFIG_ARCH_FIONA
+ config_desc.bMaxPower = (mod_data.max_current >> 1) & 0xFF;
+#endif
+
device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
device_desc.idVendor = cpu_to_le16(mod_data.vendor);
device_desc.idProduct = cpu_to_le16(mod_data.product);
@@ -3908,10 +4347,10 @@
intf_desc.bNumEndpoints = i;
intf_desc.bInterfaceSubClass = mod_data.protocol_type;
intf_desc.bInterfaceProtocol = mod_data.transport_type;
- fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ fs_function[i+1] = NULL;
#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ hs_function[i+1] = NULL;
/* Assume ep0 uses the same maxpacket value for both speeds */
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
@@ -3922,11 +4361,6 @@
hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
#endif
- if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
- config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- }
-
rc = -ENOMEM;
/* Allocate the request and buffer for endpoint 0 */
@@ -3954,10 +4388,34 @@
/* This should reflect the actual gadget power source */
usb_gadget_set_selfpowered(gadget);
+#ifdef CONFIG_ARCH_FIONA
+ snprintf(manufacturer, sizeof manufacturer, "Amazon");
+#else
snprintf(manufacturer, sizeof manufacturer,
UTS_SYSNAME " " UTS_RELEASE " with %s",
gadget->name);
+#endif
+
+#ifdef CONFIG_ARCH_FIONA
+ {
+ unsigned char hex[] = "0123456789ABCDEF";
+ unsigned char c;
+ unsigned char *src = mod_data.serial_number;
+ unsigned char *dst = serial;
+ if (*src == 0)
+ src = "Empty";
+
+ for (i = 0 ; i < sizeof(serial)-3 ; ) {
+ c = *src++;
+ if (c == 0)
+ break;
+ *dst++ = c;
+ i++;
+ }
+ *dst = 0;
+ }
+#else
/* On a real device, serial[] would be loaded from permanent
* storage. We just encode it from the driver version string. */
for (i = 0; i < sizeof(serial) - 2; i += 2) {
@@ -3967,6 +4425,7 @@
break;
sprintf(&serial[i], "%02X", c);
}
+#endif
if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS |
CLONE_FILES))) < 0)
@@ -4103,6 +4562,11 @@
/* Tell the thread to start working */
complete(&fsg->thread_notifier);
+
+#ifdef CONFIG_ARCH_FIONA
+ start_activity_thread();
+#endif
+
return 0;
}
module_init(fsg_init);
@@ -4112,6 +4576,10 @@
{
struct fsg_dev *fsg = the_fsg;
+#ifdef CONFIG_ARCH_FIONA
+ stop_activity_thread();
+#endif
+
/* Unregister the driver iff the thread hasn't already done so */
if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
usb_gadget_unregister_driver(&fsg_driver);
diff -wur linux-2.6.10/drivers/usb/gadget/gadget_chips.h linux-2.6.10-lab/drivers/usb/gadget/gadget_chips.h
--- linux-2.6.10/drivers/usb/gadget/gadget_chips.h 2004-12-24 16:33:47.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/gadget_chips.h 2007-10-04 19:10:29.000000000 -0400
@@ -62,18 +62,6 @@
#define gadget_is_omap(g) 0
#endif
-#ifdef CONFIG_USB_GADGET_N9604
-#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
-#else
-#define gadget_is_n9604(g) 0
-#endif
-
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
-#else
-#define gadget_is_pxa27x(g) 0
-#endif
-
// CONFIG_USB_GADGET_AT91RM9200
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
diff -wur linux-2.6.10/drivers/usb/gadget/goku_udc.c linux-2.6.10-lab/drivers/usb/gadget/goku_udc.c
--- linux-2.6.10/drivers/usb/gadget/goku_udc.c 2004-12-24 16:34:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/goku_udc.c 2007-10-04 19:10:29.000000000 -0400
@@ -90,7 +90,7 @@
static void nuke(struct goku_ep *, int status);
static inline void
-command(struct goku_udc_regs __iomem *regs, int command, unsigned epnum)
+command(struct goku_udc_regs *regs, int command, unsigned epnum)
{
writel(COMMAND_EP(epnum) | command, ®s->Command);
udelay(300);
@@ -161,7 +161,7 @@
/* ep1 and ep2 can do double buffering and/or dma */
if (ep->num < 3) {
- struct goku_udc_regs __iomem *regs = ep->dev->regs;
+ struct goku_udc_regs *regs = ep->dev->regs;
u32 tmp;
/* double buffer except (for now) with pio in */
@@ -191,7 +191,7 @@
return 0;
}
-static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
+static void ep_reset(struct goku_udc_regs *regs, struct goku_ep *ep)
{
struct goku_udc *dev = ep->dev;
@@ -209,16 +209,16 @@
writel(dev->int_enable, ®s->int_enable);
readl(®s->int_enable);
if (ep->num < 3) {
- struct goku_udc_regs __iomem *r = ep->dev->regs;
+ struct goku_udc_regs *regs = ep->dev->regs;
u32 tmp;
- tmp = readl(&r->EPxSingle);
+ tmp = readl(®s->EPxSingle);
tmp &= ~(0x11 << ep->num);
- writel(tmp, &r->EPxSingle);
+ writel(tmp, ®s->EPxSingle);
- tmp = readl(&r->EPxBCS);
+ tmp = readl(®s->EPxBCS);
tmp &= ~(0x11 << ep->num);
- writel(tmp, &r->EPxBCS);
+ writel(tmp, ®s->EPxBCS);
}
/* reset dma in case we're still using it */
if (ep->dma) {
@@ -237,7 +237,7 @@
}
ep->ep.maxpacket = MAX_FIFO_SIZE;
- ep->desc = NULL;
+ ep->desc = 0;
ep->stopped = 1;
ep->irqs = 0;
ep->dma = 0;
@@ -274,10 +274,10 @@
struct goku_request *req;
if (!_ep)
- return NULL;
+ return 0;
req = kmalloc(sizeof *req, gfp_flags);
if (!req)
- return NULL;
+ return 0;
memset(req, 0, sizeof *req);
req->req.dma = DMA_ADDR_INVALID;
@@ -334,7 +334,7 @@
ep = container_of(_ep, struct goku_ep, ep);
if (!_ep)
- return NULL;
+ return 0;
*dma = DMA_ADDR_INVALID;
#if defined(USE_KMALLOC)
@@ -413,7 +413,7 @@
/*-------------------------------------------------------------------------*/
static inline int
-write_packet(u32 __iomem *fifo, u8 *buf, struct goku_request *req, unsigned max)
+write_packet(u32 *fifo, u8 *buf, struct goku_request *req, unsigned max)
{
unsigned length, count;
@@ -488,7 +488,7 @@
static int read_fifo(struct goku_ep *ep, struct goku_request *req)
{
- struct goku_udc_regs __iomem *regs;
+ struct goku_udc_regs *regs;
u32 size, set;
u8 *buf;
unsigned bufferspace, is_short, dbuff;
@@ -581,8 +581,7 @@
}
static inline void
-pio_irq_enable(struct goku_udc *dev,
- struct goku_udc_regs __iomem *regs, int epnum)
+pio_irq_enable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
{
dev->int_enable |= INT_EPxDATASET (epnum);
writel(dev->int_enable, ®s->int_enable);
@@ -590,8 +589,7 @@
}
static inline void
-pio_irq_disable(struct goku_udc *dev,
- struct goku_udc_regs __iomem *regs, int epnum)
+pio_irq_disable(struct goku_udc *dev, struct goku_udc_regs *regs, int epnum)
{
dev->int_enable &= ~INT_EPxDATASET (epnum);
writel(dev->int_enable, ®s->int_enable);
@@ -615,7 +613,7 @@
// return: 0 = q running, 1 = q stopped, negative = errno
static int start_dma(struct goku_ep *ep, struct goku_request *req)
{
- struct goku_udc_regs __iomem *regs = ep->dev->regs;
+ struct goku_udc_regs *regs = ep->dev->regs;
u32 master;
u32 start = req->req.dma;
u32 end = start + req->req.length - 1;
@@ -671,7 +669,7 @@
static void dma_advance(struct goku_udc *dev, struct goku_ep *ep)
{
struct goku_request *req;
- struct goku_udc_regs __iomem *regs = ep->dev->regs;
+ struct goku_udc_regs *regs = ep->dev->regs;
u32 master;
master = readl(®s->dma_master);
@@ -718,7 +716,7 @@
static void abort_dma(struct goku_ep *ep, int status)
{
- struct goku_udc_regs __iomem *regs = ep->dev->regs;
+ struct goku_udc_regs *regs = ep->dev->regs;
struct goku_request *req;
u32 curr, master;
@@ -850,7 +848,7 @@
if (unlikely(status != 0)) {
if (status > 0)
status = 0;
- req = NULL;
+ req = 0;
}
} /* else pio or dma irq handler advances the queue. */
@@ -929,7 +927,7 @@
} else if (!list_empty(&req->queue))
done(ep, req, -ECONNRESET);
else
- req = NULL;
+ req = 0;
spin_unlock_irqrestore(&dev->lock, flags);
return req ? 0 : -EOPNOTSUPP;
@@ -986,8 +984,7 @@
retval = -EAGAIN;
else if (ep->is_in && value
/* data in (either) packet buffer? */
- && (readl(&ep->dev->regs->DataSet)
- & DATASET_AB(ep->num)))
+ && (ep->dev->regs->DataSet & DATASET_AB(ep->num)))
retval = -EAGAIN;
else if (!value)
goku_clear_halt(ep);
@@ -1004,7 +1001,7 @@
static int goku_fifo_status(struct usb_ep *_ep)
{
struct goku_ep *ep;
- struct goku_udc_regs __iomem *regs;
+ struct goku_udc_regs *regs;
u32 size;
if (!_ep)
@@ -1026,7 +1023,7 @@
static void goku_fifo_flush(struct usb_ep *_ep)
{
struct goku_ep *ep;
- struct goku_udc_regs __iomem *regs;
+ struct goku_udc_regs *regs;
u32 size;
if (!_ep)
@@ -1095,7 +1092,13 @@
return "(dma IN)";
}
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+/* if we're trying to save space, don't bother with this proc file */
+
+#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)
+# define UDC_PROC_FILE
+#endif
+
+#ifdef UDC_PROC_FILE
static const char proc_node_name [] = "driver/udc";
@@ -1146,7 +1149,7 @@
{
char *buf = buffer;
struct goku_udc *dev = _dev;
- struct goku_udc_regs __iomem *regs = dev->regs;
+ struct goku_udc_regs *regs = dev->regs;
char *next = buf;
unsigned size = count;
unsigned long flags;
@@ -1309,7 +1312,7 @@
return count - size;
}
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+#endif /* UDC_PROC_FILE */
/*-------------------------------------------------------------------------*/
@@ -1339,17 +1342,17 @@
ep->dev = dev;
INIT_LIST_HEAD (&ep->queue);
- ep_reset(NULL, ep);
+ ep_reset(0, ep);
}
- dev->ep[0].reg_mode = NULL;
+ dev->ep[0].reg_mode = 0;
dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
list_del_init (&dev->ep[0].ep.ep_list);
}
static void udc_reset(struct goku_udc *dev)
{
- struct goku_udc_regs __iomem *regs = dev->regs;
+ struct goku_udc_regs *regs = dev->regs;
writel(0, ®s->power_detect);
writel(0, ®s->int_enable);
@@ -1366,7 +1369,7 @@
static void ep0_start(struct goku_udc *dev)
{
- struct goku_udc_regs __iomem *regs = dev->regs;
+ struct goku_udc_regs *regs = dev->regs;
unsigned i;
VDBG(dev, "%s\n", __FUNCTION__);
@@ -1444,15 +1447,15 @@
return -EBUSY;
/* hook up the driver */
- driver->driver.bus = NULL;
+ driver->driver.bus = 0;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
retval = driver->bind(&dev->gadget);
if (retval) {
DBG(dev, "bind to driver %s --> error %d\n",
driver->driver.name, retval);
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
+ dev->driver = 0;
+ dev->gadget.dev.driver = 0;
return retval;
}
@@ -1474,7 +1477,7 @@
DBG (dev, "%s\n", __FUNCTION__);
if (dev->gadget.speed == USB_SPEED_UNKNOWN)
- driver = NULL;
+ driver = 0;
/* disconnect gadget driver after quiesceing hw and the driver */
udc_reset (dev);
@@ -1501,7 +1504,7 @@
return -EINVAL;
spin_lock_irqsave(&dev->lock, flags);
- dev->driver = NULL;
+ dev->driver = 0;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1517,7 +1520,7 @@
static void ep0_setup(struct goku_udc *dev)
{
- struct goku_udc_regs __iomem *regs = dev->regs;
+ struct goku_udc_regs *regs = dev->regs;
struct usb_ctrlrequest ctrl;
int tmp;
@@ -1627,7 +1630,7 @@
static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r)
{
struct goku_udc *dev = _dev;
- struct goku_udc_regs __iomem *regs = dev->regs;
+ struct goku_udc_regs *regs = dev->regs;
struct goku_ep *ep;
u32 stat, handled = 0;
unsigned i, rescans = 5;
@@ -1648,7 +1651,7 @@
stat = 0;
handled = 1;
// FIXME have a neater way to prevent re-enumeration
- dev->driver = NULL;
+ dev->driver = 0;
goto done;
}
if (stat & INT_PWRDETECT) {
@@ -1812,7 +1815,7 @@
usb_gadget_unregister_driver(dev->driver);
}
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#ifdef UDC_PROC_FILE
remove_proc_entry(proc_node_name, NULL);
#endif
if (dev->regs)
@@ -1828,9 +1831,9 @@
pci_disable_device(pdev);
device_unregister(&dev->gadget.dev);
- pci_set_drvdata(pdev, NULL);
- dev->regs = NULL;
- the_controller = NULL;
+ pci_set_drvdata(pdev, 0);
+ dev->regs = 0;
+ the_controller = 0;
INFO(dev, "unbind\n");
}
@@ -1841,9 +1844,9 @@
static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct goku_udc *dev = NULL;
+ struct goku_udc *dev = 0;
unsigned long resource, len;
- void __iomem *base = NULL;
+ void *base = 0;
int retval;
char buf [8], *bufp;
@@ -1903,7 +1906,7 @@
retval = -EFAULT;
goto done;
}
- dev->regs = (struct goku_udc_regs __iomem *) base;
+ dev->regs = (struct goku_udc_regs *) base;
pci_set_drvdata(pdev, dev);
INFO(dev, "%s\n", driver_desc);
@@ -1930,7 +1933,7 @@
pci_set_master(pdev);
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#ifdef UDC_PROC_FILE
create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
#endif
@@ -1973,7 +1976,7 @@
static int __init init (void)
{
- return pci_register_driver (&goku_pci_driver);
+ return pci_module_init (&goku_pci_driver);
}
module_init (init);
diff -wur linux-2.6.10/drivers/usb/gadget/goku_udc.h linux-2.6.10-lab/drivers/usb/gadget/goku_udc.h
--- linux-2.6.10/drivers/usb/gadget/goku_udc.h 2004-12-24 16:34:32.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/goku_udc.h 2007-10-04 19:10:29.000000000 -0400
@@ -216,9 +216,9 @@
struct list_head queue;
const struct usb_endpoint_descriptor *desc;
- u32 __iomem *reg_fifo;
- u32 __iomem *reg_mode;
- u32 __iomem *reg_status;
+ u32 *reg_fifo;
+ u32 *reg_mode;
+ u32 *reg_status;
};
struct goku_request {
@@ -253,7 +253,7 @@
/* pci state used to access those endpoints */
struct pci_dev *pdev;
- struct goku_udc_regs __iomem *regs;
+ struct goku_udc_regs *regs;
u32 int_enable;
/* statistics... */
diff -wur linux-2.6.10/drivers/usb/gadget/inode.c linux-2.6.10-lab/drivers/usb/gadget/inode.c
--- linux-2.6.10/drivers/usb/gadget/inode.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/inode.c 2007-10-04 19:10:29.000000000 -0400
@@ -1981,8 +1981,12 @@
{
struct dentry *dentry;
struct inode *inode;
+ struct qstr qname;
- dentry = d_alloc_name(sb->s_root, name);
+ qname.name = name;
+ qname.len = strlen (name);
+ qname.hash = full_name_hash (qname.name, qname.len);
+ dentry = d_alloc (sb->s_root, &qname);
if (!dentry)
return NULL;
diff -wur linux-2.6.10/drivers/usb/gadget/lh7a40x_udc.c linux-2.6.10-lab/drivers/usb/gadget/lh7a40x_udc.c
--- linux-2.6.10/drivers/usb/gadget/lh7a40x_udc.c 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/lh7a40x_udc.c 2007-10-04 19:10:29.000000000 -0400
@@ -54,6 +54,7 @@
/*
Local definintions.
*/
+#define UDC_PROC_FILE
#ifndef NO_STATES
static char *state_names[] = {
@@ -191,7 +192,7 @@
*/
#define is_usb_connected() get_portc_pdr(2)
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#ifdef UDC_PROC_FILE
static const char proc_node_name[] = "driver/udc";
@@ -247,12 +248,12 @@
#define create_proc_files() create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
#define remove_proc_files() remove_proc_entry(proc_node_name, NULL)
-#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+#else /* !UDC_PROC_FILE */
#define create_proc_files() do {} while (0)
#define remove_proc_files() do {} while (0)
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+#endif /* UDC_PROC_FILE */
/*
* udc_disable - disable USB device controller
diff -wur linux-2.6.10/drivers/usb/gadget/net2280.c linux-2.6.10-lab/drivers/usb/gadget/net2280.c
--- linux-2.6.10/drivers/usb/gadget/net2280.c 2004-12-24 16:33:51.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/net2280.c 2007-10-04 19:10:29.000000000 -0400
@@ -76,6 +76,7 @@
#define EP_DONTUSE 13 /* nonzero */
#define USE_RDK_LEDS /* GPIO pins control three LEDs */
+#define USE_SYSFS_DEBUG_FILES
static const char driver_name [] = "net2280";
@@ -116,7 +117,7 @@
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
-#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG)
+#if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG)
static char *type_string (u8 bmAttributes)
{
switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
@@ -717,7 +718,7 @@
dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
/* td->dmadesc = previously set by caller */
- td->dmaaddr = cpu_to_le32 (req->req.dma);
+ td->dmaaddr = cpu_to_le32p (&req->req.dma);
/* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
wmb ();
@@ -1449,12 +1450,7 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-/* FIXME move these into procfs, and use seq_file.
- * Sysfs _still_ doesn't behave for arbitrarily sized files,
- * and also doesn't help products using this with 2.4 kernels.
- */
+#ifdef USE_SYSFS_DEBUG_FILES
/* "function" sysfs attribute */
static ssize_t
@@ -1707,10 +1703,8 @@
td = req->td;
t = scnprintf (next, size, "\t td %08x "
" count %08x buf %08x desc %08x\n",
- (u32) req->td_dma,
- le32_to_cpu (td->dmacount),
- le32_to_cpu (td->dmaaddr),
- le32_to_cpu (td->dmadesc));
+ req->td_dma, td->dmacount,
+ td->dmaaddr, td->dmadesc);
if (t <= 0 || t > size)
goto done;
size -= t;
@@ -2847,7 +2841,6 @@
dev->got_irq = 1;
/* DMA setup */
- /* NOTE: we know only the 32 LSBs of dma addresses may be nonzero */
dev->requests = pci_pool_create ("requests", pdev,
sizeof (struct net2280_dma),
0 /* no alignment requirements */,
@@ -2943,7 +2936,7 @@
{
if (!use_dma)
use_dma_chaining = 0;
- return pci_register_driver (&net2280_pci_driver);
+ return pci_module_init (&net2280_pci_driver);
}
module_init (init);
diff -wur linux-2.6.10/drivers/usb/gadget/net2280.h linux-2.6.10-lab/drivers/usb/gadget/net2280.h
--- linux-2.6.10/drivers/usb/gadget/net2280.h 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/net2280.h 2007-10-04 19:10:29.000000000 -0400
@@ -495,10 +495,10 @@
* use struct net2280_dma_regs bitfields
*/
struct net2280_dma {
- __le32 dmacount;
- __le32 dmaaddr; /* the buffer */
- __le32 dmadesc; /* next dma descriptor */
- __le32 _reserved;
+ u32 dmacount;
+ u32 dmaaddr; /* the buffer */
+ u32 dmadesc; /* next dma descriptor */
+ u32 _reserved;
} __attribute__ ((aligned (16)));
/*-------------------------------------------------------------------------*/
diff -wur linux-2.6.10/drivers/usb/gadget/omap_udc.c linux-2.6.10-lab/drivers/usb/gadget/omap_udc.c
--- linux-2.6.10/drivers/usb/gadget/omap_udc.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/omap_udc.c 2007-10-04 19:10:29.000000000 -0400
@@ -59,14 +59,15 @@
#undef USB_TRACE
-/* bulk DMA seems to be behaving for both IN and OUT */
+/* OUT-dma seems to be behaving */
#define USE_DMA
/* ISO too */
#define USE_ISO
+
#define DRIVER_DESC "OMAP UDC driver"
-#define DRIVER_VERSION "4 October 2004"
+#define DRIVER_VERSION "24 August 2004"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
@@ -103,6 +104,7 @@
module_param (fifo_mode, uint, 0);
MODULE_PARM_DESC (fifo_mode, "endpoint setup (0 == default)");
+
#ifdef USE_DMA
static unsigned use_dma = 1;
@@ -222,17 +224,18 @@
list_add(&ep->iso, &udc->iso);
/* maybe assign a DMA channel to this endpoint */
- if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK)
- /* FIXME ISO can dma, but prefers first channel */
+ if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+ && !(ep->bEndpointAddress & USB_DIR_IN))
+ /* FIXME ISO can dma, but prefers first channel.
+ * IN can dma, but lacks debugging.
+ */
dma_channel_claim(ep, 0);
/* PIO OUT may RX packets */
if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC
&& !ep->has_dma
- && !(ep->bEndpointAddress & USB_DIR_IN)) {
+ && !(ep->bEndpointAddress & USB_DIR_IN))
UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
spin_unlock_irqrestore(&udc->lock, flags);
VDBG("%s enabled\n", _ep->name);
@@ -259,7 +262,6 @@
ep->has_dma = 0;
UDC_CTRL_REG = UDC_SET_HALT;
list_del_init(&ep->iso);
- del_timer(&ep->timer);
spin_unlock_irqrestore(&ep->udc->lock, flags);
@@ -496,22 +498,17 @@
u16 ep_stat = UDC_STAT_FLG_REG;
is_last = 0;
- if (ep_stat & FIFO_EMPTY) {
- if (!ep->double_buf)
- break;
- ep->fnf = 1;
- }
- if (ep_stat & UDC_EP_HALTED)
+ if (ep_stat & FIFO_UNREADABLE)
break;
- if (ep_stat & FIFO_FULL)
+ if (ep_stat & (UDC_NON_ISO_FIFO_FULL|UDC_ISO_FIFO_FULL))
avail = ep->ep.maxpacket;
- else {
+ else
avail = UDC_RXFSTAT_REG;
- ep->fnf = ep->double_buf;
- }
count = read_packet(buf, req, avail);
+ // FIXME double buffered PIO OUT wasn't behaving...
+
/* partial packet reads may not be errors */
if (count < ep->ep.maxpacket) {
is_last = 1;
@@ -529,56 +526,26 @@
if (!ep->bEndpointAddress)
break;
- if (is_last)
+ if (!ep->double_buf) {
+ UDC_CTRL_REG = UDC_SET_FIFO_EN;
+ if (!is_last)
+ break;
+ }
+
+ if (is_last) {
done(ep, req, 0);
+ if (list_empty(&ep->queue) || !ep->double_buf)
break;
+ req = container_of(ep->queue.next,
+ struct omap_req, queue);
+ is_last = 0;
+ }
}
return is_last;
}
/*-------------------------------------------------------------------------*/
-static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- /* IN-DMA needs this on fault/cancel paths, so 15xx misreports
- * the last transfer's bytecount by more than a FIFO's worth.
- */
- if (cpu_is_omap15xx())
- return 0;
-
- end = omap_readw(OMAP_DMA_CSAC(ep->lch));
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
- ? OMAP_DMA_CSAC(x) /* really: CPC */ \
- : OMAP_DMA_CDAC(x))
-
-static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
-{
- dma_addr_t end;
-
- end = omap_readw(DMA_DEST_LAST(ep->lch));
- if (end == ep->dma_counter)
- return 0;
-
- end |= start & (0xffff << 16);
- if (cpu_is_omap15xx())
- end++;
- if (end < start)
- end += 0x10000;
- return end - start;
-}
-
-
/* Each USB transfer request using DMA maps to one or more DMA transfers.
* When DMA completion isn't request completion, the UDC continues with
* the next DMA transfer for that USB transfer.
@@ -588,29 +555,26 @@
{
u16 txdma_ctrl;
unsigned length = req->req.length - req->req.actual;
- const int sync_mode = cpu_is_omap15xx()
- ? OMAP_DMA_SYNC_FRAME
- : OMAP_DMA_SYNC_ELEMENT;
/* measure length in either bytes or packets */
- if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
- || (cpu_is_omap15xx() && length < ep->maxpacket)) {
+ if (length <= (UDC_TXN_TSC + 1)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- length, 1, sync_mode);
+ length, 1, OMAP_DMA_SYNC_ELEMENT);
} else {
- length = min(length / ep->maxpacket,
+ length = max(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
- ep->ep.maxpacket, length, sync_mode);
+ ep->ep.maxpacket, length,
+ OMAP_DMA_SYNC_ELEMENT);
length *= ep->maxpacket;
}
+
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
omap_start_dma(ep->lch);
- ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
req->dma_bytes = length;
@@ -628,9 +592,14 @@
&& req->dma_bytes != 0
&& (req->req.actual % ep->maxpacket) == 0)
return;
- } else
- req->req.actual += dma_src_len(ep, req->req.dma
- + req->req.actual);
+ } else {
+ u32 last;
+
+ // FIXME this surely isn't #bytes transferred
+ last = (omap_readw(OMAP_DMA_CSSA_U(ep->lch)) << 16)
+ | omap_readw(OMAP_DMA_CSSA_L(ep->lch));
+ req->req.actual = last - req->req.dma;
+ }
/* tx completion */
omap_stop_dma(ep->lch);
@@ -655,7 +624,6 @@
OMAP_DMA_SYNC_ELEMENT);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
- ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -670,9 +638,11 @@
{
u16 count;
- if (status == 0)
- ep->dma_counter = (u16) (req->req.dma + req->req.actual);
- count = dma_dest_len(ep, req->req.dma + req->req.actual);
+ /* FIXME must be a better way to see how much dma
+ * happened, even when it never got going...
+ */
+ count = omap_readw(OMAP_DMA_CDAC(ep->lch));
+ count -= 0xffff & (req->req.dma + req->req.actual);
count += req->req.actual;
if (count <= req->req.length)
req->req.actual = count;
@@ -735,9 +705,7 @@
if (irq_src & UDC_RXN_CNT) {
ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)];
- ep->irqs++;
- /* omap15xx does this unasked... */
- VDBG("%s, RX_CNT irq?\n", ep->ep.name);
+ DBG("%s, RX_CNT irq?\n", ep->ep.name);
UDC_IRQ_SRC_REG = UDC_RXN_CNT;
}
}
@@ -810,7 +778,6 @@
omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
/* channel type P: hw synch (fifo) */
- if (!cpu_is_omap15xx())
omap_writew(2, OMAP_DMA_LCH_CTRL(ep->lch));
}
@@ -836,10 +803,6 @@
use_ep(ep, UDC_EP_SEL);
(is_in ? write_fifo : read_fifo)(ep, req);
deselect_ep();
- if (!is_in) {
- UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
/* IN: 6 wait states before it'll tx */
}
}
@@ -870,21 +833,24 @@
UDC_TXDMA_CFG_REG &= ~mask;
if (req) {
+ if (active)
+ udelay(50);
finish_in_dma(ep, req, -ECONNRESET);
-
- /* clear FIFO; hosts probably won't empty it */
- use_ep(ep, UDC_EP_SEL);
- UDC_CTRL_REG = UDC_CLR_EP;
- deselect_ep();
+ if (UDC_TXDMA_CFG_REG & mask)
+ WARN("%s, SPIN abort TX dma\n", ep->ep.name);
}
+
+ /* host may empty the fifo (or not...) */
while (UDC_TXDMA_CFG_REG & mask)
udelay(10);
+
} else {
UDC_RXDMA_CFG_REG &= ~mask;
/* dma empties the fifo */
- while (UDC_RXDMA_CFG_REG & mask)
+ while (active && (UDC_RXDMA_CFG_REG & mask))
udelay(10);
+ omap_stop_dma(ep->lch);
if (req)
finish_out_dma(ep, req, -ECONNRESET);
}
@@ -1031,10 +997,6 @@
if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
req = 0;
deselect_ep();
- if (!is_in) {
- UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
/* IN: 6 wait states before it'll tx */
}
}
@@ -1072,7 +1034,7 @@
if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) {
int channel = ep->dma_channel;
- /* releasing the channel cancels the request,
+ /* releasing the dma completion cancels the request,
* reclaiming the channel restarts the queue
*/
dma_channel_release(ep);
@@ -1142,10 +1104,8 @@
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0;
- if (!(ep->bEndpointAddress & USB_DIR_IN)) {
+ if (!(ep->bEndpointAddress & USB_DIR_IN))
UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
}
}
done:
@@ -1240,7 +1200,6 @@
{
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
@@ -1249,7 +1208,6 @@
static void pullup_disable(struct omap_udc *udc)
{
#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
OTG_CTRL_REG &= ~OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
@@ -1258,7 +1216,7 @@
/*
* Called by whatever detects VBUS sessions: external transceiver
- * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock.
+ * driver, or maybe GPIO0 VBUS IRQ.
*/
static int omap_vbus_session(struct usb_gadget *gadget, int is_active)
{
@@ -1269,13 +1227,6 @@
spin_lock_irqsave(&udc->lock, flags);
VDBG("VBUS %s\n", is_active ? "on" : "off");
udc->vbus_active = (is_active != 0);
- if (cpu_is_omap15xx()) {
- /* "software" detect, ignored if !VBUS_MODE_1510 */
- if (is_active)
- FUNC_MUX_CTRL_0_REG |= VBUS_CTRL_1510;
- else
- FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
- }
if (can_pullup(udc))
pullup_enable(udc);
else
@@ -1389,15 +1340,8 @@
/* Clear any pending requests and then scrub any rx/tx state
* before starting to handle the SETUP request.
*/
- if (irq_src & UDC_SETUP) {
- u16 ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX);
-
+ if (irq_src & UDC_SETUP)
nuke(ep0, 0);
- if (ack) {
- UDC_IRQ_SRC_REG = ack;
- irq_src = UDC_SETUP;
- }
- }
/* IN/OUT packets mean we're in the DATA or STATUS stage.
* This driver uses only uses protocol stalls (ep0 never halts),
@@ -1562,10 +1506,8 @@
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
ep->ackwait = 0;
- if (!(ep->bEndpointAddress & USB_DIR_IN)) {
+ if (!(ep->bEndpointAddress & USB_DIR_IN))
UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
}
VDBG("%s halt cleared by host\n", ep->name);
goto ep0out_status_stage;
@@ -1746,7 +1688,7 @@
}
change &= ~UDC_SUS;
}
- if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) {
+ if (change & OTG_FLAGS) {
update_otg(udc);
change &= ~OTG_FLAGS;
}
@@ -1799,39 +1741,6 @@
return status;
}
-/* workaround for seemingly-lost IRQs for RX ACKs... */
-#define PIO_OUT_TIMEOUT (jiffies + HZ/3)
-#define HALF_FULL(f) (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))
-
-static void pio_out_timer(unsigned long _ep)
-{
- struct omap_ep *ep = (void *) _ep;
- unsigned long flags;
- u16 stat_flg;
-
- spin_lock_irqsave(&ep->udc->lock, flags);
- if (!list_empty(&ep->queue) && ep->ackwait) {
- use_ep(ep, 0);
- stat_flg = UDC_STAT_FLG_REG;
-
- if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN)
- || (ep->double_buf && HALF_FULL(stat_flg)))) {
- struct omap_req *req;
-
- VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg);
- req = container_of(ep->queue.next,
- struct omap_req, queue);
- UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL;
- (void) read_fifo(ep, req);
- UDC_EP_NUM_REG = ep->bEndpointAddress;
- UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
- }
- }
- mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
- spin_unlock_irqrestore(&ep->udc->lock, flags);
-}
-
static irqreturn_t
omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
{
@@ -1855,56 +1764,38 @@
ep = &udc->ep[epnum];
ep->irqs++;
+ if (!list_empty(&ep->queue)) {
UDC_EP_NUM_REG = epnum | UDC_EP_SEL;
- ep->fnf = 0;
if ((UDC_STAT_FLG_REG & UDC_ACK)) {
- ep->ackwait--;
- if (!list_empty(&ep->queue)) {
int stat;
req = container_of(ep->queue.next,
struct omap_req, queue);
stat = read_fifo(ep, req);
- if (!ep->double_buf)
- ep->fnf = 1;
+ // FIXME double buffered PIO OUT should work
}
- }
- /* min 6 clock delay before clearing EP_SEL ... */
- epn_stat = UDC_EPN_STAT_REG;
- epn_stat = UDC_EPN_STAT_REG;
UDC_EP_NUM_REG = epnum;
-
- /* enabling fifo _after_ clearing ACK, contrary to docs,
- * reduces lossage; timer still needed though (sigh).
- */
- if (ep->fnf) {
- UDC_CTRL_REG = UDC_SET_FIFO_EN;
- ep->ackwait = 1 + ep->double_buf;
}
- mod_timer(&ep->timer, PIO_OUT_TIMEOUT);
}
/* then IN transfers */
- else if (irq_src & UDC_EPN_TX) {
+ if (irq_src & UDC_EPN_TX) {
epnum = epn_stat & 0x0f;
UDC_IRQ_SRC_REG = UDC_EPN_TX;
status = IRQ_HANDLED;
ep = &udc->ep[16 + epnum];
ep->irqs++;
+ ep->ackwait = 0;
+ if (!list_empty(&ep->queue)) {
UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL;
if ((UDC_STAT_FLG_REG & UDC_ACK)) {
- ep->ackwait = 0;
- if (!list_empty(&ep->queue)) {
req = container_of(ep->queue.next,
struct omap_req, queue);
(void) write_fifo(ep, req);
}
- }
- /* min 6 clock delay before clearing EP_SEL ... */
- epn_stat = UDC_EPN_STAT_REG;
- epn_stat = UDC_EPN_STAT_REG;
UDC_EP_NUM_REG = epnum | UDC_EP_DIR;
- /* then 6 clocks before it'd tx */
+ /* 6 wait states before it'll tx */
+ }
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -2046,9 +1937,6 @@
pullup_disable (udc);
}
- if (machine_is_omap_innovator())
- omap_vbus_session(&udc->gadget, 1);
-
done:
return status;
}
@@ -2064,9 +1952,6 @@
if (!driver || driver != udc->driver)
return -EINVAL;
- if (machine_is_omap_innovator())
- omap_vbus_session(&udc->gadget, 0);
-
if (udc->transceiver)
(void) otg_set_peripheral(udc->transceiver, 0);
else
@@ -2089,7 +1974,7 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#ifdef CONFIG_USB_OMAP_PROC
#include
@@ -2115,16 +2000,8 @@
stat_flg = UDC_STAT_FLG_REG;
seq_printf(s,
- "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
- ep->name, buf,
- ep->double_buf ? "dbuf " : "",
- ({char *s; switch(ep->ackwait){
- case 0: s = ""; break;
- case 1: s = "(ackw) "; break;
- case 2: s = "(ackw2) "; break;
- default: s = "(?) "; break;
- } s;}),
- ep->irqs, stat_flg,
+ "\n%s %sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
+ ep->name, buf, ep->irqs, stat_flg,
(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
(stat_flg & UDC_MISS_IN) ? "miss_in " : "",
(stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "",
@@ -2142,20 +2019,11 @@
if (list_empty (&ep->queue))
seq_printf(s, "\t(queue empty)\n");
else
- list_for_each_entry (req, &ep->queue, queue) {
- unsigned length = req->req.actual;
-
- if (use_dma && buf[0]) {
- length += ((ep->bEndpointAddress & USB_DIR_IN)
- ? dma_src_len : dma_dest_len)
- (ep, req->req.dma + length);
- buf[0] = 0;
- }
+ list_for_each_entry (req, &ep->queue, queue)
seq_printf(s, "\treq %p len %d/%d buf %p\n",
- &req->req, length,
+ &req->req, req->req.actual,
req->req.length, req->req.buf);
}
-}
static char *trx_mode(unsigned m)
{
@@ -2168,14 +2036,34 @@
}
}
-static int proc_otg_show(struct seq_file *s)
+static int proc_udc_show(struct seq_file *s, void *_)
{
u32 tmp;
+ struct omap_ep *ep;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ seq_printf(s, "%s, version: " DRIVER_VERSION
+#ifdef USE_ISO
+ " (iso)"
+#endif
+ "%s\n",
+ driver_desc,
+ use_dma ? " (dma)" : "");
- tmp = OTG_REV_REG;
- seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n",
+ tmp = UDC_REV_REG & 0xff;
+ seq_printf(s,
+ "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n"
+ "hmc %d, transceiver %08x %s\n",
tmp >> 4, tmp & 0xf,
- USB_TRANSCEIVER_CTRL_REG);
+ OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
+ fifo_mode,
+ udc->driver ? udc->driver->driver.name : "(none)",
+ HMC, USB_TRANSCEIVER_CTRL_REG,
+ udc->transceiver ? udc->transceiver->label : "");
+
+ /* OTG controller registers */
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
@@ -2229,41 +2117,6 @@
seq_printf(s, "otg_outctrl %04x" "\n", tmp);
tmp = OTG_TEST_REG;
seq_printf(s, "otg_test %04x" "\n", tmp);
-}
-
-static int proc_udc_show(struct seq_file *s, void *_)
-{
- u32 tmp;
- struct omap_ep *ep;
- unsigned long flags;
-
- spin_lock_irqsave(&udc->lock, flags);
-
- seq_printf(s, "%s, version: " DRIVER_VERSION
-#ifdef USE_ISO
- " (iso)"
-#endif
- "%s\n",
- driver_desc,
- use_dma ? " (dma)" : "");
-
- tmp = UDC_REV_REG & 0xff;
- seq_printf(s,
- "UDC rev %d.%d, fifo mode %d, gadget %s\n"
- "hmc %d, transceiver %s\n",
- tmp >> 4, tmp & 0xf,
- fifo_mode,
- udc->driver ? udc->driver->driver.name : "(none)",
- HMC,
- udc->transceiver ? udc->transceiver->label : "(none)");
- seq_printf(s, "ULPD control %04x req %04x status %04x\n",
- __REG16(ULPD_CLOCK_CTRL),
- __REG16(ULPD_SOFT_REQ),
- __REG16(ULPD_STATUS_REQ));
-
- /* OTG controller registers */
- if (!cpu_is_omap15xx())
- proc_otg_show(s);
tmp = UDC_SYSCON1_REG;
seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp,
@@ -2439,10 +2292,10 @@
epn_rxtx |= UDC_EPN_RX_ISO;
dbuf = 1;
} else {
- /* double-buffering "not supported" on 15xx,
- * and ignored for PIO-IN on 16xx
+ /* pio-out could potentially double-buffer,
+ * as can (should!) DMA-IN
*/
- if (!use_dma || cpu_is_omap15xx())
+ if (!use_dma || (addr & USB_DIR_IN))
dbuf = 0;
switch (maxp) {
@@ -2454,9 +2307,6 @@
}
if (dbuf && addr)
epn_rxtx |= UDC_EPN_RX_DB;
- init_timer(&ep->timer);
- ep->timer.function = pio_out_timer;
- ep->timer.data = (unsigned long) ep;
}
if (addr)
epn_rxtx |= UDC_EPN_RX_VALID;
@@ -2646,44 +2496,23 @@
return -EBUSY;
}
- INFO("OMAP UDC rev %d.%d%s\n",
+ INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n",
UDC_REV_REG >> 4, UDC_REV_REG & 0xf,
- config->otg ? ", Mini-AB" : "");
+ OTG_REV_REG >> 4, OTG_REV_REG & 0xf,
+ config->otg ? "Mini-AB" : "B/Mini-B");
/* use the mode given to us by board init code */
- if (cpu_is_omap15xx()) {
- hmc = HMC_1510;
- type = "(unknown)";
-
- if (machine_is_omap_innovator()) {
- /* just set up software VBUS detect, and then
- * later rig it so we always report VBUS.
- * FIXME without really sensing VBUS, we can't
- * know when to turn PULLUP_EN on/off; and that
- * means we always "need" the 48MHz clock.
- */
- u32 tmp = FUNC_MUX_CTRL_0_REG;
-
- FUNC_MUX_CTRL_0_REG &= ~VBUS_CTRL_1510;
- tmp |= VBUS_MODE_1510;
- tmp &= ~VBUS_CTRL_1510;
- FUNC_MUX_CTRL_0_REG = tmp;
- }
- } else {
- hmc = HMC_1610;
+ hmc = HMC;
switch (hmc) {
case 3:
case 11:
- case 16:
case 19:
case 25:
xceiv = otg_get_transceiver();
if (!xceiv) {
DBG("external transceiver not registered!\n");
- if (config->otg)
goto cleanup0;
- type = "(unknown external)";
- } else
+ }
type = xceiv->label;
break;
case 0: /* POWERUP DEFAULT == 0 */
@@ -2703,7 +2532,6 @@
ERR("unrecognized UDC HMC mode %d\n", hmc);
return -ENODEV;
}
- }
INFO("hmc mode %d, transceiver %s\n", hmc, type);
/* a "gadget" abstracts/virtualizes the controller */
@@ -2714,9 +2542,7 @@
xceiv = 0;
// "udc" is now valid
pullup_disable(udc);
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
udc->gadget.is_otg = (config->otg != 0);
-#endif
/* USB general purpose IRQ: ep0, state changes, dma, etc */
status = request_irq(odev->resource[1].start, omap_udc_irq,
@@ -2845,11 +2671,14 @@
static int __init udc_init(void)
{
- INFO("%s, version: " DRIVER_VERSION
-#ifdef USE_ISO
- " (iso)"
-#endif
- "%s\n", driver_desc,
+ /* should work on many OMAP systems with at most minor changes,
+ * but the 1510 doesn't have an OTG controller.
+ */
+ if (cpu_is_omap1510()) {
+ DBG("no OMAP1510 support yet\n");
+ return -ENODEV;
+ }
+ INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc,
use_dma ? " (dma)" : "");
return driver_register(&udc_driver);
}
diff -wur linux-2.6.10/drivers/usb/gadget/omap_udc.h linux-2.6.10-lab/drivers/usb/gadget/omap_udc.h
--- linux-2.6.10/drivers/usb/gadget/omap_udc.h 2004-12-24 16:34:30.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/omap_udc.h 2007-10-04 19:10:29.000000000 -0400
@@ -146,14 +146,11 @@
u8 bmAttributes;
unsigned double_buf:1;
unsigned stopped:1;
- unsigned fnf:1;
+ unsigned ackwait:1;
unsigned has_dma:1;
- u8 ackwait;
u8 dma_channel;
- u16 dma_counter;
int lch;
struct omap_udc *udc;
- struct timer_list timer;
};
struct omap_udc {
@@ -171,6 +168,7 @@
unsigned ep0_set_config:1;
unsigned ep0_reset_config:1;
unsigned ep0_setup:1;
+ unsigned hmc:6;
struct completion *done;
};
@@ -195,14 +193,7 @@
/*-------------------------------------------------------------------------*/
-#define MOD_CONF_CTRL_0_REG __REG32(MOD_CONF_CTRL_0)
-#define VBUS_W2FC_1510 (1 << 17) /* 0 gpio0, 1 dvdd2 pin */
-
-#define FUNC_MUX_CTRL_0_REG __REG32(FUNC_MUX_CTRL_0)
-#define VBUS_CTRL_1510 (1 << 19) /* 1 connected (software) */
-#define VBUS_MODE_1510 (1 << 18) /* 0 hardware, 1 software */
-
-#define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
+// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f)
#define HMC_1610 (OTG_SYSCON_2_REG & 0x3f)
-#define HMC (cpu_is_omap15xx() ? HMC_1510 : HMC_1610)
+#define HMC HMC_1610
diff -wur linux-2.6.10/drivers/usb/gadget/pxa2xx_udc.c linux-2.6.10-lab/drivers/usb/gadget/pxa2xx_udc.c
--- linux-2.6.10/drivers/usb/gadget/pxa2xx_udc.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/pxa2xx_udc.c 2007-10-04 19:10:29.000000000 -0400
@@ -92,6 +92,10 @@
// #define USE_OUT_DMA
// #define DISABLE_TEST_MODE
+#ifdef CONFIG_PROC_FS
+#define UDC_PROC_FILE
+#endif
+
#ifdef CONFIG_ARCH_IXP4XX
#undef USE_DMA
@@ -105,6 +109,12 @@
#include "pxa2xx_udc.h"
+#ifdef CONFIG_EMBEDDED
+/* few strings, and little code to use them */
+#undef DEBUG
+#undef UDC_PROC_FILE
+#endif
+
#ifdef USE_DMA
static int use_dma = 1;
module_param(use_dma, bool, 0);
@@ -1202,7 +1212,7 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#ifdef UDC_PROC_FILE
static const char proc_node_name [] = "driver/udc";
@@ -1358,12 +1368,11 @@
#define remove_proc_files() \
remove_proc_entry(proc_node_name, NULL)
-#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
-
+#else /* !UDC_PROC_FILE */
#define create_proc_files() do {} while (0)
#define remove_proc_files() do {} while (0)
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+#endif /* UDC_PROC_FILE */
/* "function" sysfs attribute */
static ssize_t
diff -wur linux-2.6.10/drivers/usb/gadget/rndis.c linux-2.6.10-lab/drivers/usb/gadget/rndis.c
--- linux-2.6.10/drivers/usb/gadget/rndis.c 2004-12-24 16:33:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/rndis.c 2007-10-04 19:10:29.000000000 -0400
@@ -70,6 +70,8 @@
#define RNDIS_MAX_CONFIGS 1
+static struct proc_dir_entry *rndis_connect_dir;
+static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
@@ -121,7 +123,7 @@
DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
length = 4;
/* Bogus question!
- * Hardware must be ready to receive high level protocols.
+ * Hardware must be ready to recieve high level protocols.
* BTW:
* reddite ergo quae sunt Caesaris Caesari
* et quae sunt Dei Deo!
@@ -1273,9 +1275,7 @@
return 0;
}
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
+int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
void *data)
{
char *out = page;
@@ -1320,7 +1320,7 @@
return len;
}
-static int rndis_proc_write (struct file *file, const char __user *buffer,
+int rndis_proc_write (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
rndis_params *p = data;
@@ -1365,40 +1365,43 @@
return count;
}
-#define NAME_TEMPLATE "driver/rndis-%03d"
-
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
-
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-
int __init rndis_init (void)
{
u8 i;
+ char name [4];
- for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- char name [20];
+ /* FIXME this should probably be /proc/driver/rndis,
+ * and only if debugging is enabled
+ */
- sprintf (name, NAME_TEMPLATE, i);
+ if (!(rndis_connect_dir = proc_mkdir ("rndis", NULL))) {
+ printk (KERN_ERR "%s: couldn't create /proc/rndis entry",
+ __FUNCTION__);
+ return -EIO;
+ }
+
+ for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
+ sprintf (name, "%03d", i);
if (!(rndis_connect_state [i]
- = create_proc_entry (name, 0660, NULL)))
+ = create_proc_entry (name, 0660,
+ rndis_connect_dir)))
{
DEBUG ("%s :remove entries", __FUNCTION__);
- while (i) {
- sprintf (name, NAME_TEMPLATE, --i);
- remove_proc_entry (name, NULL);
+ for (i--; i > 0; i--) {
+ sprintf (name, "%03d", i);
+ remove_proc_entry (name, rndis_connect_dir);
}
DEBUG ("\n");
+
+ remove_proc_entry ("000", rndis_connect_dir);
+ remove_proc_entry ("rndis", NULL);
return -EIO;
}
-
rndis_connect_state [i]->nlink = 1;
rndis_connect_state [i]->write_proc = rndis_proc_write;
rndis_connect_state [i]->read_proc = rndis_proc_read;
rndis_connect_state [i]->data = (void *)
(rndis_per_dev_params + i);
-#endif
rndis_per_dev_params [i].confignr = i;
rndis_per_dev_params [i].used = 0;
rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED;
@@ -1412,14 +1415,14 @@
void rndis_exit (void)
{
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
u8 i;
- char name [20];
+ char name [4];
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
- sprintf (name, NAME_TEMPLATE, i);
- remove_proc_entry (name, NULL);
+ sprintf (name, "%03d", i);
+ remove_proc_entry (name, rndis_connect_dir);
}
-#endif
+ remove_proc_entry ("rndis", NULL);
+ return;
}
diff -wur linux-2.6.10/drivers/usb/gadget/serial.c linux-2.6.10-lab/drivers/usb/gadget/serial.c
--- linux-2.6.10/drivers/usb/gadget/serial.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/serial.c 2007-10-04 19:10:29.000000000 -0400
@@ -123,84 +123,10 @@
})
-/* CDC-ACM Defines and Structures */
-
-#define USB_CDC_SUBCLASS_ACM 2
-
-#define USB_CDC_CTRL_PROTO_NONE 0
-#define USB_CDC_CTRL_PROTO_AT 1
-#define USB_CDC_CTRL_PROTO_VENDOR 0xff
-
-#define USB_CDC_SUBTYPE_HEADER 0
-#define USB_CDC_SUBTYPE_CALL_MGMT 1
-#define USB_CDC_SUBTYPE_ACM 2
-#define USB_CDC_SUBTYPE_UNION 6
-
-#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
-#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
-
-#define USB_CDC_REQ_SET_LINE_CODING 0x20
-#define USB_CDC_REQ_GET_LINE_CODING 0x21
-#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
-
-#define USB_CDC_1_STOP_BITS 0
-#define USB_CDC_1_5_STOP_BITS 1
-#define USB_CDC_2_STOP_BITS 2
-
-#define USB_CDC_NO_PARITY 0
-#define USB_CDC_ODD_PARITY 1
-#define USB_CDC_EVEN_PARITY 2
-#define USB_CDC_MARK_PARITY 3
-#define USB_CDC_SPACE_PARITY 4
-
-/* Header Functional Descriptor from CDC spec 5.2.3.1 */
-struct usb_cdc_header_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u16 bcdCDC;
-} __attribute__ ((packed));
-
-/* Call Management Descriptor from CDC spec 5.2.3.3 */
-struct usb_cdc_call_mgmt_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bmCapabilities;
- u8 bDataInterface;
-} __attribute__ ((packed));
-
-/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */
-struct usb_cdc_acm_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bmCapabilities;
-} __attribute__ ((packed));
-
-/* Union Functional Descriptor from CDC spec 5.2.3.8 */
-struct usb_cdc_union_desc {
- u8 bLength;
- u8 bDescriptorType;
- u8 bDescriptorSubType;
- u8 bMasterInterface0;
- u8 bSlaveInterface0;
- /* ... and there could be other slave interfaces */
-} __attribute__ ((packed));
-
-/* Line Coding Structure from CDC spec 6.2.13 */
-struct usb_cdc_line_coding {
- u32 dwDTERate;
- u8 bCharFormat;
- u8 bParityType;
- u8 bDataBits;
-} __attribute__ ((packed));
-
-
/* Defines */
-#define GS_VERSION_STR "v2.0"
-#define GS_VERSION_NUM 0x0200
+#define GS_VERSION_STR "v1.0"
+#define GS_VERSION_NUM 0x0100
#define GS_LONG_NAME "Gadget Serial"
#define GS_SHORT_NAME "g_serial"
@@ -212,13 +138,13 @@
#define GS_NUM_CONFIGS 1
#define GS_NO_CONFIG_ID 0
-#define GS_BULK_CONFIG_ID 1
-#define GS_ACM_CONFIG_ID 2
+#define GS_BULK_CONFIG_ID 2
+
+#define GS_NUM_INTERFACES 1
+#define GS_INTERFACE_ID 0
+#define GS_ALT_INTERFACE_ID 0
-#define GS_MAX_NUM_INTERFACES 2
-#define GS_BULK_INTERFACE_ID 0
-#define GS_CONTROL_INTERFACE_ID 0
-#define GS_DATA_INTERFACE_ID 1
+#define GS_NUM_ENDPOINTS 2
#define GS_MAX_DESC_LEN 256
@@ -230,23 +156,9 @@
#define GS_CLOSE_TIMEOUT 15
-#define GS_DEFAULT_USE_ACM 0
-
-#define GS_DEFAULT_DTE_RATE 9600
-#define GS_DEFAULT_DATA_BITS 8
-#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
-#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS
-
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
/* debug settings */
-#ifdef GS_DEBUG
-static int debug = 1;
+#if G_SERIAL_DEBUG
+static int debug = G_SERIAL_DEBUG;
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
@@ -260,7 +172,9 @@
#define gs_debug_level(level, format, arg...) \
do { } while(0)
-#endif /* GS_DEBUG */
+#endif /* G_SERIAL_DEBUG */
+
+
/* Thanks to NetChip Technologies for donating this product ID.
*
@@ -269,10 +183,6 @@
*/
#define GS_VENDOR_ID 0x0525 /* NetChip */
#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */
-#define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */
-
-#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
-#define GS_NOTIFY_MAXPACKET 8
/* Structures */
@@ -303,7 +213,6 @@
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
struct gs_buf *port_write_buf;
- struct usb_cdc_line_coding port_line_coding;
};
/* the device structure holds info for the USB device */
@@ -311,15 +220,8 @@
struct usb_gadget *dev_gadget; /* gadget device pointer */
spinlock_t dev_lock; /* lock for set/reset config */
int dev_config; /* configuration number */
- struct usb_ep *dev_notify_ep; /* address of notify endpoint */
struct usb_ep *dev_in_ep; /* address of in endpoint */
struct usb_ep *dev_out_ep; /* address of out endpoint */
- struct usb_endpoint_descriptor /* desciptor of notify ep */
- *dev_notify_ep_desc;
- struct usb_endpoint_descriptor /* descriptor of in endpoint */
- *dev_in_ep_desc;
- struct usb_endpoint_descriptor /* descriptor of out endpoint */
- *dev_out_ep_desc;
struct usb_request *dev_ctrl_req; /* control request */
struct list_head dev_req_list; /* list of write requests */
int dev_sched_port; /* round robin port scheduled */
@@ -336,7 +238,7 @@
/* tty driver */
static int gs_open(struct tty_struct *tty, struct file *file);
static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty,
+static int gs_write(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count);
static void gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
@@ -362,16 +264,12 @@
static void gs_unbind(struct usb_gadget *gadget);
static int gs_setup(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl);
-static int gs_setup_standard(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl);
-static int gs_setup_class(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl);
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
- u8 type, unsigned int index, int is_otg);
+static int gs_build_config_desc(u8 *buf, enum usb_device_speed speed,
+ u8 type, unsigned int index);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
int kmalloc_flags);
@@ -405,7 +303,6 @@
static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
-static const char *EP_NOTIFY_NAME;
static struct semaphore gs_open_close_sem[GS_NUM_PORTS];
@@ -414,8 +311,8 @@
static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;
-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
-
+static unsigned char gs_tmp_buf[GS_TMP_BUF_SIZE];
+static struct semaphore gs_tmp_buf_sem;
/* tty driver struct */
static struct tty_operations gs_tty_ops = {
@@ -440,7 +337,7 @@
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+#endif
.function = GS_LONG_NAME,
.bind = gs_bind,
.unbind = gs_unbind,
@@ -460,21 +357,15 @@
#define GS_MANUFACTURER_STR_ID 1
#define GS_PRODUCT_STR_ID 2
#define GS_SERIAL_STR_ID 3
-#define GS_BULK_CONFIG_STR_ID 4
-#define GS_ACM_CONFIG_STR_ID 5
-#define GS_CONTROL_STR_ID 6
-#define GS_DATA_STR_ID 7
+#define GS_CONFIG_STR_ID 4
-/* static strings, in UTF-8 */
-static char manufacturer[50];
+/* static strings, in iso 8859/1 */
+static char manufacturer[40];
static struct usb_string gs_strings[] = {
{ GS_MANUFACTURER_STR_ID, manufacturer },
{ GS_PRODUCT_STR_ID, GS_LONG_NAME },
{ GS_SERIAL_STR_ID, "0" },
- { GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
- { GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
- { GS_CONTROL_STR_ID, "Gadget Serial Control" },
- { GS_DATA_STR_ID, "Gadget Serial Data" },
+ { GS_CONFIG_STR_ID, "Bulk" },
{ } /* end of list */
};
@@ -487,8 +378,7 @@
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x0200),
- .bDeviceSubClass = 0,
- .bDeviceProtocol = 0,
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
.idVendor = __constant_cpu_to_le16(GS_VENDOR_ID),
.idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID),
.iManufacturer = GS_MANUFACTURER_STR_ID,
@@ -497,104 +387,23 @@
.bNumConfigurations = GS_NUM_CONFIGS,
};
-static struct usb_otg_descriptor gs_otg_descriptor = {
- .bLength = sizeof(gs_otg_descriptor),
- .bDescriptorType = USB_DT_OTG,
- .bmAttributes = USB_OTG_SRP,
-};
-
-static struct usb_config_descriptor gs_bulk_config_desc = {
+static const struct usb_config_descriptor gs_config_desc = {
.bLength = USB_DT_CONFIG_SIZE,
.bDescriptorType = USB_DT_CONFIG,
- /* .wTotalLength computed dynamically */
- .bNumInterfaces = 1,
+ /* .wTotalLength set by gs_build_config_desc */
+ .bNumInterfaces = GS_NUM_INTERFACES,
.bConfigurationValue = GS_BULK_CONFIG_ID,
- .iConfiguration = GS_BULK_CONFIG_STR_ID,
+ .iConfiguration = GS_CONFIG_STR_ID,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = 1,
};
-static struct usb_config_descriptor gs_acm_config_desc = {
- .bLength = USB_DT_CONFIG_SIZE,
- .bDescriptorType = USB_DT_CONFIG,
- /* .wTotalLength computed dynamically */
- .bNumInterfaces = 2,
- .bConfigurationValue = GS_ACM_CONFIG_ID,
- .iConfiguration = GS_ACM_CONFIG_STR_ID,
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 1,
-};
-
-static const struct usb_interface_descriptor gs_bulk_interface_desc = {
+static const struct usb_interface_descriptor gs_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = GS_BULK_INTERFACE_ID,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = GS_DATA_STR_ID,
-};
-
-static const struct usb_interface_descriptor gs_control_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = GS_CONTROL_INTERFACE_ID,
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_CTRL_PROTO_AT,
- .iInterface = GS_CONTROL_STR_ID,
-};
-
-static const struct usb_interface_descriptor gs_data_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = GS_DATA_INTERFACE_ID,
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- .iInterface = GS_DATA_STR_ID,
-};
-
-static const struct usb_cdc_header_desc gs_header_desc = {
- .bLength = sizeof(gs_header_desc),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_HEADER,
- .bcdCDC = __constant_cpu_to_le16(0x0110),
-};
-
-static const struct usb_cdc_call_mgmt_desc gs_call_mgmt_descriptor = {
- .bLength = sizeof(gs_call_mgmt_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_CALL_MGMT,
- .bmCapabilities = 0,
- .bDataInterface = 1, /* index of data interface */
-};
-
-static struct usb_cdc_acm_desc gs_acm_descriptor = {
- .bLength = sizeof(gs_acm_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_ACM,
- .bmCapabilities = 0,
-};
-
-static const struct usb_cdc_union_desc gs_union_desc = {
- .bLength = sizeof(gs_union_desc),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_SUBTYPE_UNION,
- .bMasterInterface0 = 0, /* index of control interface */
- .bSlaveInterface0 = 1, /* index of data interface */
-};
-
-static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
- .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
+ .bNumEndpoints = GS_NUM_ENDPOINTS,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = GS_CONFIG_STR_ID,
};
static struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
@@ -611,38 +420,6 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = {
- (struct usb_descriptor_header *) &gs_otg_descriptor,
- (struct usb_descriptor_header *) &gs_bulk_interface_desc,
- (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
- (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
- NULL,
-};
-
-static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
- (struct usb_descriptor_header *) &gs_otg_descriptor,
- (struct usb_descriptor_header *) &gs_control_interface_desc,
- (struct usb_descriptor_header *) &gs_header_desc,
- (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
- (struct usb_descriptor_header *) &gs_acm_descriptor,
- (struct usb_descriptor_header *) &gs_union_desc,
- (struct usb_descriptor_header *) &gs_fullspeed_notify_desc,
- (struct usb_descriptor_header *) &gs_data_interface_desc,
- (struct usb_descriptor_header *) &gs_fullspeed_in_desc,
- (struct usb_descriptor_header *) &gs_fullspeed_out_desc,
- NULL,
-};
-
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
- .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
-};
-
static struct usb_endpoint_descriptor gs_highspeed_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -657,37 +434,16 @@
.wMaxPacketSize = __constant_cpu_to_le16(512),
};
+#ifdef CONFIG_USB_GADGET_DUALSPEED
static struct usb_qualifier_descriptor gs_qualifier_desc = {
.bLength = sizeof(struct usb_qualifier_descriptor),
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
.bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
/* assumes ep0 uses the same value for both speeds ... */
.bNumConfigurations = GS_NUM_CONFIGS,
};
-
-static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = {
- (struct usb_descriptor_header *) &gs_otg_descriptor,
- (struct usb_descriptor_header *) &gs_bulk_interface_desc,
- (struct usb_descriptor_header *) &gs_highspeed_in_desc,
- (struct usb_descriptor_header *) &gs_highspeed_out_desc,
- NULL,
-};
-
-static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
- (struct usb_descriptor_header *) &gs_otg_descriptor,
- (struct usb_descriptor_header *) &gs_control_interface_desc,
- (struct usb_descriptor_header *) &gs_header_desc,
- (struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
- (struct usb_descriptor_header *) &gs_acm_descriptor,
- (struct usb_descriptor_header *) &gs_union_desc,
- (struct usb_descriptor_header *) &gs_highspeed_notify_desc,
- (struct usb_descriptor_header *) &gs_data_interface_desc,
- (struct usb_descriptor_header *) &gs_highspeed_in_desc,
- (struct usb_descriptor_header *) &gs_highspeed_out_desc,
- NULL,
-};
-
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+#endif
/* Module */
@@ -695,23 +451,20 @@
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
-#ifdef GS_DEBUG
+#if G_SERIAL_DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
+MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on, larger values for more messages");
#endif
-module_param(read_q_size, uint, S_IRUGO);
+module_param(read_q_size, int, 0);
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
-module_param(write_q_size, uint, S_IRUGO);
+module_param(write_q_size, int, 0);
MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");
-module_param(write_buf_size, uint, S_IRUGO);
+module_param(write_buf_size, int, 0);
MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");
-module_param(use_acm, uint, S_IRUGO);
-MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
-
module_init(gs_module_init);
module_exit(gs_module_exit);
@@ -750,6 +503,8 @@
for (i=0; i < GS_NUM_PORTS; i++)
sema_init(&gs_open_close_sem[i], 1);
+ sema_init(&gs_tmp_buf_sem, 1);
+
retval = tty_register_driver(gs_tty_driver);
if (retval) {
usb_gadget_unregister_driver(&gs_gadget_driver);
@@ -789,12 +544,13 @@
struct gs_dev *dev;
struct gs_buf *buf;
struct semaphore *sem;
- int ret;
port_num = tty->index;
gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
+ tty->driver_data = NULL;
+
if (port_num < 0 || port_num >= GS_NUM_PORTS) {
printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
port_num, tty, file);
@@ -823,8 +579,9 @@
printk(KERN_ERR
"gs_open: (%d,%p,%p) device is not connected\n",
port_num, tty, file);
- ret = -ENODEV;
- goto exit_unlock_dev;
+ spin_unlock_irqrestore(&dev->dev_lock, flags);
+ up(sem);
+ return -ENODEV;
}
port = dev->dev_port[port_num];
@@ -832,8 +589,9 @@
if (port == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
port_num, tty, file);
- ret = -ENODEV;
- goto exit_unlock_dev;
+ spin_unlock_irqrestore(&dev->dev_lock, flags);
+ up(sem);
+ return -ENODEV;
}
spin_lock(&port->port_lock);
@@ -842,20 +600,20 @@
if (port->port_dev == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
port_num, tty, file);
- ret = -EIO;
- goto exit_unlock_port;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return -EIO;
}
if (port->port_open_count > 0) {
++port->port_open_count;
+ spin_unlock_irqrestore(&port->port_lock, flags);
gs_debug("gs_open: (%d,%p,%p) already open\n",
port_num, tty, file);
- ret = 0;
- goto exit_unlock_port;
+ up(sem);
+ return 0;
}
- tty->driver_data = NULL;
-
/* mark port as in use, we can drop port lock and sleep if necessary */
port->port_in_use = 1;
@@ -871,16 +629,18 @@
"gs_open: (%d,%p,%p) port disconnected (2)\n",
port_num, tty, file);
port->port_in_use = 0;
- ret = -EIO;
- goto exit_unlock_port;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return -EIO;
}
if ((port->port_write_buf=buf) == NULL) {
printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
port_num, tty, file);
port->port_in_use = 0;
- ret = -ENOMEM;
- goto exit_unlock_port;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return -ENOMEM;
}
}
@@ -892,8 +652,9 @@
printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
port_num, tty, file);
port->port_in_use = 0;
- ret = -EIO;
- goto exit_unlock_port;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return -EIO;
}
tty->driver_data = port;
@@ -901,20 +662,12 @@
port->port_open_count = 1;
port->port_in_use = 0;
- gs_debug("gs_open: (%d,%p,%p) completed\n", port_num, tty, file);
-
- ret = 0;
-
-exit_unlock_port:
spin_unlock_irqrestore(&port->port_lock, flags);
up(sem);
- return ret;
-exit_unlock_dev:
- spin_unlock_irqrestore(&dev->dev_lock, flags);
- up(sem);
- return ret;
+ gs_debug("gs_open: (%d,%p,%p) completed\n", port_num, tty, file);
+ return 0;
}
/*
@@ -942,18 +695,24 @@
printk(KERN_ERR
"gs_close: (%d,%p,%p) port is already closed\n",
port->port_num, tty, file);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return;
}
- if (port->port_open_count > 1) {
+ if (port->port_open_count > 0) {
--port->port_open_count;
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return;
}
/* free disconnected port on final close */
if (port->port_dev == NULL) {
kfree(port);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return;
}
/* mark port as closed but in use, we can drop port lock */
@@ -974,7 +733,9 @@
/* (might have happened during the above sleep) */
if (port->port_dev == NULL) {
kfree(port);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ up(sem);
+ return;
}
gs_buf_clear(port->port_write_buf);
@@ -983,22 +744,20 @@
port->port_tty = NULL;
port->port_in_use = 0;
- gs_debug("gs_close: (%d,%p,%p) completed\n",
- port->port_num, tty, file);
-
-exit:
spin_unlock_irqrestore(&port->port_lock, flags);
up(sem);
+
+ gs_debug("gs_close: (%d,%p,%p) completed\n",
+ port->port_num, tty, file);
}
/*
* gs_write
*/
-static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
+static int gs_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
{
unsigned long flags;
struct gs_port *port = tty->driver_data;
- int ret;
if (port == NULL) {
printk(KERN_ERR "gs_write: NULL port pointer\n");
@@ -1011,36 +770,54 @@
if (count == 0)
return 0;
+ /* copy from user into tmp buffer, get tmp_buf semaphore */
+ if (from_user) {
+ if (count > GS_TMP_BUF_SIZE)
+ count = GS_TMP_BUF_SIZE;
+ down(&gs_tmp_buf_sem);
+ if (copy_from_user(gs_tmp_buf, buf, count) != 0) {
+ up(&gs_tmp_buf_sem);
+ printk(KERN_ERR
+ "gs_write: (%d,%p) cannot copy from user space\n",
+ port->port_num, tty);
+ return -EFAULT;
+ }
+ buf = gs_tmp_buf;
+ }
+
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_dev == NULL) {
printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
port->port_num, tty);
- ret = -EIO;
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ if (from_user)
+ up(&gs_tmp_buf_sem);
+ return -EIO;
}
if (port->port_open_count == 0) {
printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
port->port_num, tty);
- ret = -EBADF;
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ if (from_user)
+ up(&gs_tmp_buf_sem);
+ return -EBADF;
}
count = gs_buf_put(port->port_write_buf, buf, count);
spin_unlock_irqrestore(&port->port_lock, flags);
+ if (from_user)
+ up(&gs_tmp_buf_sem);
+
gs_send(gs_device);
gs_debug("gs_write: (%d,%p) wrote %d bytes\n", port->port_num, tty,
count);
return count;
-
-exit:
- spin_unlock_irqrestore(&port->port_lock, flags);
- return ret;
}
/*
@@ -1063,18 +840,19 @@
if (port->port_dev == NULL) {
printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
port->port_num, tty);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
}
if (port->port_open_count == 0) {
printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
port->port_num, tty);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
}
gs_buf_put(port->port_write_buf, &ch, 1);
-exit:
spin_unlock_irqrestore(&port->port_lock, flags);
}
@@ -1099,23 +877,20 @@
printk(KERN_ERR
"gs_flush_chars: (%d,%p) port is not connected\n",
port->port_num, tty);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
}
if (port->port_open_count == 0) {
printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
port->port_num, tty);
- goto exit;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
}
spin_unlock_irqrestore(&port->port_lock, flags);
gs_send(gs_device);
-
- return;
-
-exit:
- spin_unlock_irqrestore(&port->port_lock, flags);
}
/*
@@ -1312,16 +1087,17 @@
if (len < size)
size = len;
- if (size == 0)
- goto exit;
+ if (size == 0) {
+ spin_unlock(&port->port_lock);
+ return 0;
+ }
size = gs_buf_get(port->port_write_buf, packet, size);
- if (port->port_tty)
wake_up_interruptible(&port->port_tty->write_wait);
-exit:
spin_unlock(&port->port_lock);
+
return size;
}
@@ -1342,7 +1118,6 @@
{
unsigned int len;
struct gs_port *port;
- int ret;
/* TEMPORARY -- only port 0 is supported right now */
port = dev->dev_port[0];
@@ -1355,25 +1130,18 @@
spin_lock(&port->port_lock);
- if (port->port_open_count == 0) {
- printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
- port->port_num);
- ret = -EIO;
- goto exit;
- }
-
if (port->port_tty == NULL) {
printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
port->port_num);
- ret = -EIO;
- goto exit;
+ spin_unlock(&port->port_lock);
+ return -EIO;
}
if (port->port_tty->magic != TTY_MAGIC) {
printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
port->port_num);
- ret = -EIO;
- goto exit;
+ spin_unlock(&port->port_lock);
+ return -EIO;
}
len = (unsigned int)(TTY_FLIPBUF_SIZE - port->port_tty->flip.count);
@@ -1388,11 +1156,9 @@
wake_up_interruptible(&port->port_tty->read_wait);
}
- ret = 0;
-
-exit:
spin_unlock(&port->port_lock);
- return ret;
+
+ return 0;
}
/*
@@ -1497,7 +1263,21 @@
struct usb_ep *ep;
struct gs_dev *dev;
- /* device specific */
+ usb_ep_autoconfig_reset(gadget);
+
+ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
+ if (!ep)
+ goto autoconf_fail;
+ EP_IN_NAME = ep->name;
+ ep->driver_data = ep; /* claim the endpoint */
+
+ ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
+ if (!ep)
+ goto autoconf_fail;
+ EP_OUT_NAME = ep->name;
+ ep->driver_data = ep; /* claim the endpoint */
+
+ /* device specific bcdDevice value in device descriptor */
if (gadget_is_net2280(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0001);
@@ -1507,13 +1287,9 @@
} else if (gadget_is_sh(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0003);
- /* sh doesn't support multiple interfaces or configs */
- use_acm = 0;
} else if (gadget_is_sa1100(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0004);
- /* sa1100 doesn't support necessary endpoints */
- use_acm = 0;
} else if (gadget_is_goku(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0005);
@@ -1526,12 +1302,6 @@
} else if (gadget_is_lh7a40x(gadget)) {
gs_device_desc.bcdDevice =
__constant_cpu_to_le16(GS_VERSION_NUM|0x0008);
- } else if (gadget_is_n9604(gadget)) {
- gs_device_desc.bcdDevice =
- __constant_cpu_to_le16(GS_VERSION_NUM|0x0009);
- } else if (gadget_is_pxa27x(gadget)) {
- gs_device_desc.bcdDevice =
- __constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
} else {
printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
gadget->name);
@@ -1540,44 +1310,11 @@
__constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
}
- usb_ep_autoconfig_reset(gadget);
-
- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
- if (!ep)
- goto autoconf_fail;
- EP_IN_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
-
- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
- if (!ep)
- goto autoconf_fail;
- EP_OUT_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
-
- if (use_acm) {
- ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
- if (!ep) {
- printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
- goto autoconf_fail;
- }
- gs_device_desc.idProduct = __constant_cpu_to_le16(
- GS_CDC_PRODUCT_ID),
- EP_NOTIFY_NAME = ep->name;
- ep->driver_data = ep; /* claim the endpoint */
- }
-
- gs_device_desc.bDeviceClass = use_acm
- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
#ifdef CONFIG_USB_GADGET_DUALSPEED
- gs_qualifier_desc.bDeviceClass = use_acm
- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
/* assume ep0 uses the same packet size for both speeds */
gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
/* assume endpoints are dual-speed */
- gs_highspeed_notify_desc.bEndpointAddress =
- gs_fullspeed_notify_desc.bEndpointAddress;
gs_highspeed_in_desc.bEndpointAddress =
gs_fullspeed_in_desc.bEndpointAddress;
gs_highspeed_out_desc.bEndpointAddress =
@@ -1586,12 +1323,6 @@
usb_gadget_set_selfpowered(gadget);
- if (gadget->is_otg) {
- gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
- gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- }
-
gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
@@ -1646,10 +1377,8 @@
/* read/write requests already freed, only control request remains */
if (dev != NULL) {
- if (dev->dev_ctrl_req != NULL) {
+ if (dev->dev_ctrl_req != NULL)
gs_free_req(gadget->ep0, dev->dev_ctrl_req);
- dev->dev_ctrl_req = NULL;
- }
gs_free_ports(dev);
kfree(dev);
set_gadget_data(gadget, NULL);
@@ -1668,51 +1397,10 @@
* Returns the size of the data sent to the host, or a negative
* error number.
*/
-static int gs_setup(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl)
-{
- int ret = -EOPNOTSUPP;
- struct gs_dev *dev = get_gadget_data(gadget);
- struct usb_request *req = dev->dev_ctrl_req;
-
- switch (ctrl->bRequestType & USB_TYPE_MASK) {
- case USB_TYPE_STANDARD:
- ret = gs_setup_standard(gadget,ctrl);
- break;
-
- case USB_TYPE_CLASS:
- ret = gs_setup_class(gadget,ctrl);
- break;
-
- default:
- printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
- ctrl->wIndex, ctrl->wLength);
- break;
- }
-
- /* respond with data transfer before status phase? */
- if (ret >= 0) {
- req->length = ret;
- req->zero = ret < ctrl->wLength
- && (ret % gadget->ep0->maxpacket) == 0;
- ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (ret < 0) {
- printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n",
- ret);
- req->status = 0;
- gs_setup_complete(gadget->ep0, req);
- }
- }
-
- /* device either stalls (ret < 0) or reports success */
- return ret;
-}
-
-static int gs_setup_standard(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl)
+static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
int ret = -EOPNOTSUPP;
+ unsigned int sv_config;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
@@ -1738,14 +1426,10 @@
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
- break;
- /* fall through */
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- ret = gs_build_config_buf(req->buf, gadget->speed,
- ctrl->wValue >> 8, ctrl->wValue & 0xff,
- gadget->is_otg);
+ ret = gs_build_config_desc(req->buf, gadget->speed,
+ ctrl->wValue >> 8, ctrl->wValue & 0xff);
if (ret >= 0)
ret = min(ctrl->wLength, (u16)ret);
break;
@@ -1776,106 +1460,59 @@
break;
case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE
- || !dev->dev_config || ctrl->wIndex >= GS_MAX_NUM_INTERFACES)
- break;
- if (dev->dev_config == GS_BULK_CONFIG_ID
- && ctrl->wIndex != GS_BULK_INTERFACE_ID)
- break;
- /* no alternate interface settings */
- if (ctrl->wValue != 0)
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE)
break;
spin_lock(&dev->dev_lock);
- /* PXA hardware partially handles SET_INTERFACE;
- * we need to kluge around that interference. */
- if (gadget_is_pxa(gadget)) {
- ret = gs_set_config(dev, use_acm ?
- GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID);
- goto set_interface_done;
- }
- if (dev->dev_config != GS_BULK_CONFIG_ID
- && ctrl->wIndex == GS_CONTROL_INTERFACE_ID) {
- if (dev->dev_notify_ep) {
- usb_ep_disable(dev->dev_notify_ep);
- usb_ep_enable(dev->dev_notify_ep, dev->dev_notify_ep_desc);
- }
- } else {
- usb_ep_disable(dev->dev_in_ep);
- usb_ep_disable(dev->dev_out_ep);
- usb_ep_enable(dev->dev_in_ep, dev->dev_in_ep_desc);
- usb_ep_enable(dev->dev_out_ep, dev->dev_out_ep_desc);
- }
+ if (dev->dev_config == GS_BULK_CONFIG_ID
+ && ctrl->wIndex == GS_INTERFACE_ID
+ && ctrl->wValue == GS_ALT_INTERFACE_ID) {
+ sv_config = dev->dev_config;
+ /* since there is only one interface, setting the */
+ /* interface is equivalent to setting the config */
+ gs_reset_config(dev);
+ gs_set_config(dev, sv_config);
ret = 0;
-set_interface_done:
+ }
spin_unlock(&dev->dev_lock);
break;
case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
- || dev->dev_config == GS_NO_CONFIG_ID)
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ break;
+ if (dev->dev_config == GS_NO_CONFIG_ID)
break;
- if (ctrl->wIndex >= GS_MAX_NUM_INTERFACES
- || (dev->dev_config == GS_BULK_CONFIG_ID
- && ctrl->wIndex != GS_BULK_INTERFACE_ID)) {
+ if (ctrl->wIndex != GS_INTERFACE_ID) {
ret = -EDOM;
break;
}
- /* no alternate interface settings */
- *(u8 *)req->buf = 0;
+ *(u8 *)req->buf = GS_ALT_INTERFACE_ID;
ret = min(ctrl->wLength, (u16)1);
break;
default:
- printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+ printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
ctrl->wIndex, ctrl->wLength);
break;
- }
- return ret;
-}
-
-static int gs_setup_class(struct usb_gadget *gadget,
- const struct usb_ctrlrequest *ctrl)
-{
- int ret = -EOPNOTSUPP;
- struct gs_dev *dev = get_gadget_data(gadget);
- struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
- struct usb_request *req = dev->dev_ctrl_req;
-
- switch (ctrl->bRequest) {
- case USB_CDC_REQ_SET_LINE_CODING:
- ret = min(ctrl->wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
- if (port) {
- spin_lock(&port->port_lock);
- memcpy(&port->port_line_coding, req->buf, ret);
- spin_unlock(&port->port_lock);
}
- break;
- case USB_CDC_REQ_GET_LINE_CODING:
- port = dev->dev_port[0]; /* ACM only has one port */
- ret = min(ctrl->wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
- if (port) {
- spin_lock(&port->port_lock);
- memcpy(req->buf, &port->port_line_coding, ret);
- spin_unlock(&port->port_lock);
+ /* respond with data transfer before status phase? */
+ if (ret >= 0) {
+ req->length = ret;
+ req->zero = ret < ctrl->wLength
+ && (ret % gadget->ep0->maxpacket) == 0;
+ ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "gs_setup: cannot queue response, ret=%d\n",
+ ret);
+ req->status = 0;
+ gs_setup_complete(gadget->ep0, req);
}
- break;
-
- case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- ret = 0;
- break;
-
- default:
- printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
- ctrl->bRequestType, ctrl->bRequest, ctrl->wValue,
- ctrl->wIndex, ctrl->wLength);
- break;
}
+ /* device either stalls (ret < 0) or reports success */
return ret;
}
@@ -1934,7 +1571,6 @@
int ret = 0;
struct usb_gadget *gadget = dev->dev_gadget;
struct usb_ep *ep;
- struct usb_endpoint_descriptor *ep_desc;
struct usb_request *req;
struct gs_req_entry *req_entry;
@@ -1948,90 +1584,55 @@
gs_reset_config(dev);
- switch (config) {
- case GS_NO_CONFIG_ID:
+ if (config == GS_NO_CONFIG_ID)
return 0;
- case GS_BULK_CONFIG_ID:
- if (use_acm)
- return -EINVAL;
- /* device specific optimizations */
- if (gadget_is_net2280(gadget))
- net2280_set_fifo_mode(gadget, 1);
- break;
- case GS_ACM_CONFIG_ID:
- if (!use_acm)
+
+ if (config != GS_BULK_CONFIG_ID)
return -EINVAL;
+
/* device specific optimizations */
if (gadget_is_net2280(gadget))
net2280_set_fifo_mode(gadget, 1);
- break;
- default:
- return -EINVAL;
- }
-
- dev->dev_config = config;
gadget_for_each_ep(ep, gadget) {
- if (EP_NOTIFY_NAME
- && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_notify_desc,
- &gs_fullspeed_notify_desc);
- ret = usb_ep_enable(ep,ep_desc);
- if (ret == 0) {
- ep->driver_data = dev;
- dev->dev_notify_ep = ep;
- dev->dev_notify_ep_desc = ep_desc;
- } else {
- printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n",
- ep->name, ret);
- goto exit_reset_config;
- }
- }
-
- else if (strcmp(ep->name, EP_IN_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_in_desc,
- &gs_fullspeed_in_desc);
- ret = usb_ep_enable(ep,ep_desc);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ ret = usb_ep_enable(ep,
+ gadget->speed == USB_SPEED_HIGH ?
+ &gs_highspeed_in_desc : &gs_fullspeed_in_desc);
if (ret == 0) {
ep->driver_data = dev;
dev->dev_in_ep = ep;
- dev->dev_in_ep_desc = ep_desc;
} else {
printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
ep->name, ret);
- goto exit_reset_config;
+ gs_reset_config(dev);
+ return ret;
}
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_out_desc,
+ ret = usb_ep_enable(ep,
+ gadget->speed == USB_SPEED_HIGH ?
+ &gs_highspeed_out_desc :
&gs_fullspeed_out_desc);
- ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
ep->driver_data = dev;
dev->dev_out_ep = ep;
- dev->dev_out_ep_desc = ep_desc;
} else {
printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
ep->name, ret);
- goto exit_reset_config;
+ gs_reset_config(dev);
+ return ret;
}
}
}
- if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
- || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
+ if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL) {
+ gs_reset_config(dev);
printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
- ret = -ENODEV;
- goto exit_reset_config;
+ return -ENODEV;
}
/* allocate and queue read requests */
@@ -2044,9 +1645,10 @@
ret);
}
} else {
- printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
- ret = -ENOMEM;
- goto exit_reset_config;
+ gs_reset_config(dev);
+ printk(KERN_ERR
+ "gs_set_config: cannot allocate read requests\n");
+ return -ENOMEM;
}
}
@@ -2057,22 +1659,20 @@
req_entry->re_req->complete = gs_write_complete;
list_add(&req_entry->re_entry, &dev->dev_req_list);
} else {
- printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
- ret = -ENOMEM;
- goto exit_reset_config;
+ gs_reset_config(dev);
+ printk(KERN_ERR
+ "gs_set_config: cannot allocate write requests\n");
+ return -ENOMEM;
}
}
- printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
+ dev->dev_config = config;
+
+ printk(KERN_INFO "gs_set_config: %s configured for %s speed\n",
GS_LONG_NAME,
- gadget->speed == USB_SPEED_HIGH ? "high" : "full",
- config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
+ gadget->speed == USB_SPEED_HIGH ? "high" : "full");
return 0;
-
-exit_reset_config:
- gs_reset_config(dev);
- return ret;
}
/*
@@ -2109,10 +1709,6 @@
/* disable endpoints, forcing completion of pending i/o; */
/* completion handlers free their requests in this case */
- if (dev->dev_notify_ep) {
- usb_ep_disable(dev->dev_notify_ep);
- dev->dev_notify_ep = NULL;
- }
if (dev->dev_in_ep) {
usb_ep_disable(dev->dev_in_ep);
dev->dev_in_ep = NULL;
@@ -2124,48 +1720,41 @@
}
/*
- * gs_build_config_buf
+ * gs_build_config_desc
*
- * Builds the config descriptors in the given buffer and returns the
+ * Builds a config descriptor in the given buffer and returns the
* length, or a negative error number.
*/
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
- u8 type, unsigned int index, int is_otg)
+static int gs_build_config_desc(u8 *buf, enum usb_device_speed speed, u8 type, unsigned int index)
{
- int len;
int high_speed;
- const struct usb_config_descriptor *config_desc;
- const struct usb_descriptor_header **function;
+ int len = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE
+ + GS_NUM_ENDPOINTS * USB_DT_ENDPOINT_SIZE;
- if (index >= gs_device_desc.bNumConfigurations)
+ /* only one config */
+ if (index != 0)
return -EINVAL;
+ memcpy(buf, &gs_config_desc, USB_DT_CONFIG_SIZE);
+ ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+ ((struct usb_config_descriptor *)buf)->wTotalLength = __constant_cpu_to_le16(len);
+ buf += USB_DT_CONFIG_SIZE;
+
+ memcpy(buf, &gs_interface_desc, USB_DT_INTERFACE_SIZE);
+ buf += USB_DT_INTERFACE_SIZE;
+
/* other speed switches high and full speed */
high_speed = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
high_speed = !high_speed;
- if (use_acm) {
- config_desc = &gs_acm_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_acm_highspeed_function,
- gs_acm_fullspeed_function);
- } else {
- config_desc = &gs_bulk_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_bulk_highspeed_function,
- gs_bulk_fullspeed_function);
- }
-
- /* for now, don't advertise srp-only devices */
- if (!is_otg)
- function++;
-
- len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
- if (len < 0)
- return len;
-
- ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+ memcpy(buf,
+ high_speed ? &gs_highspeed_in_desc : &gs_fullspeed_in_desc,
+ USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ memcpy(buf,
+ high_speed ? &gs_highspeed_out_desc : &gs_fullspeed_out_desc,
+ USB_DT_ENDPOINT_SIZE);
return len;
}
@@ -2187,7 +1776,8 @@
if (req != NULL) {
req->length = len;
- req->buf = kmalloc(len, kmalloc_flags);
+ req->buf = usb_ep_alloc_buffer(ep, len, &req->dma,
+ kmalloc_flags);
if (req->buf == NULL) {
usb_ep_free_request(ep, req);
return NULL;
@@ -2205,7 +1795,9 @@
static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
{
if (ep != NULL && req != NULL) {
- kfree(req->buf);
+ if (req->buf != NULL)
+ usb_ep_free_buffer(ep, req->buf, req->dma,
+ req->length);
usb_ep_free_request(ep, req);
}
}
@@ -2272,10 +1864,6 @@
memset(port, 0, sizeof(struct gs_port));
port->port_dev = dev;
port->port_num = i;
- port->port_line_coding.dwDTERate = GS_DEFAULT_DTE_RATE;
- port->port_line_coding.bCharFormat = GS_DEFAULT_CHAR_FORMAT;
- port->port_line_coding.bParityType = GS_DEFAULT_PARITY;
- port->port_line_coding.bDataBits = GS_DEFAULT_DATA_BITS;
spin_lock_init(&port->port_lock);
init_waitqueue_head(&port->port_write_wait);
@@ -2318,10 +1906,8 @@
if (port->port_open_count > 0 || port->port_in_use) {
port->port_dev = NULL;
wake_up_interruptible(&port->port_write_wait);
- if (port->port_tty) {
wake_up_interruptible(&port->port_tty->read_wait);
wake_up_interruptible(&port->port_tty->write_wait);
- }
} else {
kfree(port);
}
diff -wur linux-2.6.10/drivers/usb/gadget/zero.c linux-2.6.10-lab/drivers/usb/gadget/zero.c
--- linux-2.6.10/drivers/usb/gadget/zero.c 2004-12-24 16:34:32.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/gadget/zero.c 2007-10-04 19:10:29.000000000 -0400
@@ -396,7 +396,7 @@
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
-static char manufacturer [50];
+static char manufacturer [40];
static char serial [40];
/* static strings, in UTF-8 */
@@ -1188,10 +1188,6 @@
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
} else if (gadget_is_lh7a40x(gadget)) {
device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
- } else if (gadget_is_n9604(gadget)) {
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
- } else if (gadget_is_pxa27x(gadget)) {
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
} else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
diff -wur linux-2.6.10/drivers/usb/host/Kconfig linux-2.6.10-lab/drivers/usb/host/Kconfig
--- linux-2.6.10/drivers/usb/host/Kconfig 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/host/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -47,6 +47,13 @@
To compile this driver as a module, choose M here: the
module will be called ehci-hcd.
+config USB_PHCI_HCD
+ tristate "PHCI HCD (USB 2.0) support"
+ depends on USB
+ ---help---
+ Philips ISP1762 USB 2.0 Host Controller Interface
+
+
config USB_EHCI_SPLIT_ISO
bool "Full speed ISO transactions (EXPERIMENTAL)"
depends on USB_EHCI_HCD && EXPERIMENTAL
diff -wur linux-2.6.10/drivers/usb/host/Makefile linux-2.6.10-lab/drivers/usb/host/Makefile
--- linux-2.6.10/drivers/usb/host/Makefile 2004-12-24 16:35:39.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/host/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -8,3 +8,4 @@
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
+obj-$(CONFIG_USB_PHCI_HCD) += phci/
\ No newline at end of file
diff -wur linux-2.6.10/drivers/usb/net/kaweth.c linux-2.6.10-lab/drivers/usb/net/kaweth.c
--- linux-2.6.10/drivers/usb/net/kaweth.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/net/kaweth.c 2007-10-04 19:10:23.000000000 -0400
@@ -467,7 +467,7 @@
0,
KAWETH_CONTROL_TIMEOUT);
- udelay(10000);
+ mdelay(10);
kaweth_dbg("kaweth_reset() returns %d.",result);
diff -wur linux-2.6.10/drivers/usb/serial/Kconfig linux-2.6.10-lab/drivers/usb/serial/Kconfig
--- linux-2.6.10/drivers/usb/serial/Kconfig 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/Kconfig 2007-10-04 19:10:22.000000000 -0400
@@ -53,6 +53,15 @@
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_ANYDATA
+ tristate "USB AnyDATA CDMA Wireless Driver"
+ depends on USB_SERIAL
+ help
+ Say Y here if you want to use a AnyDATA CDMA device.
+
+ To compile this driver as a module, choose M here: the module will
+ be called "anydata".
+
config USB_SERIAL_BELKIN
tristate "USB Belkin and Peracom Single Port Serial Driver"
depends on USB_SERIAL
diff -wur linux-2.6.10/drivers/usb/serial/Makefile linux-2.6.10-lab/drivers/usb/serial/Makefile
--- linux-2.6.10/drivers/usb/serial/Makefile 2004-12-24 16:34:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/Makefile 2007-10-04 19:10:22.000000000 -0400
@@ -11,6 +11,7 @@
usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
+obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
diff -wur linux-2.6.10/drivers/usb/serial/bus.c linux-2.6.10-lab/drivers/usb/serial/bus.c
--- linux-2.6.10/drivers/usb/serial/bus.c 2004-12-24 16:35:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/bus.c 2007-10-04 19:10:22.000000000 -0400
@@ -70,9 +70,15 @@
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg(&port->serial->dev->dev,
+ "%s converter now attached to ttyUSB%d\n",
+ driver->name, minor);
+#else
dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d\n",
driver->name, minor);
+#endif
exit:
return retval;
@@ -103,8 +109,13 @@
exit:
minor = port->number;
tty_unregister_device (usb_serial_tty_driver, minor);
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg(dev, "%s converter now disconnected from ttyUSB%d\n",
+ driver->name, minor);
+#else
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->name, minor);
+#endif
return retval;
}
diff -wur linux-2.6.10/drivers/usb/serial/generic.c linux-2.6.10-lab/drivers/usb/serial/generic.c
--- linux-2.6.10/drivers/usb/serial/generic.c 2004-12-24 16:33:52.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/generic.c 2007-10-04 19:10:22.000000000 -0400
@@ -9,6 +9,10 @@
*
*/
+/*
+ * Modifications Copyright (C) 2005 Lab126, Inc. All Rights Reserved.
+ */
+
#include
#include
#include
@@ -35,6 +39,11 @@
static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
+#ifdef CONFIG_ARCH_LAB126
+static int usb_serial_generic_tiocmset (struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
+#endif
+
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_device_type usb_serial_generic_device = {
.owner = THIS_MODULE,
@@ -46,6 +55,9 @@
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.shutdown = usb_serial_generic_shutdown,
+#ifdef CONFIG_ARCH_LAB126
+ .tiocmset = usb_serial_generic_tiocmset,
+#endif
};
/* we want to look at all devices, as the vendor/product id can change
@@ -75,6 +87,43 @@
};
#endif
+#ifdef CONFIG_ARCH_LAB126
+/* see section 6.2.14 of the USB CDC spec 1.1 ("SetControlLineState"). perhaps these
+ * changes are generic enough to live in here (at least for our version); if not we
+ * should split into another module
+ */
+#define USB_COMM_SET_CONTROL_LINE_STATE_REQ_TYPE 0x21
+#define USB_COMM_SET_CONTROL_LINE_STATE_REQ_CODE 0x22
+
+#define USB_COMM_DTR_CLEAR 0x0000
+#define USB_COMM_DTR_SET 0x0001
+
+#define USB_COMM_CONTROL_TIMEOUT 500
+
+static int send_comm_control_msg(struct usb_serial *serial, u16 value)
+{
+ return usb_control_msg(serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ USB_COMM_SET_CONTROL_LINE_STATE_REQ_CODE, USB_COMM_SET_CONTROL_LINE_STATE_REQ_TYPE,
+ value, 0, NULL, 0, USB_COMM_CONTROL_TIMEOUT);
+}
+
+static int usb_serial_generic_tiocmset (struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ int result = 0;
+
+ if (set & TIOCM_DTR) {
+ result |= send_comm_control_msg(port->serial, USB_COMM_DTR_SET);
+ }
+
+ if (clear & TIOCM_DTR) {
+ result |= send_comm_control_msg(port->serial, USB_COMM_DTR_CLEAR);
+ }
+
+ return result;
+}
+#endif
+
int usb_serial_generic_register (int _debug)
{
int retval = 0;
@@ -296,11 +345,12 @@
return;
}
- usb_serial_port_softint((void *)port);
-
- schedule_work(&port->work);
+ usb_serial_port_softint(port);
}
+EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
+EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
+
void usb_serial_generic_shutdown (struct usb_serial *serial)
{
int i;
diff -wur linux-2.6.10/drivers/usb/serial/usb-serial.c linux-2.6.10-lab/drivers/usb/serial/usb-serial.c
--- linux-2.6.10/drivers/usb/serial/usb-serial.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/usb-serial.c 2007-10-04 19:10:22.000000000 -0400
@@ -361,6 +361,7 @@
drivers depend on it.
*/
+static ushort maxSize = 0;
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list);
@@ -782,9 +783,21 @@
return -EINVAL;
}
-void usb_serial_port_softint(void *private)
+/* Ported fixes to usb_serial_port_softint from 2.6.18 */
+
+/*
+ * We would be calling tty_wakeup here, but unfortunately some line
+ * disciplines have an annoying habit of calling tty->write from
+ * the write wakeup callback (e.g. n_hdlc.c).
+ */
+void usb_serial_port_softint(struct usb_serial_port *port)
{
- struct usb_serial_port *port = (struct usb_serial_port *)private;
+ schedule_work(&port->work);
+}
+
+static void usb_serial_port_work(void *data)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) data;
struct tty_struct *tty;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -992,7 +1005,11 @@
#endif
/* found all that we need */
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg(&interface->dev, "%s converter detected\n", type->name);
+#else
dev_info(&interface->dev, "%s converter detected\n", type->name);
+#endif
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
@@ -1047,7 +1064,7 @@
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
- INIT_WORK(&port->work, usb_serial_port_softint, port);
+ INIT_WORK(&port->work, usb_serial_port_work, port);
serial->port[i] = port;
}
@@ -1060,7 +1077,7 @@
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = endpoint->wMaxPacketSize;
+ buffer_size = endpoint->wMaxPacketSize > maxSize ? endpoint->wMaxPacketSize : maxSize;
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1084,7 +1101,7 @@
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = endpoint->wMaxPacketSize;
+ buffer_size = endpoint->wMaxPacketSize > maxSize ? endpoint->wMaxPacketSize : maxSize;
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1109,7 +1126,7 @@
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = endpoint->wMaxPacketSize;
+ buffer_size = endpoint->wMaxPacketSize > maxSize ? endpoint->wMaxPacketSize : maxSize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->interrupt_in_buffer) {
@@ -1136,7 +1153,7 @@
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = endpoint->wMaxPacketSize;
+ buffer_size = endpoint->wMaxPacketSize > maxSize ? endpoint->wMaxPacketSize : maxSize;
port->interrupt_out_size = buffer_size;
port->interrupt_out_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1249,7 +1266,11 @@
* cause it to be cleaned up */
kref_put(&serial->kref, destroy_serial);
}
+#ifdef SQUELCH_USB_CHATTER
+ dev_dbg(dev, "device disconnected\n");
+#else
dev_info(dev, "device disconnected\n");
+#endif
}
static struct tty_operations serial_ops = {
@@ -1426,3 +1447,5 @@
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(maxSize, ushort, 0);
+MODULE_PARM_DESC(maxSize, "User specified USB endpoint size");
diff -wur linux-2.6.10/drivers/usb/serial/usb-serial.h linux-2.6.10-lab/drivers/usb/serial/usb-serial.h
--- linux-2.6.10/drivers/usb/serial/usb-serial.h 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/serial/usb-serial.h 2007-10-04 19:10:22.000000000 -0400
@@ -274,7 +274,7 @@
extern int usb_serial_register(struct usb_serial_device_type *new_device);
extern void usb_serial_deregister(struct usb_serial_device_type *device);
-extern void usb_serial_port_softint(void *private);
+extern void usb_serial_port_softint(struct usb_serial_port *port);
extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
extern void usb_serial_disconnect(struct usb_interface *iface);
diff -wur linux-2.6.10/drivers/usb/storage/freecom.c linux-2.6.10-lab/drivers/usb/storage/freecom.c
--- linux-2.6.10/drivers/usb/storage/freecom.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/freecom.c 2007-10-04 19:10:29.000000000 -0400
@@ -290,7 +290,7 @@
case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
case MODE_SENSE:
case MODE_SENSE_10:
- length = le16_to_cpu(fst->Count);
+ length = fst->Count;
break;
default:
length = srb->request_bufflen;
diff -wur linux-2.6.10/drivers/usb/storage/isd200.c linux-2.6.10-lab/drivers/usb/storage/isd200.c
--- linux-2.6.10/drivers/usb/storage/isd200.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/isd200.c 2007-10-04 19:10:29.000000000 -0400
@@ -555,7 +555,7 @@
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (us->sm_state == US_STATE_ABORTING) {
US_DEBUGP("-- command was aborted\n");
goto Handle_Abort;
}
@@ -602,7 +602,7 @@
if (need_auto_sense) {
result = isd200_read_regs(us);
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (us->sm_state == US_STATE_ABORTING) {
US_DEBUGP("-- auto-sense aborted\n");
goto Handle_Abort;
}
@@ -1053,6 +1053,12 @@
/* Standard IDE interface only supports disks */
info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
+ /* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ * in Linux.
+ */
+ info->InquiryData.Versions = 0x2;
+
/* The length must be at least 36 (5 + 31) */
info->InquiryData.AdditionalLength = 0x1F;
diff -wur linux-2.6.10/drivers/usb/storage/protocol.c linux-2.6.10-lab/drivers/usb/storage/protocol.c
--- linux-2.6.10/drivers/usb/storage/protocol.c 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/protocol.c 2007-10-04 19:10:29.000000000 -0400
@@ -58,6 +58,38 @@
***********************************************************************/
/*
+ * Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+static void fix_inquiry_data(struct scsi_cmnd *srb)
+{
+ unsigned char databuf[3];
+ unsigned int index, offset;
+
+ /* verify that it's an INQUIRY command */
+ if (srb->cmnd[0] != INQUIRY)
+ return;
+
+ index = offset = 0;
+ if (usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
+ &index, &offset, FROM_XFER_BUF) != sizeof(databuf))
+ return;
+
+ if ((databuf[2] & 7) == 2)
+ return;
+
+ US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2 - was %d\n",
+ databuf[2] & 7);
+
+ /* Change the SCSI revision number */
+ databuf[2] = (databuf[2] & ~7) | 2;
+
+ index = offset = 0;
+ usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb,
+ &index, &offset, TO_XFER_BUF);
+}
+
+/*
* Fix-up the return data from a READ CAPACITY command. My Feiya reader
* returns a value that is 1 too large.
*/
@@ -105,6 +137,10 @@
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
+ if (srb->result == SAM_STAT_GOOD) {
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
+ }
}
void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
@@ -124,6 +160,11 @@
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
+
+ if (srb->result == SAM_STAT_GOOD) {
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
+ }
}
@@ -167,6 +208,11 @@
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
+
+ if (srb->result == SAM_STAT_GOOD) {
+ /* Fix the data for an INQUIRY, if necessary */
+ fix_inquiry_data(srb);
+ }
}
void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
@@ -176,6 +222,9 @@
usb_stor_invoke_transport(srb, us);
if (srb->result == SAM_STAT_GOOD) {
+ /* Fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
+
/* Fix the READ CAPACITY result if necessary */
if (us->flags & US_FL_FIX_CAPACITY)
fix_read_capacity(srb);
diff -wur linux-2.6.10/drivers/usb/storage/scsiglue.c linux-2.6.10-lab/drivers/usb/storage/scsiglue.c
--- linux-2.6.10/drivers/usb/storage/scsiglue.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/scsiglue.c 2007-10-04 19:10:29.000000000 -0400
@@ -73,11 +73,14 @@
static int slave_alloc (struct scsi_device *sdev)
{
/*
- * Set the INQUIRY transfer length to 36. We don't use any of
- * the extra data and many devices choke if asked for more or
+ * Set default bflags. These can be overridden for individual
+ * models and vendors via the scsi devinfo mechanism. The only
+ * flag we need is to force 36-byte INQUIRYs; we don't use any
+ * of the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
- sdev->inquiry_len = 36;
+ sdev->sdev_bflags = BLIST_INQUIRY_36;
+
return 0;
}
@@ -95,23 +98,6 @@
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
- /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
- * what is originally reported. We need this to avoid confusing
- * the SCSI layer with devices that report 0 or 1, but need 10-byte
- * commands (ala ATAPI devices behind certain bridges, or devices
- * which simply have broken INQUIRY data).
- *
- * NOTE: This means /dev/sg programs (ala cdrecord) will get the
- * actual information. This seems to be the preference for
- * programs like that.
- *
- * NOTE: This also means that /proc/scsi/scsi and sysfs may report
- * the actual value or the modified one, depending on where the
- * data comes from.
- */
- if (sdev->scsi_level < SCSI_2)
- sdev->scsi_level = SCSI_2;
-
/* According to the technical support people at Genesys Logic,
* devices using their chips have problems transferring more than
* 32 KB at a time. In practice people have found that 64 KB
@@ -172,24 +158,18 @@
US_DEBUGP("%s called\n", __FUNCTION__);
srb->host_scribble = (unsigned char *)us;
- /* check for state-transition errors */
- if (us->srb != NULL) {
- printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
- __FUNCTION__, us->srb);
+ /* enqueue the command */
+ if (us->sm_state != US_STATE_IDLE || us->srb != NULL) {
+ printk(KERN_ERR USB_STORAGE "Error in %s: "
+ "state = %d, us->srb = %p\n",
+ __FUNCTION__, us->sm_state, us->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
- /* fail the command if we are disconnecting */
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- US_DEBUGP("Fail command during disconnect\n");
- srb->result = DID_NO_CONNECT << 16;
- done(srb);
- return 0;
- }
-
- /* enqueue the command and wake up the control thread */
srb->scsi_done = done;
us->srb = srb;
+
+ /* wake up the process task */
up(&(us->sema));
return 0;
@@ -199,7 +179,7 @@
* Error handling functions
***********************************************************************/
-/* Command timeout and abort */
+/* Command abort */
/* This is always called with scsi_lock(srb->host) held */
static int command_abort(struct scsi_cmnd *srb )
{
@@ -214,12 +194,22 @@
return FAILED;
}
- /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
+ /* Normally the current state is RUNNING. If the control thread
+ * hasn't even started processing this command, the state will be
+ * IDLE. Anything else is a bug. */
+ if (us->sm_state != US_STATE_RUNNING
+ && us->sm_state != US_STATE_IDLE) {
+ printk(KERN_ERR USB_STORAGE "Error in %s: "
+ "invalid state %d\n", __FUNCTION__, us->sm_state);
+ return FAILED;
+ }
+
+ /* Set state to ABORTING and set the ABORTING bit, but only if
* a device reset isn't already in progress (to avoid interfering
* with the reset). To prevent races with auto-reset, we must
* stop any ongoing USB transfers while still holding the host
* lock. */
- set_bit(US_FLIDX_TIMED_OUT, &us->flags);
+ us->sm_state = US_STATE_ABORTING;
if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
set_bit(US_FLIDX_ABORTING, &us->flags);
usb_stor_stop_transport(us);
@@ -232,7 +222,6 @@
/* Reacquire the lock and allow USB transfers to resume */
scsi_lock(host);
clear_bit(US_FLIDX_ABORTING, &us->flags);
- clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
return SUCCESS;
}
@@ -245,7 +234,14 @@
int result;
US_DEBUGP("%s called\n", __FUNCTION__);
+ if (us->sm_state != US_STATE_IDLE) {
+ printk(KERN_ERR USB_STORAGE "Error in %s: "
+ "invalid state %d\n", __FUNCTION__, us->sm_state);
+ return FAILED;
+ }
+ /* set the state and release the lock */
+ us->sm_state = US_STATE_RESETTING;
scsi_unlock(srb->device->host);
/* lock the device pointers and do the reset */
@@ -257,8 +253,9 @@
result = us->transport_reset(us);
up(&(us->dev_semaphore));
- /* lock the host for the return */
+ /* lock access to the state and clear it */
scsi_lock(srb->device->host);
+ us->sm_state = US_STATE_IDLE;
return result;
}
@@ -269,10 +266,17 @@
static int bus_reset(struct scsi_cmnd *srb)
{
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0];
- int result, rc;
+ int result;
US_DEBUGP("%s called\n", __FUNCTION__);
+ if (us->sm_state != US_STATE_IDLE) {
+ printk(KERN_ERR USB_STORAGE "Error in %s: "
+ "invalid state %d\n", __FUNCTION__, us->sm_state);
+ return FAILED;
+ }
+ /* set the state and release the lock */
+ us->sm_state = US_STATE_RESETTING;
scsi_unlock(srb->device->host);
/* The USB subsystem doesn't handle synchronisation between
@@ -287,21 +291,14 @@
result = -EBUSY;
US_DEBUGP("Refusing to reset a multi-interface device\n");
} else {
- rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
- if (rc < 0) {
- US_DEBUGP("unable to lock device for reset: %d\n", rc);
- result = rc;
- } else {
result = usb_reset_device(us->pusb_dev);
- if (rc)
- usb_unlock_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result);
}
- }
up(&(us->dev_semaphore));
- /* lock the host for the return */
+ /* lock access to the state and clear it */
scsi_lock(srb->device->host);
+ us->sm_state = US_STATE_IDLE;
return result < 0 ? FAILED : SUCCESS;
}
diff -wur linux-2.6.10/drivers/usb/storage/transport.c linux-2.6.10-lab/drivers/usb/storage/transport.c
--- linux-2.6.10/drivers/usb/storage/transport.c 2004-12-24 16:34:31.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/transport.c 2007-10-04 19:10:29.000000000 -0400
@@ -537,7 +537,7 @@
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (us->sm_state == US_STATE_ABORTING) {
US_DEBUGP("-- command was aborted\n");
goto Handle_Abort;
}
@@ -665,7 +665,7 @@
srb->cmd_len = old_cmd_len;
memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
- if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+ if (us->sm_state == US_STATE_ABORTING) {
US_DEBUGP("-- auto-sense aborted\n");
goto Handle_Abort;
}
@@ -911,6 +911,7 @@
int result;
/* issue the command */
+ us->iobuf[0] = 0;
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
US_BULK_GET_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS |
@@ -921,7 +922,7 @@
result, us->iobuf[0]);
/* if we have a successful request, return the result */
- if (result > 0)
+ if (result >= 0)
return us->iobuf[0];
/*
@@ -933,16 +934,13 @@
if (result == -EPIPE) {
usb_stor_clear_halt(us, us->recv_bulk_pipe);
usb_stor_clear_halt(us, us->send_bulk_pipe);
+ /* return the default -- no LUNs */
+ return 0;
}
- /*
- * Some devices don't like GetMaxLUN. They may STALL the control
- * pipe, they may return a zero-length result, they may do nothing at
- * all and timeout, or they may fail in even more bizarrely creative
- * ways. In these cases the best approach is to use the default
- * value: only one LUN.
- */
- return 0;
+ /* An answer or a STALL are the only valid responses. If we get
+ * something else, return an indication of error */
+ return -1;
}
int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
@@ -1057,13 +1055,8 @@
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
- if (residue) {
- if (!(us->flags & US_FL_IGNORE_RESIDUE) ||
- srb->sc_data_direction == DMA_TO_DEVICE) {
residue = min(residue, transfer_length);
srb->resid = max(srb->resid, (int) residue);
- }
- }
/* based on the status code, we report good or bad */
switch (bcs->Status) {
diff -wur linux-2.6.10/drivers/usb/storage/unusual_devs.h linux-2.6.10-lab/drivers/usb/storage/unusual_devs.h
--- linux-2.6.10/drivers/usb/storage/unusual_devs.h 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/usb/storage/unusual_devs.h 2007-10-04 19:10:29.000000000 -0400
@@ -36,16 +36,13 @@
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
*
- * If you want to add an entry for this file, be sure to include the
- * following information:
- * - a patch that adds the entry for your device, including your
- * email address right above the entry (plus maybe a brief
- * explanation of the reason for the entry),
+ * If you want to add an entry for this file, please send the following
+ * to greg@kroah.com:
+ * - patch that adds the entry for your device which includes your
+ * email address right above the entry.
* - a copy of /proc/bus/usb/devices with your device plugged in
* running with this patch.
- * Send your submission to either Phil Dibowitz or
- * Alan Stern , and don't forget to CC: the
- * USB development list .
+ *
*/
UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
@@ -71,6 +68,16 @@
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
#endif
+/* : I don't know the name of the bridge
+ * manufacturer, but I've got an external USB drive by the Revoltec company
+ * that needs this. otherwise the drive is recognized as /dev/sda, but any
+ * access to it blocks indefinitely.
+ */
+UNUSUAL_DEV( 0x0402, 0x5621, 0x0103, 0x0103,
+ "Revoltec",
+ "USB/IDE Bridge (ATA/ATAPI)",
+ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
/* Deduced by Jonathan Woithe
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
@@ -88,6 +95,12 @@
US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
#endif
+/* Patch submitted by Alessandro Fracchetti */
+UNUSUAL_DEV( 0x0482, 0x0105, 0x0100, 0x0100,
+ "Kyocera",
+ "Finecam L3",
+ US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY),
+
/* Patch submitted by Philipp Friedrich */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
"Kyocera",
@@ -108,7 +121,6 @@
/* Patch for Kyocera Finecam L3
* Submitted by Michael Krauth
- * and Alessandro Fracchetti
*/
UNUSUAL_DEV( 0x0482, 0x0105, 0x0100, 0x0100,
"Kyocera",
@@ -137,13 +149,10 @@
"785EPX Storage",
US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN),
-/* Not sure who reported this originally but
- * Pavel Machek reported that the extra US_FL_SINGLE_LUN
- * flag be added */
UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210,
"Fujifilm",
"FinePix 1400Zoom",
- US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
+ US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
/* Reported by Peter Wächtler