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