S: United Kingdom
N: Kai Harrekilde-Petersen
-E: khp@olicom.dk
+E: kai.harrekilde@get2net.dk
D: Original author of the ftape-HOWTO, i82078 fdc detection code.
N: Bart Hartgers
with pcmcia-cs.
o Gnu C 2.7.2.3 # gcc --version
-o binutils 2.9.1.0.7 # ld -v
+o binutils 2.9.1.0.22 # ld -v
o util-linux 2.10g # chsh -v
o modutils 2.3.10 # insmod -V
o e2fsprogs 1.18 # /sbin/tune2fs --version
If you can, upgrade to the latest 2.9.5 binutils release. Older
releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if
-at all possible. The later releases of 2.9.1.0.x (anything where x >= 7)
+at all possible. The later releases of 2.9.1.0.x (anything where x >= 22)
can and do compile the kernel properly, but there are many benefits
to upgrading to 2.9.5 if you're up to it.
2.9.5 series
------------
-o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.gz
- <ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.bz2>
+o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.gz
+ <ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.bz2>
System utilities
****************
If unsure, say N.
+Legacy kernel start address
+CONFIG_ALPHA_LEGACY_START_ADDRESS
+ The 2.4 kernel changed the kernel start address from 0x310000
+ to 0x810000 to make room for the Wildfire's larger SRM console.
+
+ If you're using aboot 0.7 or later, the bootloader will examine
+ the ELF headers to determine where to transfer control. Unfortunately,
+ most older bootloaders -- APB, or MILO -- hardcoded the kernel
+ start address rather than examining the ELF headers, and the result
+ is a hard lockup.
+
+ Say Y if you have a broken bootloader. Say N if you do not, or
+ if you wish to run on Wildfire.
+
Non-standard serial port support
CONFIG_SERIAL_NONSTANDARD
Say Y here if you have any non-standard serial boards -- boards
If unsure, say N.
+CONFIG_FB_SA1100
+ This is a framebuffer device for the SA-1100 LCD Controller.
+ See http://www.linux-fbdev.org/ for information on framebuffer
+ devices.
+
+ If you plan to use the LCD display with your SA-1100 system, say
+ Y here.
+
Advanced low level driver options
CONFIG_FBCON_ADVANCED
The frame buffer console uses character drawing routines that are
If you have any questions or comments about the Compaq Personal
Server, send e-mail to skiff@crl.dec.com
+Include support for Assabet
+CONFIG_SA1100_ASSABET
+ Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+ Microprocessor Development Board (also known as the Assabet).
+
+Include support for the Compaq iPAQ 3600
+CONFIG_SA1100_BITSY
+ Say Y here if you intend to run this kernel on the Compaq iPAQ 3600
+ handheld computer. Information about this machine and the Linux
+ port to this machine can be found at:
+
+ http://www.handhelds.org/Compaq/index.html#iPAQ_H3600
+ http://www.compaq.com/products/handhelds/pocketpc/
+
Math emulation
CONFIG_NWFPE
Say Y to include the NWFPE floating point emulator in the kernel.
time and disk space needed for compilation of the kernel. If in
doubt say N.
+Kernel low-level debugging functions
+CONFIG_DEBUG_LL
+ Say Y here to include definitions of printascii, printchar, printhex
+ in the kernel. This is helpful if you are debugging code that
+ executes before the console is initialized.
+
+Kernel low-level debugging messages via footbridge serial port
+CONFIG_DEBUG_DC21285_PORT
+ Say Y here if you want the low-level print routines to direct their
+ output to the serial port in the DC21285 (Footbridge).
+
Split initialisation functions into discardable section
CONFIG_TEXT_SECTIONS
If you say Y here, kernel code that is only used during
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test2
+EXTRAVERSION = -test3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
NM := nm -B
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds #-N -relax
+LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax
CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
# Determine if we can use the BWX instructions with GAS.
LIBS := $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEBOOT = $(MAKE) -C arch/alpha/boot
rawboot:
@$(MAKEBOOT) rawboot
@$(MAKEBOOT) srmboot
archclean:
- @$(MAKE) -C arch/$(ARCH)/kernel clean
+ @$(MAKE) -C arch/alpha/kernel clean
@$(MAKEBOOT) clean
+ rm -f arch/alpha/vmlinux.lds
archmrproper:
archdep:
@$(MAKEBOOT) dep
+ $(CPP) $(CPPFLAGS) -xc -P arch/alpha/vmlinux.lds.in -o arch/alpha/vmlinux.lds
bootpfile:
@$(MAKEBOOT) bootpfile
mainmenu_option next_comment
comment 'Kernel hacking'
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel FP software completion' CONFIG_MATHEMU
else
fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS
+
endmenu
#include <asm/system.h>
#include <asm/ptrace.h>
+#include <asm/hwrpb.h>
#define __EXTERN_INLINE inline
#include <asm/io.h>
void __init
pyxis_init_arch(void)
{
+ /* On pyxis machines we can precisely calculate the
+ CPU clock frequency using pyxis real time counter.
+ It's especially useful for SX164 with broken RTC.
+
+ Both CPU and chipset are driven by the single 16.666M
+ or 16.667M crystal oscillator. PYXIS_RT_COUNT clock is
+ 66.66 MHz. -ink */
+
+ unsigned int cc0, cc1;
+ unsigned long pyxis_cc;
+
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc0));
+ pyxis_cc = *(vulp)PYXIS_RT_COUNT;
+ do { } while(*(vulp)PYXIS_RT_COUNT - pyxis_cc < 4096);
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc1));
+ cc1 -= cc0;
+ hwrpb->cycle_freq = ((cc1 >> 11) * 100000000UL) / 3;
+ hwrpb_update_checksum(hwrpb);
+
do_init_arch(1);
}
return 0;
}
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain firmware forgets to set it properly, as seen
+ * on SX164 and LX164 with SRM.
+ */
+void
+pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat >= 16) return;
+ printk("PCI: Setting latency timer of device %s to 64\n",
+ dev->slot_name);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+}
+
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
static void __init
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/core_cia.h>
+#include <asm/hwrpb.h>
#include "proto.h"
#include "irq_impl.h"
SMC669_Init(0);
}
+static void __init
+sx164_init_arch(void)
+{
+ /*
+ * OSF palcode v1.23 forgets to enable PCA56 Motion Video
+ * Instructions. Let's enable it.
+ * We have to check palcode revision because CSERVE interface
+ * is subject to change without notice. For example, it
+ * has been changed completely since v1.16 (found in MILO
+ * distribution). -ink
+ */
+ struct percpu_struct *cpu = (struct percpu_struct*)
+ ((char*)hwrpb + hwrpb->processor_offset);
+
+ if (alpha_using_srm && (cpu->pal_revision & 0xffff) == 0x117) {
+ __asm__ __volatile__(
+ "lda $16,8($31)\n"
+ "call_pal 9\n" /* Allow PALRES insns in kernel mode */
+ ".long 0x64000118\n\n" /* hw_mfpr $0,icsr */
+ "ldah $16,(1<<(19-16))($31)\n"
+ "or $0,$16,$0\n" /* set MVE bit */
+ ".long 0x74000118\n" /* hw_mtpr $0,icsr */
+ "lda $16,9($31)\n"
+ "call_pal 9" /* Disable PALRES insns */
+ : : : "$0", "$16");
+ printk("PCA56 MVI set enabled\n");
+ }
+
+ pyxis_init_arch();
+}
/*
* The System Vector
nr_irqs: 48,
device_interrupt: pyxis_device_interrupt,
- init_arch: pyxis_init_arch,
+ init_arch: sx164_init_arch,
init_irq: sx164_init_irq,
init_rtc: common_init_rtc,
init_pci: sx164_init_pci,
+++ /dev/null
-OUTPUT_FORMAT("elf64-alpha")
-ENTRY(__start)
-SECTIONS
-{
- . = 0xfffffc0000810000;
- _text = .;
- .text : { *(.text) }
- _etext = .;
-
- /* Exception table */
- . = ALIGN(16);
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
-
- /* Kernel symbol table */
- . = ALIGN(8);
- __start___ksymtab = .;
- __ksymtab : { *(__ksymtab) }
- __stop___ksymtab = .;
- .kstrtab : { *(.kstrtab) }
-
- /* Startup code */
- . = ALIGN(8192);
- __init_begin = .;
- .text.init : { *(.text.init) }
- .data.init : { *(.data.init) }
-
- . = ALIGN(16);
- __setup_start = .;
- .setup.init : { *(.setup.init) }
- __setup_end = .;
-
- . = ALIGN(8);
- __initcall_start = .;
- .initcall.init : { *(.initcall.init) }
- __initcall_end = .;
-
- . = ALIGN(2*8192); /* Align double page for init_task_union */
- __init_end = .;
-
- /* The initial task and kernel stack */
- init_task : { *(init_task) }
-
- /* Global data */
- _data = .;
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
- .rodata : { *(.rodata) }
- .data : { *(.data) CONSTRUCTORS }
- .got : { *(.got) }
- .sdata : { *(.sdata) }
- _edata = .;
-
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss : { *(.bss) *(COMMON) }
- __bss_stop = .;
- _end = .;
-
- .mdebug 0 : { *(.mdebug) }
- .note 0 : { *(.note) }
- .comment 0 : { *(.comment) }
-
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
-
- /DISCARD/ : { *(.text.exit) *(.data.exit) }
-}
--- /dev/null
+#include <linux/config.h>
+
+OUTPUT_FORMAT("elf64-alpha")
+ENTRY(__start)
+PHDRS { kernel PT_LOAD ; }
+SECTIONS
+{
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+ . = 0xfffffc0000310000;
+#else
+ . = 0xfffffc0000810000;
+#endif
+
+ _text = .;
+ .text : { *(.text) } :kernel
+ _etext = .;
+
+ /* Exception table */
+ . = ALIGN(16);
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ /* Kernel symbol table */
+ . = ALIGN(8);
+ __start___ksymtab = .;
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+ .kstrtab : { *(.kstrtab) }
+
+ /* Startup code */
+ . = ALIGN(8192);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+
+ . = ALIGN(8);
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+
+ . = ALIGN(2*8192); /* Align double page for init_task_union */
+ __init_end = .;
+
+ /* The initial task and kernel stack */
+ init_task : { *(init_task) }
+
+ /* Global data */
+ _data = .;
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .rodata : { *(.rodata) }
+ .data : { *(.data) CONSTRUCTORS }
+ .got : { *(.got) }
+ .sdata : { *(.sdata) }
+ _edata = .;
+
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss : { *(.bss) *(COMMON) }
+ __bss_stop = .;
+ _end = .;
+
+ .mdebug 0 : { *(.mdebug) }
+ .note 0 : { *(.note) }
+ .comment 0 : { *(.comment) }
+
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /DISCARD/ : { *(.text.exit) *(.data.exit) }
+}
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE
endmenu
if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then
bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET
fi
- bool ' Include support for Bitsy' CONFIG_SA1100_BITSY
bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS
+ bool ' Include support for Compaq iPAQ 3600 (Bitsy)' CONFIG_SA1100_BITSY
# bool ' Include support for Empeg' CONFIG_SA1100_EMPEG
# bool ' Include support for Itsy' CONFIG_SA1100_ITSY
bool ' Include support for LART' CONFIG_SA1100_LART
bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
if [ "$CONFIG_DEBUG_LL" = "y" ]; then
if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
- bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT
+ bool 'Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT
fi
fi
fi
extern unsigned int local_bh_count[NR_CPUS];
extern unsigned int local_irq_count[NR_CPUS];
+extern void __bad_xchg(volatile void *ptr, int size);
+
/*
* syscalls
*/
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(udelay);
-EXPORT_SYMBOL(xchg_str);
EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
#ifdef CONFIG_CPU_32
EXPORT_SYMBOL(system_serial_high);
EXPORT_SYMBOL(mem_fclk_21285);
EXPORT_SYMBOL(__bug);
+EXPORT_SYMBOL(__bad_xchg);
EXPORT_SYMBOL(__readwrite_bug);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
* Copyright (C) 1998-1999 Philip Blundell
*/
-#include <linux/personality.h>
#include <linux/module.h>
+#include <linux/personality.h>
#include <linux/stddef.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/errno.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <linux/config.h>
#include <linux/sched.h>
-#include <linux/errno.h>
#include <linux/init.h>
#include <asm/dma.h>
#include <asm/fiq.h>
#include <asm/io.h>
#include <asm/iomd.h>
+#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
*
* Moved DMA resource allocation here...
*/
+#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/module.h>
-#include <linux/malloc.h>
#include <linux/mman.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#include <linux/errno.h>
#include <linux/proc_fs.h>
-#include <linux/unistd.h>
#include <linux/init.h>
#include <asm/dma.h>
ecard_t **ecp;
ecard_t *ec;
struct ex_ecid cid;
- char buffer[200];
int i, rc = -ENOMEM;
ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
nodev:
if (rc && ec)
kfree(ec);
- else {
+ else
slot_to_expcard[slot] = ec;
- ecard_prints(buffer, ec);
- printk("%s", buffer);
- }
return rc;
}
init_waitqueue_head(&ecard_done);
#endif
- printk("Probing expansion cards: (does not imply support)\n");
+ printk("Probing expansion cards\n");
for (slot = 0; slot < 8; slot ++) {
if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ptrace.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
#include <linux/init.h>
-#include <asm/dec21285.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/leds.h>
#include <asm/system.h>
#define GP1_IO_BASE 0x338
#define GP2_IO_BASE 0x33a
+
+#ifdef CONFIG_LEDS
+#define DEFAULT_LEDS 0
+#else
+#define DEFAULT_LEDS GPIO_GREEN_LED
+#endif
+
/*
* Netwinder stuff
*/
0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
#ifndef DEBUG
-#define dprintk if (0) printk
+#define dprintk(x...)
#else
-#define dprintk printk
+#define dprintk(x...) printk(x)
#endif
#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0)
EXPORT_SYMBOL(gpio_modify_io);
EXPORT_SYMBOL(cpld_modify);
-#endif
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS 0
-#else
-#define DEFAULT_LEDS GPIO_GREEN_LED
-#endif
-
-/*
- * CATS stuff
- */
-#ifdef CONFIG_ARCH_CATS
-
-#define CONFIG_PORT 0x370
-#define INDEX_PORT (CONFIG_PORT)
-#define DATA_PORT (CONFIG_PORT + 1)
-
-static void __init cats_hw_init(void)
-{
- /* Set Aladdin to CONFIGURE mode */
- outb(0x51, CONFIG_PORT);
- outb(0x23, CONFIG_PORT);
-
- /* Select logical device 3 */
- outb(0x07, INDEX_PORT);
- outb(0x03, DATA_PORT);
-
- /* Set parallel port to DMA channel 3, ECP+EPP1.9,
- enable EPP timeout */
- outb(0x74, INDEX_PORT);
- outb(0x03, DATA_PORT);
-
- outb(0xf0, INDEX_PORT);
- outb(0x0f, DATA_PORT);
-
- outb(0xf1, INDEX_PORT);
- outb(0x07, DATA_PORT);
-
- /* Select logical device 4 */
- outb(0x07, INDEX_PORT);
- outb(0x04, DATA_PORT);
-
- /* UART1 high speed mode */
- outb(0xf0, INDEX_PORT);
- outb(0x02, DATA_PORT);
-
- /* Select logical device 5 */
- outb(0x07, INDEX_PORT);
- outb(0x05, DATA_PORT);
-
- /* UART2 high speed mode */
- outb(0xf0, INDEX_PORT);
- outb(0x02, DATA_PORT);
-
- /* Set Aladdin to RUN mode */
- outb(0xbb, CONFIG_PORT);
-}
-
-#endif
-
/*
* Initialise any other hardware after we've got the PCI bus
* initialised. We may need the PCI bus to talk to this other
* hardware.
*/
-static int __init hw_init(void)
+static int __init nw_hw_init(void)
{
-#ifdef CONFIG_ARCH_NETWINDER
/*
* this ought to have a better home...
* Since this calls the above routines, which are
gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
spin_unlock_irqrestore(&gpio_lock, flags);
}
+ return 0;
+}
+
+__initcall(nw_hw_init);
#endif
+
+/*
+ * CATS stuff
+ */
#ifdef CONFIG_ARCH_CATS
- if (machine_is_cats())
- cats_hw_init();
-#endif
+
+#define CONFIG_PORT 0x370
+#define INDEX_PORT (CONFIG_PORT)
+#define DATA_PORT (CONFIG_PORT + 1)
+
+static int __init cats_hw_init(void)
+{
+ if (machine_is_cats()) {
+ /* Set Aladdin to CONFIGURE mode */
+ outb(0x51, CONFIG_PORT);
+ outb(0x23, CONFIG_PORT);
+
+ /* Select logical device 3 */
+ outb(0x07, INDEX_PORT);
+ outb(0x03, DATA_PORT);
+
+ /* Set parallel port to DMA channel 3, ECP+EPP1.9,
+ enable EPP timeout */
+ outb(0x74, INDEX_PORT);
+ outb(0x03, DATA_PORT);
+
+ outb(0xf0, INDEX_PORT);
+ outb(0x0f, DATA_PORT);
+
+ outb(0xf1, INDEX_PORT);
+ outb(0x07, DATA_PORT);
+
+ /* Select logical device 4 */
+ outb(0x07, INDEX_PORT);
+ outb(0x04, DATA_PORT);
+
+ /* UART1 high speed mode */
+ outb(0xf0, INDEX_PORT);
+ outb(0x02, DATA_PORT);
+
+ /* Select logical device 5 */
+ outb(0x07, INDEX_PORT);
+ outb(0x05, DATA_PORT);
+
+ /* UART2 high speed mode */
+ outb(0xf0, INDEX_PORT);
+ outb(0x02, DATA_PORT);
+
+ /* Set Aladdin to RUN mode */
+ outb(0xbb, CONFIG_PORT);
+ }
+
return 0;
}
-__initcall(hw_init);
+__initcall(cats_hw_init);
+#endif
+
*
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/sched.h>
#include <asm/delay.h>
*/
#include <linux/config.h>
#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/random.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <linux/stddef.h>
#include <linux/types.h>
-#include <linux/linkage.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#include <linux/init.h>
* 02-05-1999 RMK Various cleanups
*/
#include <linux/config.h>
-#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
*
*/
#include <linux/config.h>
-#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <stdarg.h>
-#include <linux/errno.h>
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/vmalloc.h>
#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
/*
* Values for cpu_do_idle()
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <asm/pgtable.h>
#include <asm/system.h>
+#include "ptrace.h"
+
+#define REG_PC 15
+#define REG_PSR 16
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
#define BREAKINST 0xef9f0001
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ */
+static inline struct pt_regs *
+get_user_regs(struct task_struct *task)
+{
+ return (struct pt_regs *)
+ ((unsigned long)task + 8192 - sizeof(struct pt_regs));
+}
+
/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the THREAD.
*/
static inline long get_stack_long(struct task_struct *task, int offset)
{
- struct pt_regs *regs;
-
- regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-
- return regs->uregs[offset];
+ return get_user_regs(task)->uregs[offset];
}
/*
* this routine assumes that all the privileged stacks are in our
* data space.
*/
-static inline long put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
+static inline int
+put_stack_long(struct task_struct *task, int offset, long data)
{
- struct pt_regs *regs;
-
- regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-
- regs->uregs[offset] = data;
+ get_user_regs(task)->uregs[offset] = data;
return 0;
}
-static int
-read_long(struct task_struct *child, unsigned long addr, unsigned long *res)
+static inline int
+read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res)
{
int copied;
return copied != sizeof(*res) ? -EIO : 0;
}
-static int
-write_long(struct task_struct *child, unsigned long addr, unsigned long val)
+static inline int
+write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val)
{
int copied;
/*
* Get value of register `rn' (in the instruction)
*/
-static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getrn(struct task_struct *child, unsigned long insn)
{
unsigned int reg = (insn >> 16) & 15;
unsigned long val;
+ val = get_stack_long(child, reg);
if (reg == 15)
- val = pc_pointer (get_stack_long (child, reg));
- else
- val = get_stack_long (child, reg);
+ val = pc_pointer(val);
-printk ("r%02d=%08lX ", reg, val);
return val;
}
/*
* Get value of operand 2 (in an ALU instruction)
*/
-static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getaluop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
-printk ("op2=");
if (insn & 1 << 25) {
val = insn & 255;
shift = (insn >> 8) & 15;
type = 3;
-printk ("(imm)");
} else {
val = get_stack_long (child, insn & 15);
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("(r%02ld)", insn & 15);
}
-printk ("sh%dx%d", type, shift);
+
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
return val;
}
/*
* Get value of operand 2 (in a LDR instruction)
*/
-static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getldrop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
- val = get_stack_long (child, insn & 15);
+ val = get_stack_long(child, insn & 15);
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
return val;
}
{
unsigned long alt = 0;
-printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
- switch (insn & 0x0e100000) {
+ switch (insn & 0x0e000000) {
case 0x00000000:
- case 0x00100000:
- case 0x02000000:
- case 0x02100000: /* data processing */
- printk ("data ");
- switch (insn & 0x01e0f000) {
- case 0x0000f000:
- alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn);
- break;
- case 0x0020f000:
- alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn);
- break;
- case 0x0040f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn);
- break;
- case 0x0060f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn);
- break;
- case 0x0080f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn);
- break;
- case 0x00a0f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00c0f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00e0f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x0180f000:
- alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn);
- break;
- case 0x01a0f000:
- alt = ptrace_getaluop2(child, insn);
- break;
- case 0x01c0f000:
- alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn);
- break;
- case 0x01e0f000:
- alt = ~ptrace_getaluop2(child, insn);
+ case 0x02000000: {
+ /*
+ * data processing
+ */
+ long aluop1, aluop2, ccbit;
+
+ if ((insn & 0xf000) != 0xf000)
break;
+
+ aluop1 = ptrace_getrn(child, insn);
+ aluop2 = ptrace_getaluop2(child, insn);
+ ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
+
+ switch (insn & 0x01e00000) {
+ case 0x00000000: alt = aluop1 & aluop2; break;
+ case 0x00200000: alt = aluop1 ^ aluop2; break;
+ case 0x00400000: alt = aluop1 - aluop2; break;
+ case 0x00600000: alt = aluop2 - aluop1; break;
+ case 0x00800000: alt = aluop1 + aluop2; break;
+ case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break;
+ case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break;
+ case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break;
+ case 0x01800000: alt = aluop1 | aluop2; break;
+ case 0x01a00000: alt = aluop2; break;
+ case 0x01c00000: alt = aluop1 & ~aluop2; break;
+ case 0x01e00000: alt = ~aluop2; break;
}
break;
+ }
+
+ case 0x04000000:
+ case 0x06000000:
+ /*
+ * ldr
+ */
+ if ((insn & 0x0010f000) == 0x0010f000) {
+ unsigned long base;
- case 0x04100000: /* ldr */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldr ");
- alt = ptrace_getrn(child, insn);
+ base = ptrace_getrn(child, insn);
if (insn & 1 << 24) {
- if (insn & 1 << 23)
- alt += ptrace_getldrop2 (child, insn);
+ long aluop2;
+
+ if (insn & 0x02000000)
+ aluop2 = ptrace_getldrop2(child, insn);
else
- alt -= ptrace_getldrop2 (child, insn);
- }
- if (read_long (child, alt, &alt) < 0)
- alt = 0; /* not valid */
- else
- alt = pc_pointer (alt);
- }
- break;
+ aluop2 = insn & 0xfff;
- case 0x06100000: /* ldr imm */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldrimm ");
- alt = ptrace_getrn(child, insn);
- if (insn & 1 << 24) {
if (insn & 1 << 23)
- alt += insn & 0xfff;
+ base += aluop2;
else
- alt -= insn & 0xfff;
+ base -= aluop2;
}
- if (read_long (child, alt, &alt) < 0)
- alt = 0; /* not valid */
- else
- alt = pc_pointer (alt);
+ if (read_tsk_long(child, base, &alt) == 0)
+ alt = pc_pointer(alt);
}
break;
- case 0x08100000: /* ldm */
- if (insn & (1 << 15)) {
+ case 0x08000000:
+ /*
+ * ldm
+ */
+ if ((insn & 0x00108000) == 0x00108000) {
unsigned long base;
- int nr_regs;
-printk ("ldm ");
+ unsigned int nr_regs;
if (insn & (1 << 23)) {
nr_regs = insn & 65535;
nr_regs = 0;
}
- base = ptrace_getrn (child, insn);
+ base = ptrace_getrn(child, insn);
- if (read_long (child, base + nr_regs, &alt) < 0)
- alt = 0; /* not valid */
- else
+ if (read_tsk_long(child, base + nr_regs, &alt) == 0)
alt = pc_pointer (alt);
break;
}
break;
- case 0x0a000000:
- case 0x0a100000: { /* bl or b */
+ case 0x0a000000: {
+ /*
+ * bl or b
+ */
signed long displ;
-printk ("b/bl ");
/* It's a branch/branch link: instead of trying to
* figure out whether the branch will be taken or not,
- * we'll put a breakpoint at either location. This is
+ * we'll put a breakpoint at both locations. This is
* simpler, more reliable, and probably not a whole lot
* slower than the alternative approach of emulating the
* branch.
}
break;
}
-printk ("=%08lX\n", alt);
return alt;
}
int res = -EINVAL;
if (nr < 2) {
- res = read_long(child, addr, &dbg->bp[nr].insn);
+ res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
if (res == 0)
- res = write_long(child, addr, BREAKINST);
+ res = write_tsk_long(child, addr, BREAKINST);
if (res == 0) {
dbg->bp[nr].address = addr;
return res;
}
-int ptrace_set_bpt (struct task_struct *child)
+int ptrace_set_bpt(struct task_struct *child)
{
- struct debug_info *dbg = &child->thread.debug;
- unsigned long insn, pc, alt;
+ unsigned long insn, pc;
int res;
- pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
+ pc = pc_pointer(get_stack_long(child, REG_PC));
- res = read_long(child, pc, &insn);
- if (res >= 0) {
- res = 0;
+ res = read_tsk_long(child, pc, &insn);
+ if (!res) {
+ struct debug_info *dbg = &child->thread.debug;
+ unsigned long alt;
dbg->nsaved = 0;
- res = add_breakpoint(child, dbg, pc + 4);
+ alt = get_branch_address(child, pc, insn);
+ if (alt)
+ res = add_breakpoint(child, dbg, alt);
- if (res == 0) {
- alt = get_branch_address(child, pc, insn);
- if (alt)
- res = add_breakpoint(child, dbg, alt);
- }
+ if (!res && (!alt || predicate(insn) != PREDICATE_ALWAYS))
+ res = add_breakpoint(child, dbg, pc + 4);
}
return res;
}
-/* Ensure no single-step breakpoint is pending. Returns non-zero
+/*
+ * Ensure no single-step breakpoint is pending. Returns non-zero
* value if child was being single-stepped.
*/
-int ptrace_cancel_bpt (struct task_struct *child)
+void __ptrace_cancel_bpt(struct task_struct *child)
{
struct debug_info *dbg = &child->thread.debug;
- unsigned long tmp;
int i, nsaved = dbg->nsaved;
dbg->nsaved = 0;
if (nsaved > 2) {
- printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
+ printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
nsaved = 2;
}
for (i = 0; i < nsaved; i++) {
- read_long(child, dbg->bp[i].address, &tmp);
+ unsigned long tmp;
+
+ read_tsk_long(child, dbg->bp[i].address, &tmp);
if (tmp != BREAKINST)
printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
- write_long(child, dbg->bp[i].address, dbg->bp[i].insn);
+ write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
}
-
- return nsaved != 0;
}
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+static int do_ptrace(int request, struct task_struct *child, long addr, long data)
{
- struct task_struct *child;
+ unsigned long tmp;
int ret;
- lock_kernel();
- ret = -EPERM;
- if (request == PTRACE_TRACEME) {
- /* are we already being traced? */
- if (current->ptrace & PT_PTRACED)
- goto out;
- /* set the ptrace bit in the process flags. */
- current->ptrace |= PT_PTRACED;
- ret = 0;
- goto out;
- }
- if (pid == 1) /* you may not mess with init */
- goto out;
- ret = -ESRCH;
- if (!(child = find_task_by_pid(pid)))
- goto out;
- ret = -EPERM;
- if (request == PTRACE_ATTACH) {
- if (child == current)
- goto out;
- if ((!child->dumpable ||
- (current->uid != child->euid) ||
- (current->uid != child->suid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
- goto out;
- /* the same process cannot be attached many times */
- if (child->ptrace & PT_PTRACED)
- goto out;
- child->ptrace |= PT_PTRACED;
- if (child->p_pptr != current) {
- REMOVE_LINKS(child);
- child->p_pptr = current;
- SET_LINKS(child);
- }
- send_sig(SIGSTOP, child, 1);
- ret = 0;
- goto out;
- }
- ret = -ESRCH;
- if (!(child->ptrace & PT_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- goto out;
- }
- if (child->p_pptr != current)
- goto out;
-
switch (request) {
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
-
- ret = read_long(child, addr, &tmp);
+ /*
+ * read word at location "addr" in the child process.
+ */
+ case PTRACE_PEEKTEXT:
+ case PTRACE_PEEKDATA:
+ ret = read_tsk_long(child, addr, &tmp);
if (!ret)
ret = put_user(tmp, (unsigned long *) data);
- goto out;
- }
-
- case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */
- unsigned long tmp;
+ break;
+ /*
+ * read the word at location "addr" in the user registers.
+ */
+ case PTRACE_PEEKUSR:
ret = -EIO;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- goto out;
+ break;
tmp = 0; /* Default return condition */
- if (addr < sizeof (struct pt_regs))
+ if (addr < sizeof(struct pt_regs))
tmp = get_stack_long(child, (int)addr >> 2);
ret = put_user(tmp, (unsigned long *)data);
- goto out;
- }
+ break;
- case PTRACE_POKETEXT: /* write the word at location addr. */
+ /*
+ * write the word at location addr.
+ */
+ case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = write_long(child, addr, data);
- goto out;
+ ret = write_tsk_long(child, addr, data);
+ break;
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ /*
+ * write the word at location addr in the user registers.
+ */
+ case PTRACE_POKEUSR:
ret = -EIO;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- goto out;
+ break;
if (addr < sizeof (struct pt_regs))
ret = put_stack_long(child, (int)addr >> 2, data);
- goto out;
+ break;
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: /* restart after signal. */
+ /*
+ * continue/restart and stop at next (return from) syscall
+ */
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT:
ret = -EIO;
if ((unsigned long) data > _NSIG)
- goto out;
+ break;
if (request == PTRACE_SYSCALL)
child->ptrace |= PT_TRACESYS;
else
child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
- wake_up_process (child);
/* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
+ __ptrace_cancel_bpt(child);
+ wake_up_process(child);
ret = 0;
- goto out;
+ break;
- /* make the child exit. Best I can do is send it a sigkill.
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL:
- if (child->state == TASK_ZOMBIE) /* already dead */
- return 0;
- wake_up_process (child);
+ /* already dead */
+ ret = 0;
+ if (child->state == TASK_ZOMBIE)
+ break;
child->exit_code = SIGKILL;
/* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
+ __ptrace_cancel_bpt(child);
+ wake_up_process(child);
ret = 0;
- goto out;
+ break;
- case PTRACE_SINGLESTEP: /* execute single instruction. */
+ /*
+ * execute single instruction.
+ */
+ case PTRACE_SINGLESTEP:
ret = -EIO;
if ((unsigned long) data > _NSIG)
- goto out;
+ break;
child->thread.debug.nsaved = -1;
child->ptrace &= ~PT_TRACESYS;
- wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
+ wake_up_process(child);
ret = 0;
- goto out;
-
- case PTRACE_GETREGS:
- { /* Get all gp regs from the child. */
- unsigned char *stack;
+ break;
+
+ /*
+ * detach a process that was attached.
+ */
+ case PTRACE_DETACH:
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
+ child->exit_code = data;
+ write_lock_irq(&tasklist_lock);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irq(&tasklist_lock);
+ /* make sure single-step breakpoint is gone. */
+ __ptrace_cancel_bpt(child);
+ wake_up_process (child);
+ ret = 0;
+ break;
+
+ /*
+ * Get all gp regs from the child.
+ */
+ case PTRACE_GETREGS: {
+ struct pt_regs *regs = get_user_regs(child);
ret = 0;
- stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
- if (copy_to_user((void *)data, stack,
+ if (copy_to_user((void *)data, regs,
sizeof(struct pt_regs)))
ret = -EFAULT;
- goto out;
- };
+ break;
+ }
- case PTRACE_SETREGS:
- {
- /* Set all gp regs in the child. */
- unsigned char *stack;
+ /*
+ * Set all gp regs in the child.
+ */
+ case PTRACE_SETREGS: {
+ struct pt_regs *regs = get_user_regs(child);
ret = 0;
- stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
- if (copy_from_user(stack, (void *)data,
+ if (copy_from_user(regs, (void *)data,
sizeof(struct pt_regs)))
ret = -EFAULT;
- goto out;
- };
+ break;
+ }
- case PTRACE_GETFPREGS:
- /* Get the child FPU state. */
- ret = 0;
- if (copy_to_user((void *)data, &child->thread.fpstate,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
+ /*
+ * Get the child FPU state.
+ */
+ case PTRACE_GETFPREGS:
+ ret = -EIO;
+ if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
+ break;
+
+ /* we should check child->used_math here */
+ ret = __copy_to_user((void *)data, &child->thread.fpstate,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
+ /*
+ * Set the child FPU state.
+ */
case PTRACE_SETFPREGS:
- /* Set the child FPU state. */
- ret = 0;
- if (copy_from_user(&child->thread.fpstate, (void *)data,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
-
- case PTRACE_DETACH: /* detach a process that was attached. */
ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
- wake_up_process (child);
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- /* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
- ret = 0;
- goto out;
+ if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
+ break;
+
+ child->used_math = 1;
+ ret = __copy_from_user(&child->thread.fpstate, (void *)data,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
default:
ret = -EIO;
+ break;
+ }
+
+ return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret;
+
+ lock_kernel();
+ ret = -EPERM;
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->ptrace & PT_PTRACED)
goto out;
+ /* set the ptrace bit in the process flags. */
+ current->ptrace |= PT_PTRACED;
+ ret = 0;
+ goto out;
}
+ ret = -ESRCH;
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
+ read_unlock(&tasklist_lock);
+ if (!child)
+ goto out;
+
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out_tsk;
+
+ if (request == PTRACE_ATTACH) {
+ if (child == current)
+ goto out_tsk;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+ goto out_tsk;
+ /* the same process cannot be attached many times */
+ if (child->ptrace & PT_PTRACED)
+ goto out_tsk;
+ child->ptrace |= PT_PTRACED;
+
+ write_lock_irq(&tasklist_lock);
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ write_unlock_irq(&tasklist_lock);
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out_tsk;
+ }
+ ret = -ESRCH;
+ if (!(child->ptrace & PT_PTRACED))
+ goto out_tsk;
+ if (child->state != TASK_STOPPED && request != PTRACE_KILL)
+ goto out_tsk;
+ if (child->p_pptr != current)
+ goto out_tsk;
+
+ ret = do_ptrace(request, child, addr, data);
+
+out_tsk:
+ free_task_struct(child);
out:
unlock_kernel();
return ret;
--- /dev/null
+extern void __ptrace_cancel_bpt(struct task_struct *);
+extern int ptrace_set_bpt(struct task_struct *);
+
+/*
+ * Clear a breakpoint, if one exists.
+ */
+static inline int ptrace_cancel_bpt(struct task_struct *tsk)
+{
+ int nsaved = tsk->thread.debug.nsaved;
+
+ if (nsaved)
+ __ptrace_cancel_bpt(tsk);
+
+ return nsaved;
+}
+
* Modified for ARM by Russell King
*/
#include <linux/sched.h>
-#include <linux/errno.h>
#include <asm/semaphore.h>
extern void bootmem_init(struct meminfo *);
extern void reboot_setup(char *str);
extern void disable_hlt(void);
+extern unsigned long memparse(char *ptr, char **retptr);
extern int root_mountflags;
extern int _stext, _text, _etext, _edata, _end;
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
-#include <linux/signal.h>
#include <linux/errno.h>
+#include <linux/signal.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
-#include <linux/unistd.h>
#include <linux/stddef.h>
-#include <linux/binfmts.h>
+#include <linux/unistd.h>
#include <linux/tty.h>
+#include <asm/pgalloc.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
+
+#include "ptrace.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
int options, unsigned long *ru);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
-extern int ptrace_cancel_bpt (struct task_struct *);
-extern int ptrace_set_bpt (struct task_struct *);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
goto badframe;
/* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt (current))
+ if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
return regs->ARM_r0;
goto badframe;
/* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt (current))
+ if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
return regs->ARM_r0;
if (!oldset)
oldset = ¤t->blocked;
- single_stepping = ptrace_cancel_bpt (current);
+ single_stepping = ptrace_cancel_bpt(current);
for (;;) {
unsigned long signr;
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
- single_stepping |= ptrace_cancel_bpt (current);
+ single_stepping |= ptrace_cancel_bpt(current);
/* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code))
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
if (single_stepping)
- ptrace_set_bpt (current);
+ ptrace_set_bpt(current);
return 1;
}
regs->ARM_pc -= 4;
}
if (single_stepping)
- ptrace_set_bpt (current);
+ ptrace_set_bpt(current);
return 0;
}
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
-#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
+#include <linux/ptrace.h>
#include <linux/init.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
#include <asm/atomic.h>
+#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "ptrace.h"
extern void c_backtrace (unsigned long fp, int pmode);
-extern int ptrace_cancel_bpt (struct task_struct *);
char *processor_modes[]=
{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
console_loglevel = 15;
}
-int kstack_depth_to_print = 200;
-
/*
* Stack pointers should always be within the kernels view of
* physical memory. If it is not there, then we can't dump
die(str, regs, err);
}
-void bad_user_access_alignment(const void *ptr)
-{
- printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr,
- __builtin_return_address(0));
- current->thread.error_code = 0;
- current->thread.trap_no = 11;
- force_sig(SIGBUS, current);
-/* die_if_kernel("Oops - bad user access alignment", regs, mode);*/
-}
-
asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
{
+ unsigned long addr = instruction_pointer(regs);
+ siginfo_t info;
+
#ifdef CONFIG_DEBUG_USER
printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
- current->comm, current->pid, instruction_pointer(regs));
+ current->comm, current->pid, addr);
#endif
+
current->thread.error_code = 0;
current->thread.trap_no = 6;
- force_sig(SIGILL, current);
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void *)addr;
+
+ force_sig_info(SIGILL, &info, current);
+
die_if_kernel("Oops - undefined instruction", regs, mode);
}
asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
{
+ siginfo_t info;
+
#ifdef CONFIG_DEBUG_USER
printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
current->comm, current->pid, instruction_pointer(regs));
#endif
+
current->thread.error_code = 0;
current->thread.trap_no = 11;
- force_sig(SIGBUS, current);
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+
+ force_sig_info(SIGBUS, &info, current);
+
die_if_kernel("Oops - address exception", regs, mode);
}
while(1);
}
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task.
- *
- * We no longer save/restore the math state on every context switch
- * any more. We only do this now if it actually gets used.
- */
-asmlinkage void math_state_restore (void)
-{
- current->used_math = 1;
-}
-
/*
* Handle some more esoteric system calls
*/
-asmlinkage int arm_syscall (int no, struct pt_regs *regs)
+asmlinkage int arm_syscall(int no, struct pt_regs *regs)
{
+ siginfo_t info;
+
switch (no) {
case 0: /* branch through 0 */
- force_sig(SIGSEGV, current);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = NULL;
+
+ force_sig_info(SIGSEGV, &info, current);
+
die_if_kernel("branch through zero", regs, 0);
break;
- case 1: /* SWI_BREAK_POINT */
- regs->ARM_pc -= 4; /* Decrement PC by one instruction */
- ptrace_cancel_bpt(current);
- force_sig(SIGTRAP, current);
+ case 1: /* SWI BREAK_POINT */
+ /*
+ * The PC is always left pointing at the next
+ * instruction. Fix this.
+ */
+ regs->ARM_pc -= 4;
+ __ptrace_cancel_bpt(current);
+
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void *)instruction_pointer(regs);
+
+ force_sig_info(SIGTRAP, &info, current);
return regs->ARM_r0;
case 2: /* sys_cacheflush */
die_if_kernel("Oops", regs, n);
}
-asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
-{
- printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
-}
-
-asmlinkage void arm_invalidptr(const char *function, int size)
+void __bad_xchg(volatile void *ptr, int size)
{
- printk("Invalid pointer size in %s (pc=%p) size %d\n",
- function, __builtin_return_address(0), size);
+ printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
+ __builtin_return_address(0), ptr, size);
+ BUG();
}
/*
- * A data abort trap was taken, but the instruction was not an instruction
- * which should cause the trap to be taken. Try to abort it. Note that
- * the while(1) is there because we cannot currently handle returning from
- * this function.
+ * A data abort trap was taken, but we did not handle the instruction.
+ * Try to abort the user program, or panic if it was the kernel.
*/
asmlinkage void
baddataabort(int code, unsigned long instr, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
+ siginfo_t info;
-#ifdef CONFIG_DEBUG_ERRORS
+#ifdef CONFIG_DEBUG_USER
dump_instr(addr, 1);
{
pgd_t *pgd;
printk ("\n");
}
#endif
- force_sig(SIGILL, current);
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void *)addr;
+
+ force_sig_info(SIGILL, &info, current);
die_if_kernel("unknown data abort code", regs, instr);
- while (1);
}
void __bug(const char *file, int line, void *data)
{
- printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
+ printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
if (data)
- printk(KERN_CRIT"extra data = %p\n", data);
+ printk(KERN_CRIT" - extra data = %p", data);
+ printk("\n");
BUG();
}
tsk->thread.error_code = mode;
tsk->thread.trap_no = 14;
si.si_signo = SIGSEGV;
+ si.si_errno = 0;
si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR;
si.si_addr = (void *)addr;
force_sig_info(SIGSEGV, &si, tsk);
flush_cache_all();
}
-/*
- * The mem_map array can get very big. Free the unused area of the memory map.
- */
+static inline void free_memmap(unsigned long start, unsigned long end)
+{
+ unsigned long pg, pgend;
+
+ start = __phys_to_virt(start);
+ end = __phys_to_virt(end);
+
+ pg = PAGE_ALIGN((unsigned long)(mem_map + MAP_NR(start)));
+ pgend = ((unsigned long)(mem_map + MAP_NR(end))) & PAGE_MASK;
+
+ start = __virt_to_phys(pg);
+ end = __virt_to_phys(pgend);
+ /*
+ * The mem_map is always stored in node 0
+ */
+ free_bootmem_node(0, start, end - start);
+}
+
static inline void free_unused_memmap_node(int node, struct meminfo *mi)
{
unsigned long bank_start, prev_bank_end = 0;
* between the current bank and the previous, free it.
*/
if (prev_bank_end && prev_bank_end != bank_start)
- free_bootmem_node(node, prev_bank_end,
- bank_start - prev_bank_end);
+ free_memmap(prev_bank_end, bank_start);
prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
mi->bank[i].size);
}
}
+/*
+ * The mem_map array can get very big. Free
+ * the unused area of the memory map.
+ */
void __init create_memmap_holes(struct meminfo *mi)
{
int node;
.word _arm2_proc_fin
.word _arm2_set_pgd
.word _arm2_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm2_xchg_4
cpu_arm2_info:
.word _arm2_proc_fin
.word _arm2_set_pgd
.word _arm3_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm3_xchg_4
cpu_arm250_info:
.word _arm3_proc_fin
.word _arm3_set_pgd
.word _arm3_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm3_xchg_4
cpu_arm3_info:
mov r0, r2
mov r1, r4
mov r2, r3
- b baddataabort
-
+ bl baddataabort
+ b ret_from_sys_call
Ldata_lateldrpreconst:
tst r4, #1 << 21 @ check writeback bit
mov r0, r2
mov r1, r4
mov r2, r3
- b baddataabort
-
+ bl baddataabort
+ b ret_from_sys_call
Ldata_lateldrpreconst:
tst r4, #1 << 21 @ check writeback bit
}
}
-void __init pcibios_penalize_isa_irq(int irq)
+void pcibios_penalize_isa_irq(int irq)
{
/*
* If any ISAPnP device reports an IRQ in its list of possible
goto out;
}
- down(¤t->mm->mmap_sem);
lock_kernel();
retval = -EINVAL;
len = PAGE_ALIGN(len);
goto out_putf;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(¤t->mm->mmap_sem);
retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up(¤t->mm->mmap_sem);
out_putf:
unlock_kernel();
- up(¤t->mm->mmap_sem);
if (file)
fput(file);
out:
struct file * file = NULL;
unsigned long retval, ret_type;
- down(¤t->mm->mmap_sem);
lock_kernel();
if(flags & MAP_NORESERVE) {
static int cnt;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(¤t->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
+ up(¤t->mm->mmap_sem);
if(!ret_type)
retval = ((retval < PAGE_OFFSET) ? 0 : retval);
fput(file);
out:
unlock_kernel();
- up(¤t->mm->mmap_sem);
return retval;
}
len = PAGE_ALIGN(len);
retval = -EINVAL;
- down(¤t->mm->mmap_sem);
lock_kernel();
if (current->thread.flags & SPARC_FLAG_32BIT) {
goto out_putf;
}
+ down(¤t->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
+ up(¤t->mm->mmap_sem);
out_putf:
unlock_kernel();
- up(¤t->mm->mmap_sem);
if (file)
fput(file);
out:
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
- lock_kernel();
file = open_exec(filename);
- unlock_kernel();
retval = PTR_ERR(file);
if (IS_ERR(file))
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv)) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count32(envp)) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.envc;
}
out:
/* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
struct file *file = NULL;
unsigned long retval, ret_type;
- down(¤t->mm->mmap_sem);
lock_kernel();
if(flags & MAP_NORESERVE) {
static int cnt;
flags &= ~_MAP_NEW;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(¤t->mm->mmap_sem);
retval = do_mmap(file,
(unsigned long) addr, (unsigned long) len,
(unsigned long) prot, (unsigned long) flags,
(unsigned long) off);
+ up(¤t->mm->mmap_sem);
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
out_putf:
fput(file);
out:
unlock_kernel();
- up(¤t->mm->mmap_sem);
return (u32) retval;
}
obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o
obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o
obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o
+obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o
# Do the i2c and rtc last
obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o
--- /dev/null
+/*
+ * linux/arch/arm/drivers/char/defkeymap.c
+ *
+ * Copyright (C) 1995, 1996 Russell King
+ */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+/* Normal (maps 1:1 with no processing) */
+#define KTn 0xF0
+/* Function keys */
+#define KTf 0xF1
+/* Special (Performs special house-keeping funcs) */
+#define KTs 0xF2
+#define KIGNORE K(KTs, 0) /* Ignore */
+#define KENTER K(KTs, 1) /* Enter */
+#define KREGS K(KTs, 2) /* Regs */
+#define KMEM K(KTs, 3) /* Mem */
+#define KSTAT K(KTs, 4) /* State */
+#define KINTR K(KTs, 5) /* Intr */
+#define Ksl 6 /* Last console */
+#define KCAPSLK K(KTs, 7) /* Caps lock */
+#define KNUMLK K(KTs, 8) /* Num-lock */
+#define KSCRLLK K(KTs, 9) /* Scroll-lock */
+#define KSCRLFOR K(KTs,10) /* Scroll forward */
+#define KSCRLBAK K(KTs,11) /* Scroll back */
+#define KREBOOT K(KTs,12) /* Reboot */
+#define KCAPSON K(KTs,13) /* Caps on */
+#define KCOMPOSE K(KTs,14) /* Compose */
+#define KSAK K(KTs,15) /* SAK */
+#define CONS_DEC K(KTs,16) /* Dec console */
+#define CONS_INC K(KTs,17) /* Incr console */
+#define KFLOPPY K(KTs,18) /* Floppy */
+/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
+#define KTp 0xF3
+#define KPAD_0 K(KTp, 0 )
+#define KPAD_1 K(KTp, 1 )
+#define KPAD_2 K(KTp, 2 )
+#define KPAD_3 K(KTp, 3 )
+#define KPAD_4 K(KTp, 4 )
+#define KPAD_5 K(KTp, 5 )
+#define KPAD_6 K(KTp, 6 )
+#define KPAD_7 K(KTp, 7 )
+#define KPAD_8 K(KTp, 8 )
+#define KPAD_9 K(KTp, 9 )
+#define KPAD_PL K(KTp,10 )
+#define KPAD_MI K(KTp,11 )
+#define KPAD_ML K(KTp,12 )
+#define KPAD_DV K(KTp,13 )
+#define KPAD_EN K(KTp,14 )
+#define KPAD_DT K(KTp,16 )
+#define KPAD_HS K(KTp,20 )
+/* Console switching */
+#define KCn 0xF5
+/* Cursor */
+#define KTc 0xF6
+#define Kcd 0 /* Cursor down */
+#define Kcl 1 /* Cursor left */
+#define Kcr 2 /* Cursor right */
+#define Kcu 3 /* Cursor up */
+/* Shift/alt modifiers etc */
+#define KMd 0xF7
+#define KSHIFT K(KMd, 0 )
+#define KALTGR K(KMd, 1 )
+#define KCTRL K(KMd, 2 )
+#define KALT K(KMd, 3 )
+/* Meta */
+#define KMt 0xF8
+#define KAs 0xF9
+#define KPADA_0 K(KAs, 0 )
+#define KPADA_1 K(KAs, 1 )
+#define KPADA_2 K(KAs, 2 )
+#define KPADA_3 K(KAs, 3 )
+#define KPADA_4 K(KAs, 4 )
+#define KPADA_5 K(KAs, 5 )
+#define KPADA_6 K(KAs, 6 )
+#define KPADA_7 K(KAs, 7 )
+#define KPADA_8 K(KAs, 8 )
+#define KPADA_9 K(KAs, 9 )
+#define KPADB_0 K(KAs,10 )
+#define KPADB_1 K(KAs,11 )
+#define KPADB_2 K(KAs,12 )
+#define KPADB_3 K(KAs,13 )
+#define KPADB_4 K(KAs,14 )
+#define KPADB_5 K(KAs,15 )
+#define KPADB_6 K(KAs,16 )
+#define KPADB_7 K(KAs,17 )
+#define KPADB_8 K(KAs,18 )
+#define KPADB_9 K(KAs,19 )
+/* Locking keys */
+#define KLk 0xFA
+/* Letters */
+#define KTl 0xFB
+
+u_short plain_map[NR_KEYS]=
+{
+ K(KTn, 27),K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6),
+ K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSCRLLK ,KINTR ,
+ K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'),
+ K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'q'),
+ K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
+ K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'),
+ K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
+ K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short shift_map[NR_KEYS]=
+{
+ K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16),
+ K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE ,KMEM ,KINTR ,
+ K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'),
+ K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ),
+ K(KTf,20 ),KSCRLBAK ,KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'Q'),
+ K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'),
+ K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR ,KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'),
+ K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'Z' ),K(KTl,'X'),
+ K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short altgr_map[NR_KEYS]=
+{
+ KIGNORE ,K(KCn,12 ),K(KCn,13 ),K(KCn,14 ),K(KCn,15 ),K(KCn,16 ),K(KCn,17 ),K(KCn, 18),
+ K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22 ),K(KCn,23 ),KIGNORE ,KREGS ,KINTR ,
+ KIGNORE ,KIGNORE ,K(KTn,'@'),KIGNORE ,K(KTn,'$'),KIGNORE ,KIGNORE ,K(KTn,'{'),
+ K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTl,'q'),
+ K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
+ K(KTl,'p'),KIGNORE ,K(KTn,'~'),KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADB_7 ,
+ KPADB_8 ,KPADB_9 ,KPAD_MI ,KCTRL ,K(KAs,20 ),K(KTl,'s'),K(KAs,23 ),K(KAs,25 ),
+ K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE ,KIGNORE ,KENTER ,
+ KPADB_4 ,KPADB_5 ,KPADB_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
+ K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPADB_1 ,KPADB_2 ,KPADB_3 ,KCAPSLK ,KALT ,KIGNORE ,
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short ctrl_map[NR_KEYS]=
+{
+ KIGNORE ,K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6),
+ K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSTAT ,KINTR ,
+ KIGNORE ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3 ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6 ),K(KTn, 7 ),
+ K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31 ),KIGNORE ,KIGNORE ,K(KTn, 8 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
+ K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
+ K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28 ),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
+ K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
+ K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KCOMPOSE ,K(KTn,127),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short shift_ctrl_map[NR_KEYS]=
+{
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KFLOPPY ,KINTR ,
+ KIGNORE ,KIGNORE ,K(KTn, 0 ),KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,K(KTn,31 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
+ K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
+ K(KTn,16 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
+ K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
+ K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short alt_map[NR_KEYS]=
+{
+ K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
+ K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KSCRLLK ,KINTR ,
+ K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
+ K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KMt, 9 ),K(KMt,'q'),
+ K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
+ K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADA_7 ,
+ KPADA_8 ,KPADA_9 ,KPAD_MI ,KCTRL ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
+ K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
+ KPADA_4 ,KPADA_5 ,KPADA_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,'z' ),K(KMt,'x'),
+ K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPADA_1 ,KPADA_2 ,KPADA_3 ,KCAPSLK ,KALT ,K(KMt,' '),
+ KALTGR ,KCTRL ,CONS_DEC ,K(KTc,Kcd ),CONS_INC ,KPADA_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short ctrl_alt_map[NR_KEYS]=
+{
+ KIGNORE ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
+ K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KIGNORE ,KINTR ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KMt,17 ),
+ K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20 ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9 ),K(KMt,15 ),
+ K(KMt,16 ),KIGNORE ,KIGNORE ,KIGNORE ,KREBOOT ,K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4 ),K(KMt, 6 ),
+ K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11 ),K(KMt,12 ),KIGNORE ,KIGNORE ,KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,26 ),K(KMt,24 ),
+ K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14 ),K(KMt,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,KIGNORE ,
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KREBOOT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', '\300'}, {'`', 'a', '\340'},
+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
+ {'^', 'A', '\302'}, {'^', 'a', '\342'},
+ {'~', 'A', '\303'}, {'~', 'a', '\343'},
+ {'"', 'A', '\304'}, {'"', 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {'`', 'E', '\310'}, {'`', 'e', '\350'},
+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
+ {'^', 'E', '\312'}, {'^', 'e', '\352'},
+ {'"', 'E', '\313'}, {'"', 'e', '\353'},
+ {'`', 'I', '\314'}, {'`', 'i', '\354'},
+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
+ {'^', 'I', '\316'}, {'^', 'i', '\356'},
+ {'"', 'I', '\317'}, {'"', 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'},
+ {'~', 'N', '\321'}, {'~', 'n', '\361'},
+ {'`', 'O', '\322'}, {'`', 'o', '\362'},
+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
+ {'^', 'O', '\324'}, {'^', 'o', '\364'},
+ {'~', 'O', '\325'}, {'~', 'o', '\365'},
+ {'"', 'O', '\326'}, {'"', 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {'`', 'U', '\331'}, {'`', 'u', '\371'},
+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
+ {'^', 'U', '\333'}, {'^', 'u', '\373'},
+ {'"', 'U', '\334'}, {'"', 'u', '\374'},
+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'},
+ {'s', 's', '\337'}, {'"', 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
#include <asm/pgtable.h>
#endif
-#ifdef MODULE
#include <linux/module.h>
-#endif
#include "fore200e.h"
#include "suni.h"
struct list_head *entry = real_head;
struct request *tmp;
+ req->elevator_sequence = orig_latency;
+
if (list_empty(real_head)) {
list_add(&req->queue, real_head);
return;
register struct request *rq = NULL;
if (!list_empty(&q->request_freelist)) {
- elevator_t *e = &q->elevator;
-
if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE))
return NULL;
rq->rq_status = RQ_ACTIVE;
rq->special = NULL;
rq->q = q;
- if (rq->cmd == READ)
- rq->elevator_sequence = e->read_latency;
- else
- rq->elevator_sequence = e->write_latency;
q->queue_requests++;
}
return rq;
goto get_rq;
}
+ /*
+ * skip first entry, for devices with active queue head
+ */
+ head = &q->queue_head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments);
switch (el_ret) {
req = __get_request_wait(q, rw);
spin_lock_irq(&io_request_lock);
+
+ head = &q->queue_head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
}
- head = &q->queue_head;
- if (q->head_active && !q->plugged)
- head = head->next;
-
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
# set when a framegrabber implements i2c support
obj-$(L_I2C) += i2c-old.o
-ifeq ($(CONFIG_DZ),y)
- L_OBJS += dz.o
-endif
-
+obj-$(CONFIG_DZ) += dz.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
NULL
};
-long __init dz_serial_console_init(long kmem_start, long kmem_end)
+void __init dz_serial_console_init(l)
{
register_console(&dz_sercons);
-
- return kmem_start;
}
#endif /* ifdef CONFIG_SERIAL_CONSOLE */
#define MODE_COLL 0x0010
#define MODE_DRETRY 0x0020
#define MODE_INTLOOP 0x0040
-#define MODE_PORT0 0x0080
+#define MODE_PORT_AUI 0x0000
+#define MODE_PORT_10BT 0x0080
#define MODE_DRXPA 0x2000
#define MODE_DRXBA 0x4000
#define MODE_PROMISC 0x8000
#define TST_LCAR 0x0800
#define TST_LCOL 0x1000
#define TST_UFLO 0x4000
+#define TST_BUFF 0x8000
struct dev_priv {
struct enet_statistics stats;
#include <asm/bitops.h>
#include <asm/io.h>
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#endif
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
ptr->next = irq;
else
(*res)->irq = irq;
+#ifdef CONFIG_PCI
for (i=0; i<16; i++)
if (irq->map & i)
pcibios_penalize_isa_irq(i);
+#endif
}
/*
p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
}
}
- p->sc = *sc;
+ memcpy(&p->sc, sc, sizeof(struct seeprom_config));
}
p->discenable = 0;
#endif
/* Put I2O last so that host specific controllers always win */
#ifdef CONFIG_I2O_SCSI
- I2OSCSI
+ I2OSCSI,
#endif
/* "Removable host adapters" below this line (Parallel Port/USB/other) */
#ifdef CONFIG_SCSI_PPA
#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir))
#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir))
#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir))
+#if BITS_PER_LONG > 32
+#define pci64_dma_hi32(a) ((u32) (0xffffffff & (a>>32)))
+#define pci64_dma_lo32(a) ((u32) (0xffffffff & (a)))
+#else
#define pci64_dma_hi32(a) 0
#define pci64_dma_lo32(a) (a)
+#endif /* BITS_PER_LONG */
#define pci64_dma_build(hi,lo) (lo)
#define sg_dma64_address(s) sg_dma_address(s)
#define sg_dma64_len(s) sg_dma_len(s)
+#if BITS_PER_LONG > 32
+#define PCI64_DMA_BITS 64
+#else
#define PCI64_DMA_BITS 32
+#endif /* BITS_PER_LONG */
#endif
#include "qlogicfc.h"
#define ISP2x00_FABRIC 1
/* Macros used for debugging */
-/*
-#define DEBUG_ISP2x00 1
-#define DEBUG_ISP2x00_INT 1
-#define DEBUG_ISP2x00_INTR 1
-#define DEBUG_ISP2x00_SETUP 1
-
-#define DEBUG_ISP2x00_FABRIC 1
-*/
-/* #define TRACE_ISP 1 */
+#define DEBUG_ISP2x00 0
+#define DEBUG_ISP2x00_INT 0
+#define DEBUG_ISP2x00_INTR 0
+#define DEBUG_ISP2x00_SETUP 0
+#define DEBUG_ISP2x00_FABRIC 0
+#define TRACE_ISP 0
#define DEFAULT_LOOP_COUNT 1000000000
for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1)));
if (!hostdata->handle_ptrs[i]) {
- cmd->handle = i;
+ cmd->handle = cpu_to_le32(i);
hostdata->handle_ptrs[i] = Cmnd;
hostdata->handle_serials[i] = Cmnd->serial_number;
} else {
break;
}
}
+ /*
+ * TEST_UNIT_READY commands from scsi_scan will fail due to "overlapped
+ * commands attempted" unless we setup at least a simple queue (midlayer
+ * will embelish this once it can do an INQUIRY command to the device)
+ */
+ else
+ cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG);
outw(in_ptr, host->io_port + MBOX4);
hostdata->req_in_ptr = in_ptr;
DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr)));
while (out_ptr != in_ptr) {
+ unsigned le_hand;
sts = (struct Status_Entry *) &hostdata->res[out_ptr*QUEUE_ENTRY_LEN];
out_ptr = (out_ptr + 1) & RES_QUEUE_LEN;
TRACE("done", out_ptr, Cmnd);
DEBUG_INTR(isp2x00_print_status_entry(sts));
- if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) {
+ le_hand = le32_to_cpu(sts->handle);
+ if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[le_hand])) {
Cmnd->result = isp2x00_return_status(Cmnd, sts);
hostdata->queued--;
* we dont have to call done because the upper
* level should already know its aborted.
*/
- if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number
+ if (hostdata->handle_serials[le_hand] != Cmnd->serial_number
|| le16_to_cpu(sts->completion_status) == CS_ABORTED){
- hostdata->handle_serials[sts->handle] = 0;
- hostdata->handle_ptrs[sts->handle] = NULL;
+ hostdata->handle_serials[le_hand] = 0;
+ hostdata->handle_ptrs[le_hand] = NULL;
outw(out_ptr, host->io_port + MBOX5);
continue;
}
continue;
}
- hostdata->handle_ptrs[sts->handle] = NULL;
+ hostdata->handle_ptrs[le_hand] = NULL;
if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED)
|| (sts->status_flags & cpu_to_le16(STF_BUS_RESET)))
}
#endif
-#ifdef __BIG_ENDIAN
- {
- u64 val;
- memcpy(&val, &hostdata->control_block.node_name, sizeof(u64));
- hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8)
- | ((val & 0x00ff00ff00ff00ffULL) << 8);
- }
-#else
- hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0x00ff) << 48;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0x00ff) << 24;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8;
- hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8;
-#endif
+ hostdata->wwn = (u64) (cpu_to_le16(hostdata->control_block.node_name[0])) << 56;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[0]) & 0xff00) << 48;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0xff00) << 24;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0x00ff) << 48;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0x00ff) << 24;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0xff00) << 8;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8;
+ hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8;
/* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */
busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block),
* determined for each queue request anew.
*/
-#if PCI64_DMA_BITS > 32
+#if BITS_PER_LONG > 32
#define DATASEGS_PER_COMMAND 2
#define DATASEGS_PER_CONT 5
#else
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local
+ Last modified: Sat Jun 17 15:21:49 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
#include "constants.h"
-static int buffer_kbs = 0;
-static int write_threshold_kbs = 0;
+static int buffer_kbs;
+static int write_threshold_kbs;
static int max_buffers = (-1);
-static int max_sg_segs = 0;
+static int max_sg_segs;
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver");
static Scsi_Tape **scsi_tapes = NULL;
-static int modes_defined = FALSE;
+static int modes_defined;
static ST_buffer *new_tape_buffer(int, int);
static int enlarge_buffer(ST_buffer *, int, int);
static int scsi_tape_flush(struct file *filp)
{
int result = 0, result2;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
ssize_t retval = 0;
int write_threshold;
int doing_write = 0;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
const char *b_point;
Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
ST_mode *STm;
ST_partstat *STps;
if (mtc.mt_op == MTSETPART) {
if (!STp->can_partitions ||
- mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
- return (-EINVAL);
+ mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {
+ retval = (-EINVAL);
+ goto out;
+ }
if (mtc.mt_count >= STp->nbr_partitions &&
- (STp->nbr_partitions = nbr_partitions(STp)) < 0)
- return (-EIO);
- if (mtc.mt_count >= STp->nbr_partitions)
- return (-EINVAL);
+ (STp->nbr_partitions = nbr_partitions(STp)) < 0) {
+ retval = (-EIO);
+ goto out;
+ }
+ if (mtc.mt_count >= STp->nbr_partitions) {
+ retval = (-EINVAL);
+ goto out;
+ }
STp->new_partition = mtc.mt_count;
retval = 0;
goto out;
}
if (mtc.mt_op == MTMKPART) {
- if (!STp->can_partitions)
- return (-EINVAL);
+ if (!STp->can_partitions) {
+ retval = (-EINVAL);
+ goto out;
+ }
if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
- (i = partition_tape(STp, mtc.mt_count)) < 0)
- return i;
+ (i = partition_tape(STp, mtc.mt_count)) < 0) {
+ retval = i;
+ goto out;
+ }
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].at_sm = 0;
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/iomd.h>
+#include <asm/irq.h>
#include <asm/system.h>
#include "sound_config.h"
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (6/22/2000) pberger and borchers
+* -- Made cond_wait_... inline--apparently on SPARC the flags arg
+* to spin_lock_irqsave cannot be passed to another function
+* to call spin_unlock_irqrestore. Thanks to Pauline Middelink.
+* -- In digi_set_modem_signals the inner nested spin locks use just
+* spin_lock() rather than spin_lock_irqsave(). The old code
+* mistakenly left interrupts off. Thanks to Pauline Middelink.
+* -- copy_from_user (which can sleep) is no longer called while a
+* spinlock is held. We copy to a local buffer before getting
+* the spinlock--don't like the extra copy but the code is simpler.
+* -- Printk and dbg are no longer called while a spin lock is held.
+*
* (6/4/2000) pberger and borchers
* -- Replaced separate calls to spin_unlock_irqrestore and
* interruptible_sleep_on_interruptible with a new function
* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
* recheck the condition they are sleeping on. This is defensive,
* in case a wake up is lost.
+* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
+* are held when calling copy_to/from_user or printk.
*
-* $Id: digi_acceleport.c,v 1.56 2000/06/07 22:47:30 root Exp root $
+* $Id: digi_acceleport.c,v 1.60 2000/06/23 17:43:17 root Exp root $
*/
#include <linux/config.h>
* wake ups. This is used to implement condition variables.
*/
-static long cond_wait_interruptible_timeout_irqrestore(
+static inline long cond_wait_interruptible_timeout_irqrestore(
wait_queue_head_t *q, long timeout,
spinlock_t *lock, unsigned long flags )
{
if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
count -= len;
buf += len;
- } else {
- dbg(
- "digi_write_oob_command: usb_submit_urb failed, ret=%d",
- ret );
- break;
}
}
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
}
/* len must be a multiple of 4 and small enough to */
- /* guarantee the write will send all data (or none), */
- /* so commands are not split */
+ /* guarantee the write will send buffered data first, */
+ /* so commands are in order with data and not split */
len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
if( len > 4 )
len &= ~3;
port->write_urb->transfer_buffer_length = len;
}
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
-
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
priv->dp_buf_len = 0;
count -= len;
buf += len;
- } else {
- dbg(
- "digi_write_inb_command: usb_submit_urb failed, ret=%d",
- ret );
- break;
}
}
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
port_priv->dp_port_num, modem_signals );
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock_irqsave( &port_priv->dp_port_lock, flags );
+ spin_lock( &port_priv->dp_port_lock );
while( oob_port->write_urb->status == -EINPROGRESS ) {
- spin_unlock_irqrestore( &port_priv->dp_port_lock, flags );
+ spin_unlock( &port_priv->dp_port_lock );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock_irqsave( &port_priv->dp_port_lock, flags );
+ spin_lock( &port_priv->dp_port_lock );
}
data[0] = DIGI_CMD_SET_DTR_SIGNAL;
port_priv->dp_modem_signals =
(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
- } else {
- dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
- ret );
}
- spin_unlock_irqrestore( &port_priv->dp_port_lock, flags );
+ spin_unlock( &port_priv->dp_port_lock );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
int ret,data_len,new_len;
digi_private_t *priv = (digi_private_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
+ unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */
unsigned long flags = 0;
dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",
priv->dp_port_num, count, from_user, in_interrupt() );
+ /* copy user data (which can sleep) before getting spin lock */
+ count = MIN( 64, MIN( count, port->bulk_out_size-2 ) );
+ if( from_user && copy_from_user( user_buf, buf, count ) ) {
+ return( -EFAULT );
+ }
+
/* be sure only one write proceeds at a time */
/* there are races on the port private buffer */
/* and races to check write_urb->status */
data += priv->dp_buf_len;
/* copy in new data */
- if( from_user ) {
- if( copy_from_user( data, buf, new_len ) ) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( -EFAULT );
- }
- } else {
- memcpy( data, buf, new_len );
- }
-
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
+ memcpy( data, from_user ? user_buf : buf, new_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
ret = new_len;
priv->dp_buf_len = 0;
- } else {
- dbg( "digi_write: usb_submit_urb failed, ret=%d",
- ret );
}
/* return length of new data written, or error */
-dbg( "digi_write: returning %d", ret );
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ if( ret < 0 ) {
+ dbg( "digi_write: usb_submit_urb failed, ret=%d", ret );
+ }
+dbg( "digi_write: returning %d", ret );
return( ret );
}
memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
priv->dp_buf_len );
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write_bulk_callback: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
-
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
priv->dp_buf_len = 0;
- } else {
- dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d", ret );
}
}
spin_unlock( &priv->dp_port_lock );
+ if( ret ) {
+ dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
/* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */
priv->dp_tasks.routine = (void *)digi_wakeup_write_lock;
unsigned long flags = 0;
-dbg( "digi_write_room: TOP: port=%d", priv->dp_port_num );
-
spin_lock_irqsave( &priv->dp_port_lock, flags );
if( port->write_urb->status == -EINPROGRESS )
digi_private_t *priv = (digi_private_t *)(port->private);
-dbg( "digi_chars_in_buffer: TOP: port=%d", priv->dp_port_num );
-
if( port->write_urb->status == -EINPROGRESS ) {
dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
/* return( port->bulk_out_size - 2 ); */
int i,ret = 0;
- spin_lock( &startup_lock );
-
/* be sure this happens exactly once */
+ spin_lock( &startup_lock );
if( device_startup ) {
spin_unlock( &startup_lock );
return( 0 );
}
+ device_startup = 1;
+ spin_unlock( &startup_lock );
/* start reading from each bulk in endpoint for the device */
for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
}
- device_startup = 1;
-
- spin_unlock( &startup_lock );
-
return( ret );
}
goto resubmit;
}
-#ifdef DEBUG_DATA
-if( urb->actual_length ) {
- printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: port=%d, length=%d, data=",
- priv->dp_port_num, urb->actual_length );
- for( i=0; i<urb->actual_length; ++i ) {
- printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] );
- }
- printk( "\n" );
-}
-#endif
-
if( urb->actual_length != len + 2 )
err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", priv->dp_port_num, opcode, len, urb->actual_length, status );
wait_queue_head_t write_wait;
+ struct tq_struct tqueue; /* task queue for line discipline waking up */
+
void * private; /* data private to the specific port */
};
return 0;
}
-
#endif /* ifdef __LINUX_USB_SERIAL_H */
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/25/2000) gkh
+ * Changed generic_write_bulk_callback to not call wake_up_interruptible
+ * directly, but to have port_softint do it at a safer time.
+ *
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
#define DEBUG
static int generic_write_room (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- int room;
+ int room = 0;
dbg(__FUNCTION__ " - port %d", port->number);
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
- room = 0;
- else
+ if (serial->num_bulk_out)
+ if (port->write_urb->status != -EINPROGRESS)
room = port->bulk_out_size;
- dbg(__FUNCTION__ " returns %d", room);
- return (room);
- }
- return (0);
+ dbg(__FUNCTION__ " - returns %d", room);
+ return (room);
}
static int generic_chars_in_buffer (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ int chars = 0;
dbg(__FUNCTION__ " - port %d", port->number);
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- return (port->bulk_out_size);
- }
- }
+ if (serial->num_bulk_out)
+ if (port->write_urb->status == -EINPROGRESS)
+ chars = port->write_urb->transfer_buffer_length;
- return (0);
+ dbg (__FUNCTION__ " - returns %d", chars);
+ return (chars);
}
unsigned char *data = urb->transfer_buffer;
int i;
- dbg (__FUNCTION__ " - enter");
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
if (usb_submit_urb(urb))
dbg(__FUNCTION__ " - failed resubmitting read urb");
- dbg (__FUNCTION__ " - exit");
-
return;
}
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
- struct tty_struct *tty;
- dbg (__FUNCTION__ " - enter");
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
return;
}
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return;
+}
+
+
+static void port_softint(void *private)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)private;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ return;
+ }
+
tty = port->tty;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+ dbg(__FUNCTION__ " - write wakeup call.");
(tty->ldisc.write_wakeup)(tty);
+ }
wake_up_interruptible(&tty->write_wait);
-
- dbg (__FUNCTION__ " - exit");
-
- return;
}
+
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
+ port->tqueue.routine = port_softint;
+ port->tqueue.data = port;
}
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/25/2000) gkh
+ * Fixed bug in visor_unthrottle that should help with the disconnect in PPP
+ * bug that people have been reporting.
+ *
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
{
dbg(__FUNCTION__ " - port %d", port->number);
- if (usb_unlink_urb (port->read_urb))
+ if (usb_submit_urb (port->read_urb))
dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return;
const char *name;
} dev_list[] = {
{
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540, "SIS 540"}, {
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, "SIS 630"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5300, "SIS 540"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_6300, "SIS 630"}, {
0, 0, NULL}
};
interpreter,
&interp_load_addr);
- lock_kernel();
+ allow_write_access(interpreter);
fput(interpreter);
- unlock_kernel();
kfree(elf_interpreter);
if (elf_entry == ~0UL) {
/* error cleanup */
out_free_dentry:
- lock_kernel();
+ allow_write_access(interpreter);
fput(interpreter);
- unlock_kernel();
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/init.h>
+#include <linux/file.h>
#define EM86_INTERP "/usr/bin/em86"
}
bprm->sh_bang++; /* Well, the bang-shell is implicit... */
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
if (!fmt)
goto _ret;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
*/
bprm->sh_bang++;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
ret = bdev->bd_op->open(fake_inode, &fake_file);
if (!ret)
atomic_inc(&bdev->bd_openers);
+ else if (!atomic_read(&bdev->bd_openers))
+ bdev->bd_op = NULL;
iput(fake_inode);
}
}
ret = bdev->bd_op->open(inode,filp);
if (!ret)
atomic_inc(&bdev->bd_openers);
+ else if (!atomic_read(&bdev->bd_openers))
+ bdev->bd_op = NULL;
}
up(&bdev->bd_sem);
return ret;
goto out;
dentry = file->f_dentry;
- if (!dentry)
- goto out_putf;
-
inode = dentry->d_inode;
- if (!inode)
- goto out_putf;
err = -EINVAL;
if (!file->f_op || !file->f_op->fsync)
goto out;
dentry = file->f_dentry;
- if (!dentry)
- goto out_putf;
-
inode = dentry->d_inode;
- if (!inode)
- goto out_putf;
err = -EINVAL;
if (!file->f_op || !file->f_op->fsync)
spin_unlock(&free_list[isize].lock);
page->buffers = bh;
+ page->flags &= ~(1 << PG_referenced);
lru_cache_add(page);
atomic_inc(&buffermem_pages);
return 1;
*/
asmlinkage long sys_uselib(const char * library)
{
- int fd, retval;
struct file * file;
+ struct nameidata nd;
+ int error;
- fd = sys_open(library, 0, 0);
- if (fd < 0)
- return fd;
- file = fget(fd);
- retval = -ENOEXEC;
- if (file) {
- if(file->f_op && file->f_op->read) {
- struct linux_binfmt * fmt;
+ error = user_path_walk(library, &nd);
+ if (error)
+ goto out;
- read_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- if (!fmt->load_shlib)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- read_unlock(&binfmt_lock);
- retval = fmt->load_shlib(file);
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (retval != -ENOEXEC)
- break;
- }
+ error = -EINVAL;
+ if (!S_ISREG(nd.dentry->d_inode->i_mode))
+ goto exit;
+
+ error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC);
+ if (error)
+ goto exit;
+
+ lock_kernel();
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ unlock_kernel();
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
+ goto out;
+
+ error = -ENOEXEC;
+ if(file->f_op && file->f_op->read) {
+ struct linux_binfmt * fmt;
+
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ if (!fmt->load_shlib)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
read_unlock(&binfmt_lock);
+ error = fmt->load_shlib(file);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (error != -ENOEXEC)
+ break;
}
- fput(file);
+ read_unlock(&binfmt_lock);
}
- sys_close(fd);
- return retval;
+ fput(file);
+out:
+ return error;
+exit:
+ path_release(&nd);
+ goto out;
}
/*
struct file *open_exec(const char *name)
{
struct nameidata nd;
+ struct inode *inode;
struct file *file;
int err = 0;
unlock_kernel();
file = ERR_PTR(err);
if (!err) {
+ inode = nd.dentry->d_inode;
file = ERR_PTR(-EACCES);
- if (S_ISREG(nd.dentry->d_inode->i_mode)) {
- int err = permission(nd.dentry->d_inode, MAY_EXEC);
+ if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) {
+ int err = permission(inode, MAY_EXEC);
file = ERR_PTR(err);
if (!err) {
lock_kernel();
file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
unlock_kernel();
+ if (!IS_ERR(file)) {
+ err = deny_write_access(file);
+ if (err) {
+ fput(file);
+ file = ERR_PTR(err);
+ }
+ }
out:
return file;
}
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- int retval,id_change,cap_raised;
+ int id_change,cap_raised;
struct inode * inode = bprm->file->f_dentry->d_inode;
mode = inode->i_mode;
- if (!S_ISREG(mode)) /* must be regular file */
- return -EACCES;
- if (!(mode & 0111)) /* with at least _one_ execute bit set */
+ /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */
+ if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
- if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */
- return -EACCES;
- if (!inode->i_sb)
- return -EACCES;
- if ((retval = permission(inode, MAY_EXEC)) != 0)
- return retval;
- /* better not execute files which are being written to */
- if (atomic_read(&inode->i_writecount) > 0)
- return -ETXTBSY;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
char * dynloader[] = { "/sbin/loader" };
struct file * file;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
+ allow_write_access(bprm->file);
if (bprm->file)
fput(bprm->file);
bprm->file = NULL;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.envc;
}
out:
/* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
/*
* set up enough so that it can read an inode
*/
- sb->s_dev = dev;
sb->s_op = &ext2_sops;
sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
if (!sb->s_root) {
err = sock_fcntl (filp, cmd, arg);
break;
}
- fput(filp);
unlock_kernel();
+ fput(filp);
out:
return err;
}
static kmem_cache_t *filp_cache;
/* sysctl tunables... */
-int nr_files; /* read only */
-int nr_free_files; /* read only */
-int max_files = NR_FILE;/* tunable */
+struct files_stat_struct files_stat = {0, 0, NR_FILE};
/* Here the new files go */
static LIST_HEAD(anon_list);
struct file * f;
file_list_lock();
- if (nr_free_files > NR_RESERVED_FILES) {
+ if (files_stat.nr_free_files > NR_RESERVED_FILES) {
used_one:
f = list_entry(free_list.next, struct file, f_list);
list_del(&f->f_list);
- nr_free_files--;
+ files_stat.nr_free_files--;
new_one:
file_list_unlock();
memset(f, 0, sizeof(*f));
/*
* Use a reserved one if we're the superuser
*/
- if (nr_free_files && !current->euid)
+ if (files_stat.nr_free_files && !current->euid)
goto used_one;
/*
* Allocate a new one if we're below the limit.
*/
- if (nr_files < max_files) {
+ if (files_stat.nr_files < files_stat.max_files) {
file_list_unlock();
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
file_list_lock();
if (f) {
- nr_files++;
+ files_stat.nr_files++;
goto new_one;
}
/* Big problems... */
printk("VFS: filp allocation failed\n");
- } else if (max_files > old_max) {
- printk("VFS: file-max limit %d reached\n", max_files);
- old_max = max_files;
+ } else if (files_stat.max_files > old_max) {
+ printk("VFS: file-max limit %d reached\n", files_stat.max_files);
+ old_max = files_stat.max_files;
}
file_list_unlock();
return NULL;
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
- nr_free_files++;
+ files_stat.nr_free_files++;
file_list_unlock();
}
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
- nr_free_files++;
+ files_stat.nr_free_files++;
file_list_unlock();
}
}
struct iattr newattrs;
int err;
hpfs_unlock_2inodes(dir, inode);
- if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret;
+ if (rep)
+ goto ret;
+ d_drop(dentry);
+ if (dentry->d_count > 1 ||
+ permission(inode, MAY_WRITE) ||
+ get_write_access(inode)) {
+ d_rehash(dentry);
+ goto ret;
+ }
/*printk("HPFS: truncating file before delete.\n");*/
down(&inode->i_sem);
newattrs.ia_size = 0;
else if (filp->f_op && filp->f_op->ioctl)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
}
- fput(filp);
unlock_kernel();
+ fput(filp);
out:
return error;
* if the pathname has trailing slashes - follow.
* otherwise - don't follow.
* (applied in that order).
+ *
+ * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT
+ * restored for 2.4. This is the last surviving part of old 4.2BSD bug.
+ * During the 2.4 we need to fix the userland stuff depending on it -
+ * hopefully we will be able to get rid of that wart in 2.5. So far only
+ * XEmacs seems to be relying on it...
*/
/* In order to reduce some races, while at the same time doing additional
* < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
* > 0: (i_writecount) users are writing to the file.
*
- * WARNING: as soon as we will move get_write_access(), do_mmap() or
- * prepare_binfmt() out of the big lock we will need a spinlock protecting
- * the checks in all 3. For the time being it is not needed.
+ * Normally we operate on that counter with atomic_{inc,dec} and it's safe
+ * except for the cases where we don't hold i_writecount yet. Then we need to
+ * use {get,deny}_write_access() - these functions check the sign and refuse
+ * to do the change if sign is wrong. Exclusion between them is provided by
+ * spinlock (arbitration_lock) and I'll rip the second arsehole to the first
+ * who will try to move it in struct inode - just leave it here.
*/
+static spinlock_t arbitration_lock = SPIN_LOCK_UNLOCKED;
int get_write_access(struct inode * inode)
{
- if (atomic_read(&inode->i_writecount) < 0)
+ spin_lock(&arbitration_lock);
+ if (atomic_read(&inode->i_writecount) < 0) {
+ spin_unlock(&arbitration_lock);
return -ETXTBSY;
+ }
atomic_inc(&inode->i_writecount);
+ spin_unlock(&arbitration_lock);
return 0;
}
-
-void put_write_access(struct inode * inode)
+int deny_write_access(struct file * file)
{
- atomic_dec(&inode->i_writecount);
+ spin_lock(&arbitration_lock);
+ if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
+ spin_unlock(&arbitration_lock);
+ return -ETXTBSY;
+ }
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ spin_unlock(&arbitration_lock);
+ return 0;
}
void path_release(struct nameidata *nd)
{
return __follow_down(mnt,dentry);
}
-
+
+static inline void follow_dotdot(struct nameidata *nd)
+{
+ while(1) {
+ struct vfsmount *parent;
+ struct dentry *dentry;
+ if (nd->dentry == current->fs->root &&
+ nd->mnt == current->fs->rootmnt) {
+ break;
+ }
+ if (nd->dentry != nd->mnt->mnt_root) {
+ dentry = dget(nd->dentry->d_parent);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ break;
+ }
+ parent=nd->mnt->mnt_parent;
+ if (parent == nd->mnt) {
+ break;
+ }
+ mntget(parent);
+ dentry=dget(nd->mnt->mnt_mountpoint);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ mntput(nd->mnt);
+ nd->mnt = parent;
+ }
+}
/*
* Name resolution.
*
case 2:
if (this.name[1] != '.')
break;
- while (1) {
- if (nd->dentry == current->fs->root &&
- nd->mnt == current->fs->rootmnt)
- break;
- if (nd->dentry != nd->mnt->mnt_root) {
- dentry = dget(nd->dentry->d_parent);
- dput(nd->dentry);
- nd->dentry = dentry;
- break;
- }
- if (!__follow_up(&nd->mnt, &nd->dentry))
- break;
- }
+ follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
case 2:
if (this.name[1] != '.')
break;
- while (1) {
- if (nd->dentry == current->fs->root &&
- nd->mnt == current->fs->rootmnt)
- break;
- if (nd->dentry != nd->mnt->mnt_root) {
- dentry = dget(nd->dentry->d_parent);
- dput(nd->dentry);
- nd->dentry = dentry;
- break;
- }
- if (!__follow_up(&nd->mnt, &nd->dentry))
- break;
- }
+ follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
int error;
if (!victim->d_inode || victim->d_parent->d_inode != dir)
return -ENOENT;
- if (IS_DEADDIR(dir))
- return -ENOENT;
error = permission(dir,MAY_WRITE | MAY_EXEC);
if (error)
return error;
return -ENOTDIR;
if (IS_ROOT(victim))
return -EBUSY;
- if (d_mountpoint(victim))
- return -EBUSY;
} else if (S_ISDIR(victim->d_inode->i_mode))
return -EISDIR;
return 0;
int acc_mode, error = 0;
struct inode *inode;
struct dentry *dentry;
+ struct dentry *dir;
+ int count = 0;
acc_mode = ACC_MODE(flag);
+
+ /*
+ * The simplest case - just a plain lookup.
+ */
if (!(flag & O_CREAT)) {
if (path_init(pathname, lookup_flags(flag), nd))
error = path_walk(pathname, nd);
if (error)
return error;
-
dentry = nd->dentry;
- } else {
- struct dentry *dir;
+ goto ok;
+ }
- if (path_init(pathname, LOOKUP_PARENT, nd))
- error = path_walk(pathname, nd);
+ /*
+ * Create - we need to know the parent.
+ */
+ if (path_init(pathname, LOOKUP_PARENT, nd))
+ error = path_walk(pathname, nd);
+ if (error)
+ return error;
+
+ /*
+ * We have the parent and last component. First of all, check
+ * that we are not asked to creat(2) an obvious directory - that
+ * will not do.
+ */
+ error = -EISDIR;
+ if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])
+ goto exit;
+
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+ dentry = lookup_hash(&nd->last, nd->dentry);
+
+do_last:
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ up(&dir->d_inode->i_sem);
+ goto exit;
+ }
+
+ /* Negative dentry, just create the file */
+ if (!dentry->d_inode) {
+ error = vfs_create(dir->d_inode, dentry, mode);
+ up(&dir->d_inode->i_sem);
+ dput(nd->dentry);
+ nd->dentry = dentry;
if (error)
- return error;
- /*
- * It's not obvious that open(".", O_CREAT, foo) should
- * fail, but it's even less obvious that it should succeed.
- * Since O_CREAT means an intention to create the thing and
- * open(2) had never created directories, count it as caller's
- * luserdom and let him sod off - -EISDIR it is.
- */
- error = -EISDIR;
- if (nd->last_type != LAST_NORM)
- goto exit;
- /* same for foo/ */
- if (nd->last.name[nd->last.len])
goto exit;
+ /* Don't check for write permission, don't truncate */
+ acc_mode = 0;
+ flag &= ~O_TRUNC;
+ goto ok;
+ }
- dir = nd->dentry;
- down(&dir->d_inode->i_sem);
+ /*
+ * It already exists.
+ */
+ up(&dir->d_inode->i_sem);
- dentry = lookup_hash(&nd->last, nd->dentry);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry)) {
- up(&dir->d_inode->i_sem);
- goto exit;
- }
+ error = -EEXIST;
+ if (flag & O_EXCL)
+ goto exit_dput;
- if (dentry->d_inode) {
- up(&dir->d_inode->i_sem);
- error = -EEXIST;
- if (flag & O_EXCL)
- goto exit_dput;
- if (dentry->d_inode->i_op &&
- dentry->d_inode->i_op->follow_link) {
- /*
- * With O_EXCL it would be -EEXIST.
- * If symlink is a dangling one it's -ENOENT.
- * Otherwise we open the object it points to.
- */
- error = do_follow_link(dentry, nd);
- dput(dentry);
- if (error)
- return error;
- dentry = nd->dentry;
- } else {
- dput(nd->dentry);
- nd->dentry = dentry;
- }
- error = -EISDIR;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
- goto exit;
- } else {
- error = vfs_create(dir->d_inode, dentry, mode);
- up(&dir->d_inode->i_sem);
- /* Don't check for write permission, don't truncate */
- acc_mode = 0;
- flag &= ~O_TRUNC;
- dput(nd->dentry);
- nd->dentry = dentry;
- if (error)
- goto exit;
- }
+ if (d_mountpoint(dentry)) {
+ error = -ELOOP;
+ if (flag & O_NOFOLLOW)
+ goto exit_dput;
+ do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry));
}
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit_dput;
+ if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
+ goto do_link;
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ error = -EISDIR;
+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+ goto exit;
+ok:
error = -ENOENT;
inode = dentry->d_inode;
if (!inode)
exit:
path_release(nd);
return error;
+
+do_link:
+ error = -ELOOP;
+ if (flag & O_NOFOLLOW)
+ goto exit_dput;
+ /*
+ * This is subtle. Instead of calling do_follow_link() we do the
+ * thing by hands. The reason is that this way we have zero link_count
+ * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT.
+ * After that we have the parent and last component, i.e.
+ * we are in the same situation as after the first path_walk().
+ * Well, almost - if the last component is normal we get its copy
+ * stored in nd->last.name and we will have to putname() it when we
+ * are done. Procfs-like symlinks just set LAST_BIND.
+ */
+ UPDATE_ATIME(dentry->d_inode);
+ error = dentry->d_inode->i_op->follow_link(dentry, nd);
+ dput(dentry);
+ if (error)
+ return error;
+ if (nd->last_type == LAST_BIND) {
+ dentry = nd->dentry;
+ goto ok;
+ }
+ error = -EISDIR;
+ if (nd->last_type != LAST_NORM)
+ goto exit;
+ if (nd->last.name[nd->last.len]) {
+ putname(nd->last.name);
+ goto exit;
+ }
+ if (count++==32) {
+ dentry = nd->dentry;
+ putname(nd->last.name);
+ goto ok;
+ }
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+ dentry = lookup_hash(&nd->last, nd->dentry);
+ putname(nd->last.name);
+ goto do_last;
}
static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
d_unhash(dentry);
- error = dir->i_op->rmdir(dir, dentry);
- if (!error)
- dentry->d_inode->i_flags |= S_DEAD;
+ if (IS_DEADDIR(dir))
+ error = -ENOENT;
+ else if (d_mountpoint(dentry))
+ error = -EBUSY;
+ else {
+ error = dir->i_op->rmdir(dir, dentry);
+ if (!error)
+ dentry->d_inode->i_flags |= S_DEAD;
+ }
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
if (!error)
d_delete(dentry);
error = -EPERM;
if (dir->i_op && dir->i_op->unlink) {
DQUOT_INIT(dir);
- error = dir->i_op->unlink(dir, dentry);
- if (!error)
- d_delete(dentry);
+ if (d_mountpoint(dentry))
+ error = -EBUSY;
+ else {
+ error = dir->i_op->unlink(dir, dentry);
+ if (!error)
+ d_delete(dentry);
+ }
}
}
up(&dir->i_zombie);
} else
double_down(&old_dir->i_zombie,
&new_dir->i_zombie);
- error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir))
+ error = -ENOENT;
+ else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (target) {
if (!error)
target->i_flags |= S_DEAD;
DQUOT_INIT(old_dir);
DQUOT_INIT(new_dir);
double_down(&old_dir->i_zombie, &new_dir->i_zombie);
- error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
double_up(&old_dir->i_zombie, &new_dir->i_zombie);
if (error)
return error;
static inline int
__vfs_follow_link(struct nameidata *nd, const char *link)
{
+ int res = 0;
+ char *name;
if (IS_ERR(link))
goto fail;
path_release(nd);
if (!walk_init_root(link, nd))
/* weird __emul_prefix() stuff did it */
- return 0;
+ goto out;
}
- return path_walk(link, nd);
-
+ res = path_walk(link, nd);
+out:
+ if (current->link_count || res || nd->last_type!=LAST_NORM)
+ return res;
+ /*
+ * If it is an iterative symlinks resolution in open_namei() we
+ * have to copy the last component. And all that crap because of
+ * bloody create() on broken symlinks. Furrfu...
+ */
+ name = __getname();
+ if (IS_ERR(name))
+ goto fail_name;
+ strcpy(name, nd->last.name);
+ nd->last.name = name;
+ return 0;
+fail_name:
+ link = name;
fail:
path_release(nd);
return PTR_ERR(link);
* creates a client control block and adds it to the hash
* table. Then, you call NFSCTL_EXPORT for each fs.
*
- * You cannot currently read the export information from the
- * kernel. It would be nice to have a /proc file though.
*
* Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
*/
err = -EPERM;
if (path) {
- err = 0;
- if (path_init(path, LOOKUP_POSITIVE, &nd))
- err = path_walk(path, &nd);
- if (err) {
+ if (path_init(path, LOOKUP_POSITIVE, &nd) &&
+ path_walk(path, &nd)) {
printk("nfsd: exp_rootfh path not found %s", path);
- return -EPERM;
+ return err;
}
dev = nd.dentry->d_inode->i_dev;
ino = nd.dentry->d_inode->i_ino;
fh_put(&fh);
out:
- path_release(&nd);
+ if (path)
+ path_release(&nd);
return err;
}
nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
{
struct svc_cacherep *rh, *rp;
- struct svc_client *clp = rqstp->rq_client;
u32 xid = rqstp->rq_xid,
+ proto = rqstp->rq_prot,
+ vers = rqstp->rq_vers,
proc = rqstp->rq_proc;
unsigned long age;
while ((rp = rp->c_hash_next) != rh) {
if (rp->c_state != RC_UNUSED &&
xid == rp->c_xid && proc == rp->c_proc &&
- exp_checkaddr(clp, rp->c_client)) {
+ proto == rp->c_prot && vers == rp->c_vers &&
+ time_before(jiffies, rp->c_timestamp + 120*HZ) &&
+ memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) {
nfsdstats.rchits++;
goto found_entry;
}
rp->c_state = RC_INPROG;
rp->c_xid = xid;
rp->c_proc = proc;
- rp->c_client = rqstp->rq_addr.sin_addr;
+ rp->c_addr = rqstp->rq_addr;
+ rp->c_prot = proto;
+ rp->c_vers = vers;
+ rp->c_timestamp = jiffies;
+
hash_refile(rp);
/* release any buffer */
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#define NFS_GETFH_NEW
#include <linux/config.h>
#include <linux/module.h>
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
- if (!fhp->fh_dverified) {
+ if (!fhp->fh_dentry) {
kdev_t xdev;
ino_t xino;
__u32 *datap=NULL;
int data_left = fh->fh_size/4;
int nfsdev;
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
datap = fh->fh_auth;
* Look up the dentry using the NFS file handle.
*/
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
/* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
fhp->fh_dentry = dentry;
fhp->fh_export = exp;
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
} else {
/* just rechecking permissions
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
- if (fhp->fh_dverified || fhp->fh_locked || fhp->fh_dentry) {
+ if (fhp->fh_locked || fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
parent->d_name.name, dentry->d_name.name);
}
fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
- /* We stuck it there, we know it's good. */
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
if (fhp->fh_handle.fh_fileid_type == 255)
return nfserr_opnotsupp;
struct dentry *dentry;
__u32 *datap;
- if (!fhp->fh_dverified)
+ if (!fhp->fh_dentry)
goto out_bad;
dentry = fhp->fh_dentry;
fh_put(struct svc_fh *fhp)
{
struct dentry * dentry = fhp->fh_dentry;
- if (fhp->fh_dverified) {
+ if (dentry) {
fh_unlock(fhp);
fhp->fh_dentry = NULL;
- fhp->fh_dverified = 0;
dput(dentry);
nfsd_nr_put++;
}
* whether the file exists or not. Time to bail ...
*/
nfserr = nfserr_acces;
- if (!newfhp->fh_dverified) {
+ if (!newfhp->fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n");
goto out_unlock;
dprintk("nfsd: MKDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
- if (resp->fh.fh_dverified) {
+ if (resp->fh.fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_mkdir: response already verified??\n");
}
/* Encode result.
* For NFSv2, additional info is never returned in case of an error.
*/
-#ifdef CONFIG_NFSD_V3
if (!(nfserr && rqstp->rq_vers == 2)) {
xdr = proc->pc_encode;
if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
return 1;
}
}
-#else
- xdr = proc->pc_encode;
- if (!nfserr && xdr
- && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
- /* Failed to encode result. Release cache entry */
- dprintk("nfsd: failed to encode result!\n");
- nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
- *statp = rpc_system_err;
- return 1;
- }
-#endif /* CONFIG_NFSD_V3 */
/* Store reply in cache. */
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
dentry = mounts;
} else
dput(mounts);
+ mntput(mnt);
}
}
/*
goto out_nfserr;
err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (err)
+ if (err) {
+ put_write_access(inode);
goto out_nfserr;
+ }
DQUOT_INIT(inode);
}
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(inode);
err = 0;
-
- /* Don't unlock inode; the nfssvc_release functions are supposed
- * to do this. */
out:
return err;
out:
return error;
}
-#endif
+#endif /* CONFIG_NFSD_V3 */
oldfs = get_fs(); set_fs(KERNEL_DS);
err = file.f_op->read(&file, buf, *count, &file.f_pos);
set_fs(oldfs);
- nfsdstats.io_read += *count;
/* Write back readahead params */
if (ra != NULL) {
}
if (err >= 0) {
+ nfsdstats.io_read += err;
*count = err;
err = 0;
} else
* When gathered writes have been configured for this volume,
* flushing the data to disk is handled separately below.
*/
-#ifdef CONFIG_NFSD_V3
+
if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
stable = 2;
*stablep = 2; /* FILE_SYNC */
}
+
if (!EX_ISSYNC(exp))
stable = 0;
if (stable && !EX_WGATHER(exp))
file.f_flags |= O_SYNC;
-#else
- if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
- file.f_flags |= O_SYNC;
-#endif /* CONFIG_NFSD_V3 */
file.f_pos = offset; /* set write offset */
#else
err = file.f_op->write(&file, buf, cnt, &file.f_pos);
#endif
- nfsdstats.io_write += cnt;
+ if (err >= 0)
+ nfsdstats.io_write += cnt;
set_fs(oldfs);
/* clear setuid/setgid flag after write */
#else
dprintk("nfsd: write defer %d\n", current->pid);
/* FIXME: Olaf commented this out [gam3] */
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((HZ+99)/100);
+ current->state = TASK_RUNNING;
dprintk("nfsd: write resume %d\n", current->pid);
#endif
}
dprintk("nfsd: write sync %d\n", current->pid);
nfsd_sync(&file);
}
+#if 0
wake_up(&inode->i_wait);
+#endif
last_ino = inode->i_ino;
last_dev = inode->i_dev;
}
#ifdef CONFIG_NFSD_V3
/*
- * Commit all pendig writes to stable storage.
- * Strictly speaking, we could sync just indicated the file region here,
+ * Commit all pending writes to stable storage.
+ * Strictly speaking, we could sync just the indicated file region here,
* but there's currently no way we can ask the VFS to do so.
*
- * We lock the file to make sure we return full WCC data to the client.
+ * Unfortunately we cannot lock the file to make sure we return full WCC
+ * data to the client, as locking happens lower down in the filesystem.
*/
int
nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
* Check whether the response file handle has been verified yet.
* If it has, the parent directory should already be locked.
*/
- if (!resfhp->fh_dverified) {
+ if (!resfhp->fh_dentry) {
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
fh_lock(fhp);
dchild = lookup_one(fname, dentry);
struct dentry *dentry, *dchild;
struct inode *dirp;
int err;
+ __u32 v_mtime=0, v_atime=0;
+ int v_mode=0;
err = nfserr_perm;
if (!flen)
if (err)
goto out;
+ if (createmode == NFS3_CREATE_EXCLUSIVE) {
+ /* while the verifier would fit in mtime+atime,
+ * solaris7 gets confused (bugid 4218508) if these have
+ * the high bit set, so we use the mode as well
+ */
+ v_mtime = verifier[0]&0x7fffffff;
+ v_atime = verifier[1]&0x7fffffff;
+ v_mode = S_IFREG
+ | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */
+ | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */
+ ;
+ }
+
if (dchild->d_inode) {
err = 0;
}
break;
case NFS3_CREATE_EXCLUSIVE:
- if ( dchild->d_inode->i_mtime == verifier[0]
- && dchild->d_inode->i_atime == verifier[1]
- && dchild->d_inode->i_mode == S_IFREG
- && dchild->d_inode->i_size == 0 )
+ if ( dchild->d_inode->i_mtime == v_mtime
+ && dchild->d_inode->i_atime == v_atime
+ && dchild->d_inode->i_mode == v_mode
+ && dchild->d_inode->i_size == 0 )
break;
/* fallthru */
case NFS3_CREATE_GUARDED:
goto out;
if (createmode == NFS3_CREATE_EXCLUSIVE) {
- /* Cram the verifier into atime/mtime */
- iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET;
- iap->ia_mtime = verifier[0];
- iap->ia_atime = verifier[1];
+ /* Cram the verifier into atime/mtime/mode */
+ iap->ia_valid = ATTR_MTIME|ATTR_ATIME
+ | ATTR_MTIME_SET|ATTR_ATIME_SET
+ | ATTR_MODE;
+ iap->ia_mtime = v_mtime;
+ iap->ia_atime = v_atime;
+ iap->ia_mode = v_mode;
}
- /* Set file attributes. Mode has already been set and
- * setting uid/gid works only for root. Irix appears to
- * send along the gid when it tries to implement setgid
- * directories via NFS. Clear out all that cruft.
+ /* Set file attributes.
+ * Mode has already been set but we might need to reset it
+ * for CREATE_EXCLUSIVE
+ * Irix appears to send along the gid when it tries to
+ * implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
out:
if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
goto out;
+ /* cannot use fh_lock as we need deadlock protective ordering
+ * so do it by hand */
double_down(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 1;
+ fill_pre_wcc(ffhp);
+ fill_pre_wcc(tfhp);
+
odentry = lookup_one(fname, fdentry);
err = PTR_ERR(odentry);
if (IS_ERR(odentry))
if (IS_ERR(ndentry))
goto out_dput_old;
-#ifdef CONFIG_NFSD_V3
- /* Fill in the pre-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_pre_wcc(ffhp);
- fill_pre_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
nfsd_sync_dir(tdentry);
nfsd_sync_dir(fdentry);
}
-#ifdef CONFIG_NFSD_V3
- /* Fill in the post-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_post_wcc(ffhp);
- fill_post_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
- double_up(&tdir->i_sem, &fdir->i_sem);
dput(ndentry);
-out_dput_old:
+ out_dput_old:
dput(odentry);
+ out_nfserr:
if (err)
- goto out_nfserr;
+ err = nfserrno(err);
+
+ /* we cannot reply on fh_unlock on the two filehandles,
+ * as that would do the wrong thing if the two directories
+ * were the same, so again we do it by hand
+ */
+ fill_post_wcc(ffhp);
+ fill_post_wcc(tfhp);
+ double_up(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 0;
+
out:
return err;
-
-out_nfserr:
- err = nfserrno(err);
- goto out;
}
/*
err = vfs_rmdir(dirp, rdentry);
}
- fh_unlock(fhp);
-
dput(rdentry);
if (err)
goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export)) {
- down(&dentry->d_inode->i_sem);
+ if (EX_ISSYNC(fhp->fh_export))
nfsd_sync_dir(dentry);
- up(&dentry->d_inode->i_sem);
- }
+
out:
return err;
struct file file;
struct readdir_cd cd;
- err = 0;
- if (offset > ~(u32) 0)
- goto out;
-
err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
if (err)
goto out;
+ if (offset > ~(u32) 0)
+ goto out_close;
err = nfserr_notdir;
if (!file.f_op->readdir)
eof = !cd.eob;
if (cd.offset) {
-#ifdef CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
(void)xdr_encode_hyper(cd.offset, file.f_pos);
else
-#endif /* CONFIG_NFSD_V3 */
*cd.offset = htonl(file.f_pos);
}
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+ root->i_sb = sb;
+ root->i_dev = sb->s_dev;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = PIPEFS_MAGIC;
goto out;
error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
+ nd->last_type = LAST_BIND;
out:
#ifdef NULL_VFSMNT
mntput(dummy);
set_blocksize(dev, QNX4_BLOCK_SIZE);
s->s_blocksize = QNX4_BLOCK_SIZE;
s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS;
- s->s_dev = dev;
/* Check the boot signature. Since the qnx4 code is
dangerous, we should leave as quickly as possible
return len;
}
-static struct file_system_type *get_fs_type(const char *name)
+struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type *fs;
static LIST_HEAD(vfsmntlist);
-static struct vfsmount *add_vfsmnt(struct super_block *sb,
- struct dentry *mountpoint,
+/**
+ * add_vfsmnt - add a new mount node
+ * @nd: location of mountpoint or %NULL if we want a root node
+ * @root: root of (sub)tree to be mounted
+ * @dev_name: device name to show in /proc/mounts
+ *
+ * This is VFS idea of mount. New node is allocated, bound to a tree
+ * we are mounting and optionally (OK, usually) registered as mounted
+ * on a given mountpoint. Returns a pointer to new node or %NULL in
+ * case of failure.
+ *
+ * Potential reason for failure (aside of trivial lack of memory) is a
+ * deleted mountpoint. Caller must hold ->i_zombie on mountpoint
+ * dentry (if any).
+ */
+
+static struct vfsmount *add_vfsmnt(struct nameidata *nd,
struct dentry *root,
- struct vfsmount *parent,
- const char *dev_name,
- const char *dir_name)
+ const char *dev_name)
{
struct vfsmount *mnt;
+ struct super_block *sb = root->d_inode->i_sb;
char *name;
mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
goto out;
memset(mnt, 0, sizeof(struct vfsmount));
- atomic_set(&mnt->mnt_count,1);
- mnt->mnt_sb = sb;
- mnt->mnt_mountpoint = dget(mountpoint);
- mnt->mnt_root = dget(root);
- mnt->mnt_parent = parent ? mntget(parent) : mnt;
-
- /* N.B. Is it really OK to have a vfsmount without names? */
+ /* It may be NULL, but who cares? */
if (dev_name) {
name = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (name) {
mnt->mnt_devname = name;
}
}
- name = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
- if (name) {
- strcpy(name, dir_name);
- mnt->mnt_dirname = name;
- }
mnt->mnt_owner = current->uid;
+ atomic_set(&mnt->mnt_count,1);
+ mnt->mnt_sb = sb;
- if (parent)
- list_add(&mnt->mnt_child, &parent->mnt_mounts);
- else
+ if (nd && !IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
+ goto fail;
+ mnt->mnt_root = dget(root);
+ mnt->mnt_mountpoint = nd ? dget(nd->dentry) : dget(root);
+ mnt->mnt_parent = nd ? mntget(nd->mnt) : mnt;
+
+ if (nd) {
+ list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+ list_add(&mnt->mnt_clash, &nd->dentry->d_vfsmnt);
+ } else {
INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_clash);
+ }
INIT_LIST_HEAD(&mnt->mnt_mounts);
list_add(&mnt->mnt_instances, &sb->s_mounts);
- list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
list_add(&mnt->mnt_list, vfsmntlist.prev);
out:
return mnt;
+fail:
+ kfree(mnt->mnt_devname);
+ kfree(mnt);
+ return NULL;
}
static void move_vfsmnt(struct vfsmount *mnt,
struct dentry *mountpoint,
struct vfsmount *parent,
- const char *dev_name,
- const char *dir_name)
+ const char *dev_name)
{
- struct dentry *old_mountpoint = mnt->mnt_mountpoint;
- struct vfsmount *old_parent = mnt->mnt_parent;
- char *new_devname = NULL, *new_dirname = NULL;
+ struct dentry *old_mountpoint;
+ struct vfsmount *old_parent;
+ char *new_devname = NULL;
if (dev_name) {
new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (new_devname)
strcpy(new_devname, dev_name);
}
- if (dir_name) {
- new_dirname = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
- if (new_dirname)
- strcpy(new_dirname, dir_name);
- }
+
+ old_mountpoint = mnt->mnt_mountpoint;
+ old_parent = mnt->mnt_parent;
/* flip names */
- if (new_dirname) {
- kfree(mnt->mnt_dirname);
- mnt->mnt_dirname = new_dirname;
- }
if (new_devname) {
kfree(mnt->mnt_devname);
mnt->mnt_devname = new_devname;
mnt->mnt_parent = parent ? mntget(parent) : mnt;
list_del(&mnt->mnt_clash);
list_del(&mnt->mnt_child);
- list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
- if (parent)
+ if (parent) {
list_add(&mnt->mnt_child, &parent->mnt_mounts);
- else
+ list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
+ } else {
INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_clash);
+ }
/* put the old stuff */
dput(old_mountpoint);
dput(mnt->mnt_mountpoint);
dput(mnt->mnt_root);
kfree(mnt->mnt_devname);
- kfree(mnt->mnt_dirname);
kfree(mnt);
}
/* Done with lookups, semaphore down */
down(&mount_sem);
dev = to_kdev_t(bdev->bd_dev);
- check_disk_change(dev);
- error = -EACCES;
- if (!(flags & MS_RDONLY) && is_read_only(dev))
- goto out;
sb = get_super(dev);
if (sb) {
if (fs_type == sb->s_type) {
error = blkdev_get(bdev, mode, 0, BDEV_FS);
if (error)
goto out;
+ check_disk_change(dev);
+ error = -EACCES;
+ if (!(flags & MS_RDONLY) && is_read_only(dev))
+ goto out1;
error = -EINVAL;
sb = read_super(dev, bdev, fs_type, flags, data, 0);
if (sb) {
path_release(&nd);
return sb;
}
+out1:
blkdev_put(bdev, BDEV_FS);
}
out:
put_unnamed_dev(dev);
return ERR_PTR(-EINVAL);
}
- mnt = add_vfsmnt(sb, sb->s_root, sb->s_root, NULL, "none", type->name);
+ mnt = add_vfsmnt(NULL, sb->s_root, "none");
if (!mnt) {
kill_super(sb, 0);
return ERR_PTR(-ENOMEM);
void kern_umount(struct vfsmount *mnt)
{
struct super_block *sb = mnt->mnt_sb;
- struct dentry *root = sb->s_root;
remove_vfsmnt(mnt);
- dput(root);
- sb->s_root = NULL;
kill_super(sb, 0);
}
{
struct super_block * sb = mnt->mnt_sb;
+ /*
+ * No sense to grab the lock for this test, but test itself looks
+ * somewhat bogus. Suggestions for better replacement?
+ * Ho-hum... In principle, we might treat that as umount + switch
+ * to rootfs. GC would eventually take care of the old vfsmount.
+ * The problem being: we have to implement rootfs and GC for that ;-)
+ * Actually it makes sense, especially if rootfs would contain a
+ * /reboot - static binary that would close all descriptors and
+ * call reboot(9). Then init(8) could umount root and exec /reboot.
+ */
if (mnt == current->fs->rootmnt && !umount_root) {
int retval = 0;
/*
if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
if (sb->s_type->fs_flags & FS_SINGLE)
put_filesystem(sb->s_type);
+ /* We hold two references, so mntput() is safe */
mntput(mnt);
remove_vfsmnt(mnt);
return 0;
shrink_dcache_sb(sb);
fsync_dev(sb->s_dev);
- /* Something might grab it again - redo checks */
-
- if (atomic_read(&mnt->mnt_count) > 2) {
+ if (sb->s_root->d_inode->i_state) {
mntput(mnt);
return -EBUSY;
}
- if (sb->s_root->d_inode->i_state) {
+ /* Something might grab it again - redo checks */
+
+ if (atomic_read(&mnt->mnt_count) > 2) {
mntput(mnt);
return -EBUSY;
}
{
if (capable(CAP_SYS_ADMIN))
return 0;
+ return -EPERM;
+#ifdef notyet
if (S_ISLNK(nd->dentry->d_inode->i_mode))
return -EPERM;
if (nd->dentry->d_inode->i_mode & S_ISVTX) {
if (permission(nd->dentry->d_inode, MAY_WRITE))
return -EPERM;
return 0;
+#endif
}
/*
if (S_ISDIR(new_nd.dentry->d_inode->i_mode) !=
S_ISDIR(old_nd.dentry->d_inode->i_mode))
goto out2;
-
- down(&mount_sem);
- err = -ENOENT;
- if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
- goto out3;
- if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
- goto out3;
- /* there we go */
+
err = -ENOMEM;
if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
get_filesystem(old_nd.mnt->mnt_sb->s_type);
- if (add_vfsmnt(old_nd.mnt->mnt_sb, new_nd.dentry, old_nd.dentry,
- new_nd.mnt, old_nd.mnt->mnt_devname, new_name))
+
+ down(&mount_sem);
+ /* there we go */
+ down(&new_nd.dentry->d_inode->i_zombie);
+ if (IS_DEADDIR(new_nd.dentry->d_inode))
+ err = -ENOENT;
+ else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname))
err = 0;
-out3:
+ up(&new_nd.dentry->d_inode->i_zombie);
up(&mount_sem);
+ if (err && old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
+ put_filesystem(old_nd.mnt->mnt_sb->s_type);
out2:
path_release(&new_nd);
out1:
{
struct file_system_type * fstype;
struct nameidata nd;
- struct vfsmount *mnt;
+ struct vfsmount *mnt = NULL;
struct super_block *sb;
int retval = 0;
unsigned long flags = 0;
if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
return -EINVAL;
- if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
- return -EINVAL;
if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
return -EINVAL;
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
flags = new_flags & ~MS_MGC_MSK;
+ /* For the rest we need the type */
+
+ if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
+ return -EINVAL;
+
/* loopback mount? This is special - requires fewer capabilities */
if (strcmp(type_page, "bind")==0)
return do_loopback(dev_name, dir_name);
if (IS_ERR(sb))
goto dput_out;
- retval = -ENOENT;
- if (d_unhashed(nd.dentry) && !IS_ROOT(nd.dentry))
- goto fail;
-
/* Something was mounted here while we slept */
while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
;
-
- retval = -ENOMEM;
- mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, dev_name, dir_name);
+ retval = -ENOENT;
+ if (!nd.dentry->d_inode)
+ goto fail;
+ down(&nd.dentry->d_inode->i_zombie);
+ if (!IS_DEADDIR(nd.dentry->d_inode)) {
+ retval = -ENOMEM;
+ mnt = add_vfsmnt(&nd, sb->s_root, dev_name);
+ }
+ up(&nd.dentry->d_inode->i_zombie);
if (!mnt)
goto fail;
retval = 0;
if (retval < 0)
return retval;
- /* copy_mount_options allows a NULL user pointer,
- * and just returns zero in that case. But if we
- * allow the type to be NULL we will crash.
- * Previously we did not check this case.
- */
- if (type_page == 0)
- return -EINVAL;
-
- lock_kernel();
dir_page = getname(dir_name);
retval = PTR_ERR(dir_page);
if (IS_ERR(dir_page))
goto out2;
retval = copy_mount_options (data, &data_page);
if (retval >= 0) {
+ lock_kernel();
retval = do_mount((char*)dev_page,dir_page,(char*)type_page,
new_flags, (void*)data_page);
+ unlock_kernel();
free_page(data_page);
}
free_page(dev_page);
putname(dir_page);
out1:
free_page(type_page);
- unlock_kernel();
return retval;
}
path + 5 + path_start, 0,
NULL, NULL);
memcpy (path + path_start, "/dev/", 5);
- vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
- path + path_start, "/");
+ vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start);
}
else
- vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
- "/dev/root", "/");
+ vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root");
+ /* FIXME: if something will try to umount us right now... */
if (vfsmnt) {
set_fs_root(current->fs, vfsmnt, sb->s_root);
set_fs_pwd(current->fs, vfsmnt, sb->s_root);
read_lock(&tasklist_lock);
for_each_task(p) {
+ /* FIXME - unprotected usage of ->fs + (harmless) race */
if (!p->fs) continue;
if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt)
set_fs_root(p->fs, new_rootmnt, new_root);
root_mnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
down(&mount_sem);
+ down(&old_nd.dentry->d_inode->i_zombie);
error = -ENOENT;
+ if (IS_DEADDIR(new_nd.dentry->d_inode))
+ goto out2;
if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
goto out2;
if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
goto out2;
- error = -ENOMEM;
- name = __getname();
- if (!name)
- goto out2;
-
- move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/");
- move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL,
- __d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry,
- new_nd.mnt, name, PAGE_SIZE));
- putname(name);
+ move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL);
+ move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL);
chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt);
error = 0;
out2:
+ up(&old_nd.dentry->d_inode->i_zombie);
up(&mount_sem);
dput(root);
mntput(root_mnt);
int __init change_root(kdev_t new_root_dev,const char *put_old)
{
kdev_t old_root_dev = ROOT_DEV;
- struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt);
+ struct vfsmount *old_rootmnt;
struct nameidata devfs_nd, nd;
int error = 0;
+ old_rootmnt = mntget(current->fs->rootmnt);
/* First unmount devfs if mounted */
if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
error = path_walk("/dev", &devfs_nd);
printk(KERN_ERR "error %ld\n",blivet);
return error;
}
- move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old);
+ /* FIXME: we should hold i_zombie on nd.dentry */
+ move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old");
mntput(old_rootmnt);
path_release(&nd);
return 0;
sb->s_blocksize = sb->sv_block_size;
sb->s_blocksize_bits = sb->sv_block_size_bits;
/* set up enough so that it can read an inode */
- sb->s_dev = dev;
sb->s_op = &sysv_sops;
root_inode = iget(sb,SYSV_ROOT_INO);
sb->s_root = d_alloc_root(root_inode);
return sb;
error_out:
- sb->s_dev = NODEV;
if (UDF_SB_VAT(sb))
iput(UDF_SB_VAT(sb));
if (!(sb->s_flags & MS_RDONLY))
#define PCIBIOS_MIN_IO alpha_mv.min_io_address
#define PCIBIOS_MIN_MEM alpha_mv.min_mem_address
-extern inline void pcibios_set_master(struct pci_dev *dev)
-{
- /* No special bus mastering setup handling */
-}
+extern void pcibios_set_master(struct pci_dev *dev);
extern inline void pcibios_penalize_isa_irq(int irq)
{
* We leave one page for the initial stack page, and one page for
* the initial process structure. Also, the console eats 3 MB for
* the initial bootloader (one of which we can reclaim later).
- * With a few other pages for various reasons, we'll use an initial
- * load address of PAGE_OFFSET+0x310000UL
*/
#define BOOT_PCB 0x20000000
#define BOOT_ADDR 0x20000000
/* Remove when official MILO sources have ELF support: */
#define BOOT_SIZE (16*1024)
-
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+#define KERNEL_START_PHYS 0x300000 /* Old bootloaders hardcoded this. */
+#else
#define KERNEL_START_PHYS 0x800000 /* Wildfire has a huge console */
+#endif
#define KERNEL_START (PAGE_OFFSET+KERNEL_START_PHYS)
#define SWAPPER_PGD KERNEL_START
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
memset(&hw, 0, sizeof(hw));
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_HARDDISK;
ide_register_hw(&hw, NULL);
#endif
}
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
}
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
{
hw_regs_t hw;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_HARDDISK;
ide_register_hw(&hw, NULL);
}
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg;
int i;
reg += (1 << IO_SHIFT);
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) (ctrl_port << IO_SHIFT);
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
/* MAC 23/4/1999, swap these round so that the left hand
hard disk is hda when viewed from the front. This
doesn't match the silkscreen however. */
- ide_init_hwif_ports(&hw,0x10,0x1e,EMPEG_IRQ_IDE2);
+ ide_init_hwif_ports(&hw,0x10,0x1e,NULL);
+ hw.irq = EMPEG_IRQ_IDE2;
ide_register_hw(&hw, NULL);
- ide_init_hwif_ports(&hw,0x00,0x0e,EMPEG_IRQ_IDE1);
+ ide_init_hwif_ports(&hw,0x00,0x0e,NULL);
+ hw.irq = EMPEG_IRQ_IDE1;
ide_register_hw(&hw, NULL);
#elif defined( CONFIG_SA1100_VICTOR )
/* set the pcmcia interface timing */
MECR = 0x00060006;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_GPIO7);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_GPIO7;
ide_register_hw(&hw, NULL);
#else
#error Missing IDE interface definition in include/asm/arch/ide.h
* 26-05-2000 JD SA-1111 support added
*/
#include <linux/config.h>
+#include <asm/irq.h>
#define fixup_irq(x) (x)
static void sa1100_GPIO11_27_demux(int irq, void *dev_id,
struct pt_regs *regs)
{
- int i, irq, spurious;
+ int i, spurious;
while( (irq = (GEDR & 0xfffff800)) ){
/*
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
/*
* Mapping areas
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
{
hw_regs_t hw;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, 14);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = 14;
ide_register_hw(&hw, NULL);
}
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter += i;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_sub(int i, volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= i;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_inc(volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter += 1;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_dec(volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= 1;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
unsigned long flags;
int result;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= 1;
result = (v->counter == 0);
- restore_flags (flags);
+ __restore_flags(flags);
return result;
}
unsigned long flags;
int result;
- save_flags_cli(flags);
+ __save_flags_cli(flags);
v->counter += i;
result = (v->counter < 0);
- restore_flags(flags);
+ __restore_flags(flags);
return result;
}
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
*addr &= ~mask;
- restore_flags (flags);
+ __restore_flags(flags);
}
#endif
void (*_set_pgd)(pgd_t *pgd);
/* XCHG */
unsigned long (*_xchg_1)(unsigned long x, volatile void *ptr);
- unsigned long (*_xchg_2)(unsigned long x, volatile void *ptr);
unsigned long (*_xchg_4)(unsigned long x, volatile void *ptr);
} processor;
#define cpu_do_idle() do { } while (0)
#define cpu_switch_mm(pgd,tsk) processor._set_pgd(pgd)
#define cpu_xchg_1(x,ptr) processor._xchg_1(x,ptr)
-#define cpu_xchg_2(x,ptr) processor._xchg_2(x,ptr)
#define cpu_xchg_4(x,ptr) processor._xchg_4(x,ptr)
extern void cpu_memc_update_all(pgd_t *pgd);
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
-#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/memory.h>
#include <asm/arch/dma.h>
/*
/*
* linux/include/asm-arm/floppy.h
*
- * (C) 1996 Russell King
+ * (C) 1996-2000 Russell King
+ *
+ * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here
*/
#ifndef __ASM_ARM_FLOPPY_H
#define __ASM_ARM_FLOPPY_H
#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK)
#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK)
-#define fd_request_dma() request_dma(FLOPPY_DMA,"floppy")
-#define fd_free_dma() free_dma(FLOPPY_DMA)
-#define fd_disable_dma() disable_dma(FLOPPY_DMA)
-#define fd_enable_dma() enable_dma(FLOPPY_DMA)
-#define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA)
-#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA, (mode))
-#define fd_set_dma_addr(addr) set_dma_addr(FLOPPY_DMA, virt_to_bus((addr)))
-#define fd_set_dma_count(len) set_dma_count(FLOPPY_DMA, (len))
+#define fd_request_dma() request_dma(DMA_FLOPPY,"floppy")
+#define fd_free_dma() free_dma(DMA_FLOPPY)
+#define fd_disable_dma() disable_dma(DMA_FLOPPY)
+#define fd_enable_dma() enable_dma(DMA_FLOPPY)
+#define fd_clear_dma_ff() clear_dma_ff(DMA_FLOPPY)
+#define fd_set_dma_mode(mode) set_dma_mode(DMA_FLOPPY, (mode))
+#define fd_set_dma_addr(addr) set_dma_addr(DMA_FLOPPY, virt_to_bus((addr)))
+#define fd_set_dma_count(len) set_dma_count(DMA_FLOPPY, (len))
#define fd_cacheflush(addr,sz)
/* need to clean up dma.h */
}
#define FDC1 (0x3f0)
-static int FDC2 = -1;
#define FLOPPY0_TYPE 4
#define FLOPPY1_TYPE 4
#define N_FDC 1
-#define N_DRIVE 8
+#define N_DRIVE 4
#define FLOPPY_MOTOR_MASK 0xf0
/*
* linux/include/asm-arm/io.h
*
- * Copyright (C) 1996-1999 Russell King
+ * Copyright (C) 1996-2000 Russell King
*
* Modifications:
* 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both
* 27-Mar-1999 PJB Second parameter of memcpy_toio is const..
* 04-Apr-1999 PJB Added check_signature.
* 12-Dec-1999 RMK More cleanups
+ * 18-Jun-2000 RMK Removed virt_to_* and friends definitions
*/
#ifndef __ASM_ARM_IO_H
#define __ASM_ARM_IO_H
#ifdef __KERNEL__
-#include <asm/arch/memory.h>
-
-extern __inline__ unsigned long virt_to_phys(volatile void *x)
-{
- return __virt_to_phys((unsigned long)(x));
-}
-
-extern __inline__ void *phys_to_virt(unsigned long x)
-{
- return (void *)(__phys_to_virt((unsigned long)(x)));
-}
-
-/*
- * Virtual <-> DMA view memory address translations
- */
-#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x)))
-#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x))))
+#include <asm/memory.h>
/* the following macro is depreciated */
#define ioaddr(port) __ioaddr((port))
--- /dev/null
+/*
+ * linux/include/asm-arm/memory.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Note: this file should not be included by non-asm/.h files
+ *
+ * Modifications:
+ */
+#ifndef __ASM_ARM_MEMORY_H
+#define __ASM_ARM_MEMORY_H
+
+#include <asm/arch/memory.h>
+
+extern __inline__ unsigned long virt_to_phys(volatile void *x)
+{
+ return __virt_to_phys((unsigned long)(x));
+}
+
+extern __inline__ void *phys_to_virt(unsigned long x)
+{
+ return (void *)(__phys_to_virt((unsigned long)(x)));
+}
+
+/*
+ * Virtual <-> DMA view memory address translations
+ */
+#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x)))
+#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x))))
+
+#endif
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H
-extern const char xchg_str[];
-
-#include <linux/config.h>
#include <asm/proc-fns.h>
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
- extern void arm_invalidptr(const char *, int);
+ extern void __bad_xchg(volatile void *, int);
switch (size) {
case 1: return cpu_xchg_1(x, ptr);
- case 2: return cpu_xchg_2(x, ptr);
case 4: return cpu_xchg_4(x, ptr);
- default: arm_invalidptr(xchg_str, size);
+ default: __bad_xchg(ptr, size);
}
return 0;
}
: "memory"); \
} while (0)
-/* For spinlocks etc */
-#define local_irq_save(x) __save_flags_cli(x)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-#ifdef CONFIG_SMP
-#error SMP not supported
-#else
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_flags_cli(x) __save_flags_cli(x)
-
-#endif
-
#endif
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H
-#include <linux/config.h>
-
-extern const char xchg_str[];
-
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
- extern void arm_invalidptr(const char *, int);
+ extern void __bad_xchg(volatile void *, int);
switch (size) {
case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory");
break;
case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory");
break;
- default: arm_invalidptr(xchg_str, size);
+ default: __bad_xchg(ptr, size);
}
return x;
}
: "r" (x) \
: "memory")
-/* For spinlocks etc */
-#define local_irq_save(x) __save_flags_cli(x)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-#ifdef CONFIG_SMP
-#error SMP not supported
-#else
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_flags_cli(x) __save_flags_cli(x)
-
-#endif
-
#endif
#ifdef __KERNEL__
extern void show_regs(struct pt_regs *);
+
+#define predicate(x) (x & 0xf0000000)
+#define PREDICATE_ALWAYS 0xe0000000
+
#endif
#endif /* __ASSEMBLY__ */
#define tas(ptr) (xchg((ptr),1))
-extern void arm_malalignedptr(const char *, void *, volatile void *);
extern asmlinkage void __backtrace(void);
/*
#endif
+/* For spinlocks etc */
+#define local_irq_save(x) __save_flags_cli(x)
+#define local_irq_restore(x) __restore_flags(x)
+#define local_irq_disable() __cli()
+#define local_irq_enable() __sti()
+
+#ifdef CONFIG_SMP
+#error SMP not supported
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#define save_flags_cli(x) __save_flags_cli(x)
+
+#endif
+
#endif
#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
/* And dynamically-tunable limits and defaults: */
-extern int max_files, nr_files, nr_free_files;
+struct files_stat_struct {
+ int nr_files; /* read only */
+ int nr_free_files; /* read only */
+ int max_files; /* tunable */
+};
+extern struct files_stat_struct files_stat;
extern int max_super_blocks, nr_super_blocks;
#define NR_FILE 8192 /* this can well be larger on a larger system */
extern int notify_change(struct dentry *, struct iattr *);
extern int permission(struct inode *, int);
extern int get_write_access(struct inode *);
-extern void put_write_access(struct inode *);
+extern int deny_write_access(struct file *);
+static inline void put_write_access(struct inode * inode)
+{
+ atomic_dec(&inode->i_writecount);
+}
+static inline void allow_write_access(struct file *file)
+{
+ if (file)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
+}
extern int do_pipe(int *);
extern int open_namei(const char *, int, int, struct nameidata *);
/*
* Type of the last component on LOOKUP_PARENT
*/
-enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT };
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
/*
* "descriptor" for what we're up to with a read for sendfile().
extern int vfs_readdir(struct file *, filldir_t, void *);
extern int dcache_readdir(struct file *, void *, filldir_t);
+extern struct file_system_type *get_fs_type(const char *name);
extern struct super_block *get_super(kdev_t);
struct super_block *get_empty_super(void);
extern void put_super(kdev_t);
*
*/
-/*
- * We need to do a check-parent every time
- * after we have locked the parent - to verify
- * that the parent is still our parent and
- * that we are still hashed onto it..
- *
- * This is required in case two processes race
- * on removing (or moving) the same entry: the
- * parent lock will serialize them, but the
- * other process will be too late..
- */
-#define check_parent(dir, dentry) \
- ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
-
/*
* Locking the parent is needed to:
* - serialize directory operations
#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags)
#define PageDirty(page) test_bit(PG_dirty, &(page)->flags)
#define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags)
+#define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags)
#define PageLocked(page) test_bit(PG_locked, &(page)->flags)
#define LockPage(page) set_bit(PG_locked, &(page)->flags)
#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags)
atomic_t mnt_count;
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
- char *mnt_dirname; /* Name of directory mounted on */
struct list_head mnt_list;
uid_t mnt_owner;
};
unsigned char c_state, /* unused, inprog, done */
c_type, /* status, buffer */
c_secure : 1; /* req came from port < 1024 */
- struct in_addr c_client;
+ struct sockaddr_in c_addr;
u32 c_xid;
+ u32 c_prot;
u32 c_proc;
+ u32 c_vers;
unsigned long c_timestamp;
union {
struct svc_buf u_buffer;
void exp_nlmdetach(void);
-extern __inline__ int
-exp_checkaddr(struct svc_client *clp, struct in_addr addr)
-{
- struct in_addr *ap = clp->cl_addr;
- int i;
-
- for (i = clp->cl_naddr; i--; ap++)
- if (ap->s_addr == addr.s_addr)
- return 1;
- return 0;
-}
-
#endif /* __KERNEL__ */
#endif /* NFSD_EXPORT_H */
void nfsd_racache_shutdown(void);
int nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, int, struct svc_fh *);
-#ifdef CONFIG_NFSD_V3
-int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
-#endif /* CONFIG_NFSD_V3 */
int nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *);
int nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
int type, dev_t rdev, struct svc_fh *res);
#ifdef CONFIG_NFSD_V3
+int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
int nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
struct svc_fh *res, int createmode,
u32 *verifier);
+int nfsd_commit(struct svc_rqst *, struct svc_fh *,
+ off_t, unsigned long);
#endif /* CONFIG_NFSD_V3 */
int nfsd_open(struct svc_rqst *, struct svc_fh *, int,
int, struct file *);
u32 *buffer, int *countp, u32 *verf);
int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct statfs *);
-#ifdef CONFIG_NFSD_V3
-int nfsd_commit(struct svc_rqst *, struct svc_fh *,
- off_t, unsigned long);
-#endif /* CONFIG_NFSD_V3 */
+
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
};
struct knfsd_fh {
- int fh_size; /* significant for NFSv3.
+ unsigned int fh_size; /* significant for NFSv3.
* Points to the current size while building
* a new file handle
*/
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
int fh_maxsize; /* max size for fh_handle */
+
+ unsigned char fh_locked; /* inode locked by us */
+
#ifdef CONFIG_NFSD_V3
unsigned char fh_post_saved; /* post-op attrs saved */
unsigned char fh_pre_saved; /* pre-op attrs saved */
-#endif /* CONFIG_NFSD_V3 */
- unsigned char fh_locked; /* inode locked by us */
- unsigned char fh_dverified; /* dentry has been checked */
-#ifdef CONFIG_NFSD_V3
/* Pre-op attributes saved during fh_lock */
__u64 fh_pre_size; /* size before operation */
time_t fh_pre_mtime; /* mtime before oper */
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
- if (src->fh_dverified || src->fh_locked) {
+ if (src->fh_dentry || src->fh_locked) {
struct dentry *dentry = src->fh_dentry;
printk(KERN_ERR "fh_copy: copying %s/%s, already verified!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
fhp->fh_pre_size = inode->i_size;
fhp->fh_pre_saved = 1;
}
- fhp->fh_locked = 1;
}
/*
fhp->fh_post_mtime = inode->i_mtime;
fhp->fh_post_ctime = inode->i_ctime;
fhp->fh_post_saved = 1;
- fhp->fh_locked = 0;
}
+#else
+#define fill_pre_wcc(ignored)
+#define fill_post_wcc(notused)
#endif /* CONFIG_NFSD_V3 */
/*
* Lock a file handle/inode
+ * NOTE: both fh_lock and fh_unlock are done "by hand" in
+ * vfs.c:nfsd_rename as it needs to grab 2 i_sem's at once
+ * so, any changes here should be reflected there.
*/
static inline void
fh_lock(struct svc_fh *fhp)
dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n",
SVCFH_fmt(fhp), fhp->fh_locked);
- if (!fhp->fh_dverified) {
+ if (!fhp->fh_dentry) {
printk(KERN_ERR "fh_lock: fh not verified!\n");
return;
}
inode = dentry->d_inode;
down(&inode->i_sem);
-#ifdef CONFIG_NFSD_V3
fill_pre_wcc(fhp);
-#else
fhp->fh_locked = 1;
-#endif /* CONFIG_NFSD_V3 */
}
/*
static inline void
fh_unlock(struct svc_fh *fhp)
{
- if (!fhp->fh_dverified)
+ if (!fhp->fh_dentry)
printk(KERN_ERR "fh_unlock: fh not verified!\n");
if (fhp->fh_locked) {
-#ifdef CONFIG_NFSD_V3
fill_post_wcc(fhp);
up(&fhp->fh_dentry->d_inode->i_sem);
-#else
- struct dentry *dentry = fhp->fh_dentry;
- struct inode *inode = dentry->d_inode;
-
fhp->fh_locked = 0;
- up(&inode->i_sem);
-#endif /* CONFIG_NFSD_V3 */
}
}
#endif /* __KERNEL__ */
#define PCI_DEVICE_ID_SI_6205 0x0205
#define PCI_DEVICE_ID_SI_501 0x0406
#define PCI_DEVICE_ID_SI_496 0x0496
-#define PCI_DEVICE_ID_SI_300 0x0300
+#define PCI_DEVICE_ID_SI_300 0x0300
#define PCI_DEVICE_ID_SI_530 0x0530
-#define PCI_DEVICE_ID_SI_540 0x5300
+#define PCI_DEVICE_ID_SI_540 0x0540
#define PCI_DEVICE_ID_SI_601 0x0601
#define PCI_DEVICE_ID_SI_620 0x0620
-#define PCI_DEVICE_ID_SI_630 0x6300
+#define PCI_DEVICE_ID_SI_630 0x0630
#define PCI_DEVICE_ID_SI_5107 0x5107
+#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
#define PCI_DEVICE_ID_SI_5513 0x5513
#define PCI_DEVICE_ID_SI_5571 0x5571
#define PCI_DEVICE_ID_SI_5597 0x5597
#define PCI_DEVICE_ID_SI_5598 0x5598
#define PCI_DEVICE_ID_SI_5600 0x5600
+#define PCI_DEVICE_ID_SI_6300 0x6300
#define PCI_DEVICE_ID_SI_6306 0x6306
#define PCI_DEVICE_ID_SI_6326 0x6326
#define PCI_DEVICE_ID_SI_7001 0x7001
__u32 gid;
};
-/* Socket types. */
-
-#define SOCK_STREAM 1 /* stream (connection) socket */
-#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
-#define SOCK_RAW 3 /* raw socket */
-#define SOCK_RDM 4 /* reliably-delivered message */
-#define SOCK_SEQPACKET 5 /* sequential packet socket */
-#define SOCK_PACKET 10 /* linux specific way of */
- /* getting packets at the dev */
- /* level. For writing rarp and */
- /* other similar things on the */
- /* user level. */
-
/* Supported address families. */
#define AF_UNSPEC 0
#define AF_UNIX 1 /* Unix domain sockets */
extern struct vm_struct * get_vm_area (unsigned long size, unsigned long flags);
extern void vfree(void * addr);
-extern void * __vmalloc (unsigned long size, int gfp_mask);
+extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot);
extern long vread(char *buf, char *addr, unsigned long count);
extern void vmfree_area_pages(unsigned long address, unsigned long size);
-extern int vmalloc_area_pages(unsigned long address, unsigned long size , int gfp_mask);
+extern int vmalloc_area_pages(unsigned long address, unsigned long size,
+ int gfp_mask, pgprot_t prot);
extern struct vm_struct * vmlist;
static inline void * vmalloc (unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM);
+ return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
}
/*
static inline void * vmalloc_dma (unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL|GFP_DMA);
+ return __vmalloc(size, GFP_KERNEL|GFP_DMA, PAGE_KERNEL);
}
/*
static inline void * vmalloc_32(unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL);
+ return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
}
/*
return RETRY;
if (shp->id != zero_id) swap_attempts++;
- if (--counter < 0) /* failed */
+ if (--*counter < 0) /* failed */
return FAILED;
if (page_count(page_map) != 1)
return RETRY;
void __set_personality(unsigned long personality)
{
- struct exec_domain *it;
+ struct exec_domain *it, *prev;
it = lookup_exec_domain(personality);
- if (it) {
- if (atomic_read(¤t->fs->count) != 1) {
- struct fs_struct *new = copy_fs_struct(current->fs);
- struct fs_struct *old;
- if (!new) {
- put_exec_domain(it);
- return;
- }
- task_lock(current);
- old = current->fs;
- current->fs = new;
- task_unlock(current);
- put_fs_struct(old);
- }
- /*
- * At that point we are guaranteed to be the sole owner of
- * current->fs.
- */
+ if (it == current->exec_domain) {
current->personality = personality;
- current->exec_domain = it;
- set_fs_altroot();
- put_exec_domain(current->exec_domain);
+ return;
+ }
+ if (!it)
+ return;
+ if (atomic_read(¤t->fs->count) != 1) {
+ struct fs_struct *new = copy_fs_struct(current->fs);
+ struct fs_struct *old;
+ if (!new) {
+ put_exec_domain(it);
+ return;
+ }
+ task_lock(current);
+ old = current->fs;
+ current->fs = new;
+ task_unlock(current);
+ put_fs_struct(old);
}
+ /*
+ * At that point we are guaranteed to be the sole owner of
+ * current->fs.
+ */
+ current->personality = personality;
+ prev = current->exec_domain;
+ current->exec_domain = it;
+ set_fs_altroot();
+ put_exec_domain(prev);
}
asmlinkage long sys_personality(unsigned long personality)
/* filesystem internal functions */
EXPORT_SYMBOL(def_blk_fops);
EXPORT_SYMBOL(update_atime);
+EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(get_empty_super);
EXPORT_SYMBOL(getname);
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
-EXPORT_SYMBOL(put_write_access);
/* dynamic registering of consoles */
EXPORT_SYMBOL(register_console);
/* Initialize the module. */
mod->flags |= MOD_INITIALIZING;
atomic_set(&mod->uc.usecount,1);
- if (mod->init && mod->init() != 0) {
+ if (mod->init && (error = mod->init()) != 0) {
atomic_set(&mod->uc.usecount,0);
mod->flags &= ~MOD_INITIALIZING;
- error = -EBUSY;
+ if (error > 0) /* Buggy module */
+ error = -EBUSY;
goto err0;
}
atomic_dec(&mod->uc.usecount);
* The run-queue lock locks the parts that actually access
* and change the run-queues, and have to be interrupt-safe.
*/
-__cacheline_aligned spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; /* second */
-__cacheline_aligned rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; /* third */
+spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* second */
+rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* third */
static LIST_HEAD(runqueue_head);
0444, NULL, &proc_dointvec},
{FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
+ {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_MAXFILE, "file-max", &max_files, sizeof(int),
+ {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
0644, NULL, &proc_dointvec},
{FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
0444, NULL, &proc_dointvec},
* to it causing all sorts of fun problems ...
*/
remove_inode_page(page);
+ ClearPageDirty(page);
UnlockPage(page);
page_cache_release(page);
/*
* This adds a page to the page cache, starting out as locked,
- * owned by us, referenced, but not uptodate and with no errors.
+ * owned by us, but unreferenced, not uptodate and with no errors.
*/
static inline void __add_to_page_cache(struct page * page,
struct address_space *mapping, unsigned long offset,
if (PageLocked(page))
BUG();
- flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty));
- page->flags = flags | (1 << PG_locked) | (1 << PG_referenced);
+ flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ page->flags = flags | (1 << PG_locked);
page_cache_get(page);
page->index = offset;
add_page_to_inode_queue(mapping, page);
{
struct mm_struct * mm = current->mm;
struct vm_area_struct * vma;
+ int correct_wcount = 0;
int error;
if (file && (!file->f_op || !file->f_op->mmap))
goto free_vma;
if (file) {
- int correct_wcount = 0;
if (vma->vm_flags & VM_DENYWRITE) {
- if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
- error = -ETXTBSY;
+ error = deny_write_access(file);
+ if (error)
goto free_vma;
- }
- /* f_op->mmap might possibly sleep
- * (generic_file_mmap doesn't, but other code
- * might). In any case, this takes care of any
- * race that this might cause.
- */
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
correct_wcount = 1;
}
vma->vm_file = file;
get_file(file);
error = file->f_op->mmap(file, vma);
- /* Fix up the count if necessary, then check for an error */
- if (correct_wcount)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
if (error)
goto unmap_and_free_vma;
} else if (flags & MAP_SHARED) {
addr = vma->vm_start; /* can addr have changed?? */
vmlist_modify_lock(mm);
insert_vm_struct(mm, vma);
+ if (correct_wcount)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
merge_segments(mm, vma->vm_start, vma->vm_end);
vmlist_modify_unlock(mm);
return addr;
unmap_and_free_vma:
+ if (correct_wcount)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
vma->vm_file = NULL;
fput(file);
/* Undo any partial mapping done by a device driver. */
* so release them, and unmap the page range..
* If the one of the segments is only being partially unmapped,
* it will put new vm_area_struct(s) into the address space.
+ * In that case we have to be careful with VM_DENYWRITE.
*/
while ((mpnt = free) != NULL) {
unsigned long st, end, size;
+ struct file *file = NULL;
free = free->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->unmap)
mpnt->vm_ops->unmap(mpnt, st, size);
+ if (mpnt->vm_flags & VM_DENYWRITE &&
+ (st != mpnt->vm_start || end != mpnt->vm_end) &&
+ (file = mpnt->vm_file) != NULL) {
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ }
remove_shared_vm_struct(mpnt);
mm->map_count--;
* Fix the mapping, and free the old area if it wasn't reused.
*/
extra = unmap_fixup(mm, mpnt, st, size, extra);
+ if (file)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
}
/* Release the extra vma struct if it wasn't used */
BUG();
if (PageDecrAfter(page))
BUG();
+ if (PageDirty(page))
+ BUG();
zone = page->zone;
BUG();
if (page->mapping)
BUG();
- flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty));
- page->flags = flags | (1 << PG_referenced) | (1 << PG_uptodate);
+ flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ page->flags = flags | (1 << PG_uptodate);
add_to_page_cache_locked(page, &swapper_space, entry.val);
}
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- lock_kernel();
err = user_path_walk(specialfile, &nd);
if (err)
goto out;
+ lock_kernel();
prev = -1;
swap_list_lock();
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
err = 0;
out_dput:
+ unlock_kernel();
path_release(&nd);
out:
- unlock_kernel();
return err;
}
unsigned long maxpages;
int swapfilesize;
struct block_device *bdev = NULL;
- char *name;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
} else {
p->prio = --least_priority;
}
- name = getname(specialfile);
- error = PTR_ERR(name);
- if (IS_ERR(name))
- goto bad_swap_2;
- error = 0;
- if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
- error = path_walk(name, &nd);
- putname(name);
+ error = user_path_walk(specialfile, &nd);
if (error)
goto bad_swap_2;
}
static inline int alloc_area_pte (pte_t * pte, unsigned long address,
- unsigned long size, int gfp_mask)
+ unsigned long size, int gfp_mask, pgprot_t prot)
{
unsigned long end;
page = alloc_page(gfp_mask);
if (!page)
return -ENOMEM;
- set_pte(pte, mk_pte(page, PAGE_KERNEL));
+ set_pte(pte, mk_pte(page, prot));
address += PAGE_SIZE;
pte++;
} while (address < end);
return 0;
}
-static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask)
+static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot)
{
unsigned long end;
pte_t * pte = pte_alloc_kernel(pmd, address);
if (!pte)
return -ENOMEM;
- if (alloc_area_pte(pte, address, end - address, gfp_mask))
+ if (alloc_area_pte(pte, address, end - address, gfp_mask, prot))
return -ENOMEM;
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
return 0;
}
-inline int vmalloc_area_pages (unsigned long address,
- unsigned long size, int gfp_mask)
+inline int vmalloc_area_pages (unsigned long address, unsigned long size,
+ int gfp_mask, pgprot_t prot)
{
pgd_t * dir;
unsigned long end = address + size;
pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
- if (alloc_area_pmd(pmd, address, end - address, gfp_mask))
+ if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
return -ENOMEM;
if (pgd_val(olddir) != pgd_val(*dir))
set_pgdir(address, *dir);
printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
}
-void * __vmalloc (unsigned long size, int gfp_mask)
+void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot)
{
void * addr;
struct vm_struct *area;
return NULL;
}
addr = area->addr;
- if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask)) {
+ if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) {
vfree(addr);
BUG();
return NULL;
/* Needed by unix.o */
EXPORT_SYMBOL(scm_fp_dup);
-EXPORT_SYMBOL(max_files);
+EXPORT_SYMBOL(files_stat);
EXPORT_SYMBOL(memcpy_toiovec);
EXPORT_SYMBOL(csum_partial);
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
+#include <net/checksum.h>
#include <net/ip.h>
#include <asm/uaccess.h>
dprintk("svc: recvfrom returned error %d\n", -err);
}
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
+ unsigned int csum = skb->csum;
+ csum = csum_partial(skb->h.raw, skb->len, csum);
+ if ((unsigned short)csum_fold(csum)) {
+ skb_free_datagram(svsk->sk_sk, skb);
+ svc_sock_received(svsk, 0);
+ return 0;
+ }
+ }
+
/* There may be more data */
svsk->sk_data = 1;
{
struct sock *sk;
- if (atomic_read(&unix_nr_socks) >= 2*max_files)
+ if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files)
return NULL;
MOD_INC_USE_COUNT;