S: University of Limerick
S: Ireland
+N: Tigran A. Aivazian
+E: tigran@ocston.org
+W: http://www.ocston.org/~tigran
+D: BFS filesystem
+S: United Kingdom
+
N: Werner Almesberger
E: werner.almesberger@lrc.di.epfl.ch
D: dosfs, LILO, some fd features, various other hacks here and there
S: Germany
N: Stephen Rothwell
-E: Stephen.Rothwell@canb.auug.org.au
-W: http://www.canb.auug.org.au/~sfr
+E: sfr@linuxcare.com
+W: http://linuxcare.com.au/sfr
P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02
D: Boot/setup/build work for setup > 2K
D: Author, APM driver
compiled as a module, and so this could be dangerous. Most everyone
wants to say Y here.
+SCO UnixWare BFS Support
+CONFIG_BFS_FS
+ Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to
+ allow bootloader access the kernel image and other important files
+ during the boot process. It is usually mounted under /stand and
+ corresponds to the slice marked as "STAND" in the UnixWare
+ partition. This is useful if you want to access files on your /stand
+ slice from Linux. If you don't know what it is, say N.
+
+ If you want to compile this as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called bfs.o. Note that the filesystem of your root partition (the
+ one containing the directory /) cannot be compiled as a module.
+
ISO 9660 CDROM filesystem support
CONFIG_ISO9660_FS
This is the standard filesystem used on CDROMs. It was previously
lead to all sorts of problems.
You can safely say Y even if your machine doesn't have MTRRs, you'll
- just add about 3k to your kernel.
+ just add about 9K to your kernel.
See Documentation/mtrr.txt for more information.
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
APM compliant BIOSes. If you say Y here, the system time will be
- reset after a USER RESUME operation, the /proc/apm device will
- provide battery status information, and user-space programs will
- receive notification of APM "events" (e.g., battery status change).
+ reset after a RESUME operation, the /proc/apm device will provide
+ battery status information, and user-space programs will receive
+ notification of APM "events" (e.g. battery status change).
+
+ If you select "Y" here, you can disable actual use of the APM
+ BIOS by passing the "apm=off" option to the kernel at boot time.
+
+ Note that the APM support is almost completely disabled for
+ machines with more than one CPU.
Supporting software is available; for more information, read the
Battery Powered Linux mini-HOWTO, available from
This driver does not support the TI 4000M TravelMate and the ACER
486/DX4/75 because they don't have compliant BIOSes. Many "green"
desktop machines also don't have compliant BIOSes, and this driver
- will cause those machines to panic during the boot phase (typically,
- these machines are using a data segment of 0040, which is reserved
- for the Linux kernel).
+ may cause those machines to panic during the boot phase.
If you are running Linux on a laptop, you may also want to read the
Linux Laptop home page on the WWW at
- info and mount options for the Acorn Advanced Disc Filing System.
affs.txt
- info and mount options for the Amiga Fast File System.
+bfs.txt
+ - info for the SCO UnixWare Boot Filesystem (BFS).
coda.txt
- description of the CODA filesystem.
fat_cvf.txt
--- /dev/null
+The BFS filesystem is used on SCO UnixWare machines for /stand slice.
+There are no special mount options supported by bfs at this time.
+You can mount it only read-only at this stage. Even if you attempt to
+mount it read-write it will be automatically mounted read-only, unless
+you have enabled "BFS write support" when configuring the kernel.
+
+In order to access /stand partition under Linux you obviously need to
+know the partition number and the kernel must support UnixWare disk slices
+(CONFIG_UNIXWARE_DISKLABEL config option). However BFS support does not
+depend on having UnixWare disklabel support because one can also mount
+BFS filesystem via loopback:
+
+# losetup /dev/loop0 stand.img
+# mount -t bfs /dev/loop0 /mnt/stand
+
+where stand.img is a file containing the image of BFS filesystem.
+When you have finished using it and umounted you need to also deallocate
+/dev/loop0 device by:
+
+# losetup -d /dev/loop0
+
+You can simplify mounting by just typing:
+
+# mount -t bfs -o loop stand.img /mnt/stand
+
+this will allocate the first available loopback device (and load loop.o
+kernel module if necessary) automatically. Beware that umount will not
+deallocate /dev/loopN device if /etc/mtab file on your system is a
+symbolic link to /proc/mounts. You will need to do it manually using
+"-d" switch of losetup(8). Read losetup(8) manpage for more info.
+
+To create the BFS image under UnixWare you need to find out first which
+slice contains it. The command prtvtoc(1M) is your friend:
+
+# prtvtoc /dev/rdsk/c0b0t0d0s0
+
+(assuming your root disk is on target=0, lun=0, bus=0, controller=0). Then you
+look for the slice with tag "STAND", which is usually slice 10. With this
+information you can use dd(1) to create the BFS image:
+
+# umount /stand
+# dd if=/dev/rdsk/c0b0t0d0sa of=stand.img bs=512
+
+Just in case, you can verify that you have done the right thing by checking
+the magic number:
+
+# od -Ad -tx4 stand.img | more
+
+The first 4 bytes should be 0x1BADFACE.
+
+If you have any questions or suggestions regarding this BFS implementation
+please contact me:
+
+Tigran A. Aivazian <tigran@ocston.org>.
restrictions referred to are that the relevant option is valid if:
APIC APIC support is enabled.
- APM Automatic Power Management support is enabled.
+ APM Advanced Power Management support is enabled.
AX25 Appropriate AX.25 support is enabled.
CD Appropriate CD support is enabled.
EIDE EIDE/ATAPI support is enabled.
AM53C974= [HW,SCSI]
- apm= [APM] Automatic Power Management.
+ apm= [APM] Advanced Power Management.
arcrimi= [HW,NET]
APM DRIVER
P: Stephen Rothwell
-M: Stephen.Rothwell@canb.auug.org.au
+M: sfr@linuxcare.com
L: linux-laptop@vger.rutgers.edu
-S: Maintained
+W: http://linuxcare.com.au/apm/
+S: Supported
APPLETALK NETWORK LAYER
P: Jay Schulist
ARM PORT
P: Russell King
-M: linux@arm.uk.linux.org
+M: linux@arm.linux.org.uk
L: linux-arm@vger.rutgers.edu
-L: arm-linux@tardis.ed.ac.uk
-W: http://www.arm.uk.linux.org/~rmk/armlinux.html
+W: http://www.arm.linux.org.uk/~rmk/armlinux.html
S: Maintained
ARPD SUPPORT
W: http://ftp.bitgate.com/pcwd/
S: Maintained
+BFS FILE SYSTEM
+P: Tigran A. Aivazian
+M: tigran@ocston.org
+L: linux-kernel@vger.rutgers.edu
+W: http://www.ocston.org/~tigran/patches/bfs
+S: Maintained
+
BUSLOGIC SCSI DRIVER
P: Leonard N. Zubkoff
M: Leonard N. Zubkoff <lnz@dandelion.com>
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 24
+SUBLEVEL = 25
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
rm -f drivers/sound/bin2hex drivers/sound/hex2hex
rm -f net/khttpd/make_times_h
rm -f net/khttpd/times.h
- if [ -d modules ]; then \
- rm -f core `find modules/ -type f -print`; \
- fi
rm -f submenu*
+ rm -rf modules
mrproper: clean archmrproper
rm -f include/linux/autoconf.h include/linux/version.h
rm -f .hdepend scripts/mkdep scripts/split-include
rm -f $(TOPDIR)/include/linux/modversions.h
rm -rf $(TOPDIR)/include/linux/modules
- rm -rf modules
distclean: mrproper
rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
CPP := $(CC) -E
PERL := perl
-LINKFLAGS := -X -T arch/arm/vmlinux.lds
+LINKFLAGS := -p -X -T arch/arm/vmlinux.lds
ARCHCC := $(word 1,$(CC))
-
+AFLAGS += -mno-fpu
CFLAGS_PIPE := -pipe
CFLAGS := $(CFLAGS) $(CFLAGS_PIPE)
CFLAGS += -g
endif
+# Ensure this is ld "2.9.4" or later
+NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi)
+
+ifneq ($(NEW_LINKER),y)
+dummy:; @echo '*** 2.3 kernels no longer build correctly with old versions of binutils.'
+ @echo '*** Please upgrade your binutils to 2.9.5.'
+ @false
+endif
+
# GCC 2.7 uses different options to later compilers; sort out which we have
NEW_GCC := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi)
CFLAGS_SA110 := -m6
endif
-# See if this is ld "2.9.4" or later
-NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi)
-
-ifeq ($(NEW_LINKER),y)
-AFLAGS += -mno-fpu
-AFLAGS_PROC_CPU_26 := -mapcs-26
-AFLAGS_PROC_CPU_32v3 := -mapcs-32 -marmv3m
-AFLAGS_PROC_CPU_32v4 := -mapcs-32 -marmv4t
-LINKFLAGS := -p $(LINKFLAGS)
-else
-AFLAGS_PROC_CPU_26 := -m3
-AFLAGS_PROC_CPU_32v3 := -m6
-AFLAGS_PROC_CPU_32v4 := -m6
-endif
-
#
# Select CPU dependent flags
#
PROCESSOR = armo
TEXTADDR = 0x02080000
CFLAGS += $(CFLAGS_PROC_CPU_26)
- AFLAGS += $(AFLAGS_PROC_CPU_26)
+ AFLAGS += -mapcs-26
endif
ifeq ($(CONFIG_CPU_32),y)
TEXTADDR = 0xC0008000
ifeq ($(CONFIG_CPU_32v4),y)
CFLAGS += $(CFLAGS_PROC_CPU_32v4)
- AFLAGS += $(AFLAGS_PROC_CPU_32v4)
+ AFLAGS += -mapcs-32 -marmv4
else
CFLAGS += $(CFLAGS_PROC_CPU_32v3)
- AFLAGS += $(AFLAGS_PROC_CPU_32v3)
+ AFLAGS += -mapcs-32 -marmv3m
endif
#
# Exactly one of the following must be selected
DRIVERS += arch/arm/special/special.a
ifeq ($(CONFIG_NWFPE),y)
-CORE_FILES += arch/arm/nwfpe/math-emu.o
+LIBS := arch/arm/nwfpe/math-emu.o $(LIBS)
endif
ifeq ($(CONFIG_ARCH_ACORN),y)
# to date before starting compilation
CONSTANTS := constants
-constants: dummy
+constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy
@$(MAKE) -C arch/arm/lib constants.h
symlinks: archsymlinks
SYSTEM = $(TOPDIR)/vmlinux
CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC)
FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c
-ZLDFLAGS = -X -T vmlinux.lds
+ZLDFLAGS = -p -X -T vmlinux.lds
#
# Architecture dependencies
*/
reloc_start: add r8, r5, r0
#if 0
+ mov r0, #'\n'
+ bl putc
mov r0, r6
mov r1, #8
bl phex
bl phex
mov r0, #'\n'
bl putc
- mov r0, r4
- bl memdump
+ mov r0, r4
+ bl memdump
#endif
eor r0, r6, #0x44 << 24 @ SA-110?
eor r0, r0, #0x01 << 16
phexbuf: .space 12
+#if 0
+ .macro loadsp, rb
+ mov \rb, #0x7c000000
+ .endm
+
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8]
+ .endm
+#else
+ .macro loadsp, rb
+ mov \rb, #0x03000000
+ orr \rb, \rb, #0x00010000
+ .endm
+
+ .macro writeb, rb
+ strb \rb, [r3, #0x3f8 << 2]
+ .endm
+#endif
+
phex: adr r3, phexbuf
mov r2, #0
strb r2, [r3, r1]
strb r2, [r3, r1]
b 1b
-puts: mov r3, #0x7c000000
+puts: loadsp r3
1: ldrb r2, [r0], #1
teq r2, #0
moveq pc, lr
-2: strb r2, [r3, #0x3f8]
+2: writeb r2
mov r1, #0x00020000
3: subs r1, r1, #1
bne 3b
putc:
mov r2, r0
mov r0, #0
- mov r3, #0x7c000000
+ loadsp r3
b 2b
memdump: mov r12, r0
EBSA-110 CONFIG_ARCH_EBSA110 \
FootBridge-based CONFIG_FOOTBRIDGE" RiscPC
# SA1100-based CONFIG_ARCH_SA1100
+
if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE
if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then
if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
define_bool CONFIG_CPU_SA1100 y
choice 'SA1100 implementation' \
- "Brutus CONFIG_SA1100_BRUTUS \
- empeg CONFIG_SA1100_EMPEG \
- Itsy CONFIG_SA1100_ITSY \
- LART CONFIG_SA1100_LART \
- PLEB CONFIG_SA1100_PLEB \
- Victor CONFIG_SA1100_VICTOR \
- Tifon CONFIG_SA1100_TIFON" Brutus
+ "Brutus CONFIG_SA1100_BRUTUS \
+ Empeg CONFIG_SA1100_EMPEG \
+ Itsy CONFIG_SA1100_ITSY \
+ LART CONFIG_SA1100_LART \
+ PLEB CONFIG_SA1100_PLEB \
+ Victor CONFIG_SA1100_VICTOR \
+ Tifon CONFIG_SA1100_TIFON" Brutus
fi
#
define_bool CONFIG_ISA_DMA n
fi
-endmenu
-
if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP
fi
#include <asm/byteorder.h>
#include <asm/elf.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
#include <asm/proc-fns.h>
EXPORT_SYMBOL(system_rev);
EXPORT_SYMBOL(system_serial_low);
EXPORT_SYMBOL(system_serial_high);
-
+EXPORT_SYMBOL(__bug);
+EXPORT_SYMBOL(__readwrite_bug);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
#ifndef CONFIG_NO_PGT_CACHE
EXPORT_SYMBOL(quicklists);
#endif
-EXPORT_SYMBOL(__bad_pmd);
-EXPORT_SYMBOL(__bad_pmd_kernel);
+EXPORT_SYMBOL(__handle_bad_pmd);
+EXPORT_SYMBOL(__handle_bad_pmd_kernel);
/* string / mem functions */
EXPORT_SYMBOL_NOVERS(strcpy);
#include <asm/irq.h>
#include <asm/system.h>
-int have_isa_bridge;
+#include "bios32.h"
-int (*pci_irq_fixup)(struct pci_dev *dev);
+static int debug_pci;
+int have_isa_bridge;
-extern struct pci_ops *dc21285_init(int pass);
-extern void pcibios_fixup_ebsa285(struct pci_dev *dev);
extern void hw_init(void);
-void
-pcibios_report_device_errors(void)
+void pcibios_report_device_errors(void)
{
struct pci_dev *dev;
pci_read_config_word(dev, PCI_STATUS, &status);
- if (status & 0xf900) {
- pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
- printk(KERN_DEBUG "PCI: %02x:%02x status = %X\n",
- dev->bus->number, dev->devfn, status);
- }
+ if ((status & 0xf900) == 0)
+ continue;
+
+ pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
+ printk(KERN_DEBUG "PCI: status %04X on %s\n",
+ status, dev->name);
}
}
/*
- * We don't use this to fix the device, but more our initialisation.
+ * We don't use this to fix the device, but initialisation of it.
* It's not the correct use for this, but it works. The actions we
* take are:
* - enable only IO
pci_write_config_byte(dev, 0x81, 0x01);
}
-struct pci_fixup pcibios_fixups[] = {
- { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 },
- { 0 }
-};
-
-/*
- * Assign new address to PCI resource. We hope our resource information
- * is complete. On the PC, we don't re-assign resources unless we are
- * forced to do so.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-
-int __init pcibios_assign_resource(struct pci_dev *dev, int i)
+static void __init pci_fixup_unassign(struct pci_dev *dev)
{
- struct resource *r = &dev->resource[i];
- struct resource *pr = pci_find_parent_resource(dev, r);
- unsigned long size = r->end + 1;
- unsigned long flags = 0;
-
- if (!pr)
- return -EINVAL;
- if (r->flags & IORESOURCE_IO) {
- if (size > 0x100)
- return -EFBIG;
- if (allocate_resource(pr, r, size, 0x9000, ~0, 1024))
- return -EBUSY;
- flags = PCI_BASE_ADDRESS_SPACE_IO;
- } else {
- if (allocate_resource(pr, r, size, 0x00100000, 0x7fffffff, size))
- return -EBUSY;
- }
- if (i < 6)
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start | flags);
- return 0;
+ dev->resource[0].end -= dev->resource[0].start;
+ dev->resource[0].start = 0;
}
/*
- * Assign an address to an I/O range.
+ * PCI IDE controllers use non-standard I/O port
+ * decoding, respect it.
*/
-static void __init pcibios_fixup_io_addr(struct pci_dev *dev, struct resource *r, int idx)
+static void __init pci_fixup_ide_bases(struct pci_dev *dev)
{
- unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2);
- unsigned int size = r->end - r->start + 1;
- u32 try;
+ struct resource *r;
+ int i;
- /*
- * We need to avoid collisions with `mirrored' VGA ports and other strange
- * ISA hardware, so we always want the addresses kilobyte aligned.
- */
- if (!size || size > 256) {
- printk(KERN_ERR "PCI: Cannot assign I/O space to %s, "
- "%d bytes are too much.\n", dev->name, size);
+ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
- }
-
- if (allocate_resource(&ioport_resource, r, size, 0x9000, ~0, 1024)) {
- printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O "
- "space for %s.\n", size, dev->name);
- return;
- }
- printk("PCI: Assigning I/O space %04lx-%04lx to %s\n",
- r->start, r->end, dev->name);
-
- pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO);
- pci_read_config_dword(dev, reg, &try);
-
- if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) {
- r->start = 0;
- pci_write_config_dword(dev, reg, 0);
- printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try);
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ r = dev->resource + i;
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
}
}
+struct pci_fixup pcibios_fixups[] = {
+ {
+ PCI_FIXUP_HEADER,
+ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553,
+ pci_fixup_83c553
+ }, {
+ PCI_FIXUP_HEADER,
+ PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F,
+ pci_fixup_unassign
+ }, {
+ PCI_FIXUP_HEADER,
+ PCI_ANY_ID, PCI_ANY_ID,
+ pci_fixup_ide_bases
+ }, { 0 }
+};
+
/*
- * Assign an address to an memory range.
+ * Allocate resources for all PCI devices that have been enabled.
+ * We need to do that before we try to fix up anything.
*/
-static void __init pcibios_fixup_mem_addr(struct pci_dev *dev, struct resource *r, int idx)
+static void __init pcibios_claim_resources(void)
{
- unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2);
- unsigned int size = r->end - r->start + 1;
- u32 try;
-
- if (!size) {
- printk(KERN_ERR "PCI: Cannot assign memory space to %s, "
- "%d bytes are too much.\n", dev->name, size);
- return;
- }
-
- if (allocate_resource(&iomem_resource, r, size,
- 0x00100000, 0x0fffffff, 1024)) {
- printk(KERN_ERR "PCI: Unable to find free %d bytes of memory "
- "space for %s.\n", size, dev->name);
- return;
- }
-
- printk("PCI: Assigning memory space %08lx-%08lx to %s\n",
- r->start, r->end, dev->name);
-
- pci_write_config_dword(dev, reg, r->start);
- pci_read_config_dword(dev, reg, &try);
+ struct pci_dev *dev;
+ int idx;
- if (try != r->start) {
- r->start = 0;
- pci_write_config_dword(dev, reg, 0);
- printk(KERN_ERR "PCI: memory address setup failed, "
- "got %08x\n", try);
- }
+ for (dev = pci_devices; dev; dev = dev->next)
+ for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
+ if (dev->resource[idx].flags &&
+ dev->resource[idx].start)
+ pci_claim_resource(dev, idx);
}
-#define _PCI_REGION_IO 1
-#define _PCI_REGION_MEM 2
-
-/*
- * Fix up one PCI devices regions, enables and interrupt lines
- */
-static void __init pcibios_fixup_device(struct pci_dev *dev, u16 *cmd)
+void __init
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
{
- int i, has_regions = 0;
-
- /*
- * Fix up the regions. Any regions which aren't allocated
- * are given a free region.
- */
- for (i = 0; i < 6; i++) {
- struct resource *r = dev->resource + i;
+ unsigned long where, size;
+ u32 reg;
- if (r->flags & IORESOURCE_IO) {
- has_regions |= _PCI_REGION_IO;
+ if (debug_pci)
+ printk("PCI: Assigning %3s %08lx to %s\n",
+ res->flags & IORESOURCE_IO ? "IO" : "MEM",
+ res->start, dev->name);
- if (!r->start || r->end == 0xffffffff)
- pcibios_fixup_io_addr(dev, r, i);
- } else if (r->end) {
- has_regions |= _PCI_REGION_MEM;
+ where = PCI_BASE_ADDRESS_0 + resource * 4;
+ size = res->end - res->start;
- if (!r->start)
- pcibios_fixup_mem_addr(dev, r, i);
- }
- }
-
- switch (dev->class >> 8) {
- case PCI_CLASS_BRIDGE_ISA:
- case PCI_CLASS_BRIDGE_EISA:
- /*
- * If this device is an ISA bridge, set the have_isa_bridge
- * flag. We will then go looking for things like keyboard,
- * etc
- */
- have_isa_bridge = !0;
- /* FALL THROUGH */
-
- default:
- /*
- * Don't enable VGA-compatible cards since they have
- * fixed I/O and memory space.
- *
- * Don't enabled disabled IDE interfaces either because
- * some BIOSes may reallocate the same address when they
- * find that no devices are attached.
- */
- if (has_regions & _PCI_REGION_IO &&
- !((*cmd) & PCI_COMMAND_IO)) {
- printk("PCI: Enabling I/O for %s\n", dev->name);
- *cmd |= PCI_COMMAND_IO;
- }
+ pci_read_config_dword(dev, where, ®);
+ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
- if (has_regions & _PCI_REGION_MEM &&
- !((*cmd) & PCI_COMMAND_MEMORY)) {
- printk("PCI: Enabling memory for %s\n", dev->name);
- *cmd |= PCI_COMMAND_MEMORY;
- }
- }
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ if (debug_pci)
+ printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
/*
- * Fix base addresses, I/O and memory enables and IRQ's
+ * Called after each bus is probed, but before its children
+ * are examined.
*/
-static void __init pcibios_fixup_devices(void)
+void __init pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next) {
+ for (dev = bus->devices; dev; dev = dev->sibling) {
u16 cmd;
/*
- * architecture specific hacks.
- * I don't really want this here,
- * but I don't see any other place
- * for it to live.
+ * architecture specific hacks. I don't really want
+ * this here, but I don't see any other place for it
+ * to live. Shame the device doesn't support
+ * capabilities
*/
if (machine_is_netwinder() &&
dev->vendor == PCI_VENDOR_ID_DEC &&
/* Put the chip to sleep in case the driver isn't loaded */
pci_write_config_dword(dev, 0x40, 0x80000000);
+ /*
+ * If this device is an ISA bridge, set the have_isa_bridge
+ * flag. We will then go looking for things like keyboard,
+ * etc
+ */
+ if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA ||
+ dev->class >> 8 == PCI_CLASS_BRIDGE_EISA)
+ have_isa_bridge = !0;
+
/*
* Set latency timer to 32, and a cache line size to 32 bytes.
* Also, set system error enable, parity error enable, and
*/
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32);
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR |
PCI_COMMAND_PARITY;
- pcibios_fixup_device(dev, &cmd);
-
pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+ }
+}
- /*
- * now fixup the IRQs, if required
- */
- if (pci_irq_fixup)
- dev->irq = pci_irq_fixup(dev);
+static u8 __init no_swizzle(struct pci_dev *dev, u8 *pin)
+{
+ return 0;
+}
- /*
- * If any remaining IRQs are weird, fix it now.
- */
- if (dev->irq >= NR_IRQS)
- dev->irq = 0;
+/* ebsa285 host-specific stuff */
+static int irqmap_ebsa285[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
- /*
- * catch any drivers still reading this from the
- * device itself. This can be removed once
- * all drivers are fixed. (are there any?)
- */
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
+static u8 __init ebsa285_swizzle(struct pci_dev *dev, u8 *pin)
+{
+ return PCI_SLOT(dev->devfn);
}
-/*
- * Allocate resources for all PCI devices that have been enabled.
- * We need to do that before we try to fix up anything.
- */
-static void __init pcibios_claim_resources(void)
+static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- struct pci_dev *dev;
- int idx;
+ return irqmap_ebsa285[(slot + pin) & 3];
+}
- for (dev = pci_devices; dev; dev = dev->next)
- for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
- struct resource *a, *r = &dev->resource[idx];
-
- /*
- * Ignore regions that start at 0 or
- * end at 0xffffffff
- */
- if (!r->start || r->end == 0xffffffff)
- continue;
-
- if (r->flags & IORESOURCE_IO)
- a = &ioport_resource;
- else
- a = &iomem_resource;
-
- if (request_resource(a, r) < 0)
- printk(KERN_ERR "PCI: Address space collision "
- "on region %d of %s\n",
- idx, dev->name);
- /* We probably should disable the region,
- * shouldn't we?
- */
- }
+static struct hw_pci ebsa285_pci __initdata = {
+ dc21285_init,
+ 0x9000,
+ 0x00100000,
+ ebsa285_swizzle,
+ ebsa285_map_irq
+};
+
+/* cats host-specific stuff */
+static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
+
+static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (dev->irq >= 128)
+ return 16 + (dev->irq & 0x1f);
+
+ if (dev->irq >= 1 && dev->irq <= 4)
+ return irqmap_cats[dev->irq - 1];
+
+ if (dev->irq != 0)
+ printk("PCI: device %02x:%02x has unknown irq line %x\n",
+ dev->bus->number, dev->devfn, dev->irq);
+
+ return -1;
}
-/*
- * Called after each bus is probed, but before its children
- * are examined.
- *
- * No fixup of bus required
- */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+static struct hw_pci cats_pci __initdata = {
+ dc21285_init,
+ 0x9000,
+ 0x00100000,
+ no_swizzle,
+ cats_map_irq
+};
+
+/* netwinder host-specific stuff */
+static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
+#define DEV(v,d) ((v)<<16|(d))
+ switch (DEV(dev->vendor, dev->device)) {
+ case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
+ return IRQ_NETWINDER_ETHER100;
+
+ case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a):
+ return IRQ_NETWINDER_ETHER10;
+
+ case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553):
+ return 0;
+
+ case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105):
+ return IRQ_ISA_HARDDISK1;
+
+ case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000):
+ return IRQ_NETWINDER_VGA;
+
+ default:
+ printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n",
+ dev->bus->number, dev->devfn,
+ dev->vendor, dev->device);
+ return 0;
+ }
}
+static struct hw_pci netwinder_pci __initdata = {
+ dc21285_init,
+ 0x9000,
+ 0x00100000,
+ no_swizzle,
+ netwinder_map_irq
+};
+
void __init pcibios_init(void)
{
- struct pci_ops *ops;
+ struct hw_pci *hw_pci = NULL;
+
+ if (machine_is_ebsa285())
+ hw_pci = &ebsa285_pci;
+ else if (machine_is_cats())
+ hw_pci = &cats_pci;
+ else if (machine_is_netwinder())
+ hw_pci = &netwinder_pci;
+
+ if (hw_pci == NULL)
+ return;
/*
- * Pre-initialisation. Set up the host bridge.
+ * Set up the host bridge, and scan the bus.
*/
- ops = dc21285_init(0);
+ hw_pci->init();
- printk("PCI: Probing PCI hardware\n");
-
- pci_scan_bus(0, ops, NULL);
+ /*
+ * Other architectures don't seem to do this... should we?
+ */
pcibios_claim_resources();
- pcibios_fixup_devices();
/*
- * Now clear down any PCI error IRQs and
- * register the error handler
+ * Assign any unassigned resources. Note that we really ought to
+ * have min/max stuff here - max mem address is 0x0fffffff
*/
- dc21285_init(1);
+ pci_assign_unassigned_resources(hw_pci->io_start, hw_pci->mem_start);
+ pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq);
+ pci_set_bus_ranges();
/*
- * Initialise any other hardware after we've
- * got the PCI bus initialised. We may need
- * the PCI bus to talk to this other hardware.
+ * Initialise any other hardware after we've got the PCI bus
+ * initialised. We may need the PCI bus to talk to this other
+ * hardware.
*/
hw_init();
}
char * __init pcibios_setup(char *str)
{
+ if (!strcmp(str, "debug")) {
+ debug_pci = 1;
+ return NULL;
+ }
return str;
}
#include <asm/irq.h>
#include <asm/system.h>
+#include "bios32.h"
+
#define MAX_SLOTS 21
extern int setup_arm_irq(int, struct irqaction *);
extern void pcibios_report_device_errors(void);
-extern int (*pci_irq_fixup)(struct pci_dev *dev);
static unsigned long
dc21285_base_address(struct pci_dev *dev, int where)
dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL
};
-static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 };
-
-static int __init ebsa_irqval(struct pci_dev *dev)
-{
- u8 pin;
-
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-
- return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
-}
-
-static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
-
-static int __init cats_irqval(struct pci_dev *dev)
-{
- if (dev->irq >= 128)
- return 16 + (dev->irq & 0x1f);
-
- switch (dev->irq) {
- case 1 ... 4:
- return irqmap_cats[dev->irq - 1];
-
- default:
- printk("PCI: device %02x:%02x has unknown irq line %x\n",
- dev->bus->number, dev->devfn, dev->irq);
- case 0:
- break;
- }
- return 0;
-}
-
-static int __init netwinder_irqval(struct pci_dev *dev)
-{
-#define DEV(v,d) ((v)<<16|(d))
- switch (DEV(dev->vendor, dev->device)) {
- case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142):
- return IRQ_NETWINDER_ETHER100;
-
- case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a):
- return IRQ_NETWINDER_ETHER10;
-
- case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553):
- return 0;
-
- case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105):
- return IRQ_ISA_HARDDISK1;
-
- case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000):
- return IRQ_NETWINDER_VGA;
-
- default:
- printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n",
- dev->bus->number, dev->devfn,
- dev->vendor, dev->device);
- return 0;
- }
-}
-
-struct pci_ops * __init dc21285_init(int pass)
+void __init dc21285_init(void)
{
unsigned int mem_size;
unsigned long cntl;
- if (pass == 0) {
- mem_size = (unsigned int)high_memory - PAGE_OFFSET;
- *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000;
- *CSR_SDRAMBASEOFFSET = 0;
- *CSR_ROMBASEMASK = 0x80000000;
- *CSR_CSRBASEMASK = 0;
- *CSR_CSRBASEOFFSET = 0;
- *CSR_PCIADDR_EXTN = 0;
+ mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+ *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000;
+ *CSR_SDRAMBASEOFFSET = 0;
+ *CSR_ROMBASEMASK = 0x80000000;
+ *CSR_CSRBASEMASK = 0;
+ *CSR_CSRBASEOFFSET = 0;
+ *CSR_PCIADDR_EXTN = 0;
#ifdef CONFIG_HOST_FOOTBRIDGE
- /*
- * Map our SDRAM at a known address in PCI space, just in case
- * the firmware had other ideas. Using a nonzero base is
- * necessary, since some VGA cards forcefully use PCI addresses
- * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
- */
- *CSR_PCICACHELINESIZE = 0x00002008;
- *CSR_PCICSRBASE = 0;
- *CSR_PCICSRIOBASE = 0;
- *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
- *CSR_PCIROMBASE = 0;
- *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
- PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
- (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
+ /*
+ * Map our SDRAM at a known address in PCI space, just in case
+ * the firmware had other ideas. Using a nonzero base is
+ * necessary, since some VGA cards forcefully use PCI addresses
+ * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
+ */
+ *CSR_PCICACHELINESIZE = 0x00002008;
+ *CSR_PCICSRBASE = 0;
+ *CSR_PCICSRIOBASE = 0;
+ *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
+ *CSR_PCIROMBASE = 0;
+ *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
+ PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
+ (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
#endif
- printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n",
- *CSR_CLASSREV & 0xff);
-
- switch (machine_arch_type) {
- case MACH_TYPE_EBSA285:
- pci_irq_fixup = ebsa_irqval;
- break;
-
- case MACH_TYPE_CATS:
- pci_irq_fixup = cats_irqval;
- break;
-
- case MACH_TYPE_NETWINDER:
- pci_irq_fixup = netwinder_irqval;
- break;
- }
-
- return &dc21285_ops;
- } else {
- /*
- * Clear any existing errors - we aren't
- * interested in historical data...
- */
- cntl = *CSR_SA110_CNTL & 0xffffde07;
- *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
- cntl = *CSR_PCICMD & 0x0000ffff;
- *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
-
- /*
- * Initialise PCI error IRQ after we've finished probing
- */
- setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action);
-
- return NULL;
- }
+ printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n",
+ *CSR_CLASSREV & 0xff);
+
+ pci_scan_bus(0, &dc21285_ops, NULL);
+
+ /*
+ * Clear any existing errors - we aren't
+ * interested in historical data...
+ */
+ cntl = *CSR_SA110_CNTL & 0xffffde07;
+ *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
+ cntl = *CSR_PCICMD & 0x0000ffff;
+ *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
+
+ /*
+ * Initialise PCI error IRQ after we've finished probing
+ */
+ setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action);
}
return (count > cnt) ? cnt : count;
}
-static struct proc_dir_entry proc_ecard_devices = {
- PROC_BUS_ECARD_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- get_ecard_dev_info
-};
-
-static struct proc_dir_entry *proc_bus_ecard_dir;
+static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
static void ecard_proc_init(void)
{
proc_bus_ecard_dir = create_proc_entry("ecard", S_IFDIR, proc_bus);
- proc_register(proc_bus_ecard_dir, &proc_ecard_devices);
+ create_proc_info_entry("devices", 0, proc_bus_ecard_dir,
+ get_ecard_dev_info);
}
/*
#include <linux/blk.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#include <asm/elf.h>
#include <asm/hardware.h>
extern void reboot_setup(char *str, int *ints);
extern void disable_hlt(void);
-
-struct drive_info_struct { char dummy[32]; } drive_info;
-struct screen_info screen_info = {
- orig_video_lines: 30,
- orig_video_cols: 80,
- orig_video_mode: 0,
- orig_video_ega_bx: 0,
- orig_video_isVGA: 1,
- orig_video_points: 8
-};
-
extern int root_mountflags;
-extern int _text, _etext, _edata, _end;
-
-unsigned char aux_device_present;
- char elf_platform[ELF_PLATFORM_SIZE];
-unsigned int elf_hwcap;
+extern int _stext, _text, _etext, _edata, _end;
-/*
- * From head-armv.S
- */
unsigned int processor_id;
unsigned int __machine_arch_type;
unsigned int vram_size;
unsigned int system_rev;
unsigned int system_serial_low;
unsigned int system_serial_high;
-#ifdef MULTI_CPU
-struct processor processor;
-#endif
+unsigned int elf_hwcap;
+
#ifdef CONFIG_ARCH_ACORN
unsigned int memc_ctrl_reg;
unsigned int number_mfm_drives;
#endif
+struct meminfo meminfo;
+
+#ifdef MULTI_CPU
+struct processor processor;
+#endif
+
+struct drive_info_struct { char dummy[32]; } drive_info;
+
+struct screen_info screen_info = {
+ orig_video_lines: 30,
+ orig_video_cols: 80,
+ orig_video_mode: 0,
+ orig_video_ega_bx: 0,
+ orig_video_isVGA: 1,
+ orig_video_points: 8
+};
+
+unsigned char aux_device_present;
+char elf_platform[ELF_PLATFORM_SIZE];
+char saved_command_line[COMMAND_LINE_SIZE];
+
static struct proc_info_item proc_info;
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
-/*-------------------------------------------------------------------------
- * Early initialisation routines for various configurable items in the
- * kernel. Each one either supplies a setup_ function, or defines this
- * symbol to be empty if not configured.
+/*
+ * Standard memory resources
*/
+static struct resource mem_res[] = {
+ { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY },
+ { "Video RAM", 0, 0, IORESOURCE_MEM },
+ { "Kernel code", 0, 0, IORESOURCE_MEM },
+ { "Kernel data", 0, 0, IORESOURCE_MEM }
+};
+
+#define system_ram mem_res[0]
+#define video_ram mem_res[1]
+#define kernel_code mem_res[2]
+#define kernel_data mem_res[3]
+
+static struct resource io_res[] = {
+ { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
+ { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
+ { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
+};
+
+#define lp0 io_res[0]
+#define lp1 io_res[1]
+#define lp2 io_res[2]
static void __init setup_processor(void)
{
cpu_proc_init();
}
-static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
- char saved_command_line[COMMAND_LINE_SIZE];
+static unsigned long __init memparse(char *ptr, char **retptr)
+{
+ unsigned long ret = simple_strtoul(ptr, retptr, 0);
+
+ switch (**retptr) {
+ case 'M':
+ case 'm':
+ ret <<= 10;
+ case 'K':
+ case 'k':
+ ret <<= 10;
+ (*retptr)++;
+ default:
+ break;
+ }
+ return ret;
+}
+/*
+ * Initial parsing of the command line. We need to pick out the
+ * memory size. We look for mem=size@start, where start and size
+ * are "size[KkMm]"
+ */
static void __init
-setup_mem(char *cmd_line, unsigned long *mem_sz)
+parse_cmdline(char **cmdline_p, char *from)
{
char c = ' ', *to = command_line;
- int len = 0;
-
- if (!*mem_sz)
- *mem_sz = MEM_SIZE;
+ int usermem = 0, len = 0;
for (;;) {
- if (c == ' ') {
- if (cmd_line[0] == 'm' &&
- cmd_line[1] == 'e' &&
- cmd_line[2] == 'm' &&
- cmd_line[3] == '=') {
- *mem_sz = simple_strtoul(cmd_line+4, &cmd_line, 0);
- switch(*cmd_line) {
- case 'M':
- case 'm':
- *mem_sz <<= 10;
- case 'K':
- case 'k':
- *mem_sz <<= 10;
- cmd_line++;
- }
- }
- /* if there are two spaces, remove one */
- if (*cmd_line == ' ') {
- cmd_line++;
- continue;
+ if (c == ' ' && !memcmp(from, "mem=", 4)) {
+ unsigned long size, start;
+
+ if (to != command_line)
+ to -= 1;
+
+ /* If the user specifies memory size, we
+ * blow away any automatically generated
+ * size.
+ */
+ if (usermem == 0) {
+ usermem = 1;
+ meminfo.nr_banks = 0;
}
+
+ start = 0;
+ size = memparse(from + 4, &from);
+ if (*from == '@')
+ start = memparse(from + 1, &from);
+
+ meminfo.bank[meminfo.nr_banks].start = start;
+ meminfo.bank[meminfo.nr_banks].size = size;
+ meminfo.nr_banks += 1;
}
- c = *cmd_line++;
+ c = *from++;
if (!c)
break;
if (COMMAND_LINE_SIZE <= ++len)
break;
*to++ = c;
}
-
*to = '\0';
-
- /* remove trailing spaces */
- while (*--to == ' ' && to != command_line)
- *to = '\0';
+ *cmdline_p = command_line;
}
static void __init
static void __init setup_initrd(unsigned int start, unsigned int size)
{
#ifdef CONFIG_BLK_DEV_INITRD
- if (start) {
- initrd_start = start;
- initrd_end = start + size;
- } else {
- initrd_start = 0;
- initrd_end = 0;
- }
+ if (start == 0)
+ size = 0;
+ initrd_start = start;
+ initrd_end = start + size;
#endif
}
-static void __init check_initrd(unsigned long mem_end)
+/*
+ * Work out our memory regions. Note that "pfn" is the physical page number
+ * relative to the first physical page, not the physical address itself.
+ */
+static void __init setup_bootmem(void)
{
+ unsigned int end_pfn, bootmem_end;
+ int bank;
+
+ /*
+ * Calculate the end of memory.
+ */
+ for (bank = 0; bank < meminfo.nr_banks; bank++) {
+ if (meminfo.bank[bank].size) {
+ unsigned long end;
+
+ end = meminfo.bank[bank].start +
+ meminfo.bank[bank].size;
+ if (meminfo.end < end)
+ meminfo.end = end;
+ }
+ }
+
+ bootmem_end = __pa(PAGE_ALIGN((unsigned long)&_end));
+ end_pfn = meminfo.end >> PAGE_SHIFT;
+
+ /*
+ * Initialise the boot-time allocator
+ */
+ bootmem_end += init_bootmem(bootmem_end >> PAGE_SHIFT, end_pfn);
+
+ /*
+ * Register all available RAM with the bootmem allocator.
+ * The address is relative to the start of physical memory.
+ */
+ for (bank = 0; bank < meminfo.nr_banks; bank ++)
+ free_bootmem(meminfo.bank[bank].start, meminfo.bank[bank].size);
+
+ /*
+ * reserve the following regions:
+ * physical page 0 - it contains the exception vectors
+ * kernel and the bootmem structure
+ * swapper page directory (if any)
+ * initrd (if any)
+ */
+ reserve_bootmem(0, PAGE_SIZE);
+#ifdef CONFIG_CPU_32
+ reserve_bootmem(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(void *));
+#endif
+ reserve_bootmem(__pa(&_stext), bootmem_end - __pa(&_stext));
#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_end > mem_end) {
+ if (__pa(initrd_end) > (end_pfn << PAGE_SHIFT)) {
printk ("initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx) - disabling initrd\n",
- initrd_end, mem_end);
+ "(0x%08lx > 0x%08x) - disabling initrd\n",
+ __pa(initrd_end), end_pfn << PAGE_SHIFT);
initrd_start = 0;
}
+
+ if (initrd_start)
+ reserve_bootmem(__pa(initrd_start),
+ initrd_end - initrd_start);
#endif
}
-/*
- * Standard memory resources
- */
-static struct resource system_ram = { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY };
-static struct resource video_ram = { "Video RAM", 0, 0, IORESOURCE_MEM };
-static struct resource kernel_code = { "Kernel code", 0, 0, IORESOURCE_MEM };
-static struct resource kernel_data = { "Kernel data", 0, 0, IORESOURCE_MEM };
-static struct resource lpt1 = { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY };
-static struct resource lpt2 = { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY };
-static struct resource lpt3 = { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY };
-
-static void __init request_standard_resources(unsigned long end)
+static void __init request_standard_resources(void)
{
kernel_code.start = __virt_to_bus((unsigned long) &_text);
kernel_code.end = __virt_to_bus((unsigned long) &_etext - 1);
kernel_data.start = __virt_to_bus((unsigned long) &_etext);
kernel_data.end = __virt_to_bus((unsigned long) &_edata - 1);
system_ram.start = __virt_to_bus(PAGE_OFFSET);
- system_ram.end = __virt_to_bus(end - 1);
+ system_ram.end = __virt_to_bus(meminfo.end + PAGE_OFFSET - 1);
request_resource(&iomem_resource, &system_ram);
request_resource(&system_ram, &kernel_code);
request_resource(&system_ram, &kernel_data);
+
if (video_ram.start != video_ram.end)
request_resource(&iomem_resource, &video_ram);
*/
if (machine_is_ebsa110() || machine_is_riscpc() ||
machine_is_netwinder())
- request_resource(&ioport_resource, &lpt1);
+ request_resource(&ioport_resource, &lp0);
if (machine_is_riscpc())
- request_resource(&ioport_resource, &lpt2);
+ request_resource(&ioport_resource, &lp1);
if (machine_is_ebsa110() || machine_is_netwinder())
- request_resource(&ioport_resource, &lpt3);
+ request_resource(&ioport_resource, &lp2);
}
-void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
+void __init setup_arch(char **cmdline_p)
{
struct param_struct *params = (struct param_struct *)PARAMS_BASE;
- unsigned long memory_end = 0;
char *from = default_command_line;
#if defined(CONFIG_ARCH_ARC)
case MACH_TYPE_RISCPC:
/* RiscPC can't handle half-word loads and stores */
elf_hwcap &= ~HWCAP_HALF;
- {
- extern void init_dram_banks(struct param_struct *);
- init_dram_banks(params);
- }
switch (params->u1.s.pages_in_vram) {
case 512:
default:
break;
}
+ {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ meminfo.bank[i].start = i << 26;
+ meminfo.bank[i].size =
+ params->u1.s.pages_in_bank[i] *
+ params->u1.s.page_size;
+ }
+ meminfo.nr_banks = 4;
+ }
#endif
case MACH_TYPE_ARCHIMEDES:
case MACH_TYPE_A5K:
*/
reboot_setup("s", NULL);
params = NULL;
- ORIG_VIDEO_LINES = 25;
+ ORIG_VIDEO_LINES = 25;
ORIG_VIDEO_POINTS = 16;
ORIG_Y = 24;
video_ram.start = 0x0a0000;
}
if (params) {
- memory_end = PAGE_SIZE * params->u1.s.nr_pages;
+ if (meminfo.nr_banks == 0) {
+ meminfo.nr_banks = 1;
+ meminfo.bank[0].start = 0;
+ meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT;
+ }
ROOT_DEV = to_kdev_t(params->u1.s.rootdev);
system_rev = params->u1.s.system_rev;
system_serial_low = params->u1.s.system_serial_low;
from = params->commandline;
}
- /* Save unparsed command line copy for /proc/cmdline */
- memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
- saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-
- setup_mem(from, &memory_end);
-
- memory_end += PAGE_OFFSET;
+ if (meminfo.nr_banks == 0) {
+ meminfo.nr_banks = 1;
+ meminfo.bank[0].start = 0;
+ meminfo.bank[0].size = MEM_SIZE;
+ }
- *cmdline_p = command_line;
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
- *memory_start_p = (unsigned long) &_end;
- *memory_end_p = memory_end;
- request_standard_resources(memory_end);
- check_initrd(memory_end);
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+ parse_cmdline(cmdline_p, from);
+ setup_bootmem();
+ request_standard_resources();
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
/*
* Constant strings used in inlined functions in header files
*/
-/* proc/system.h */
-const char xchg_str[] = "xchg";
/*
* sys_pipe() is the normal C calling standard for creating
"UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
};
-static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
+/* proc/system.h */
+const char xchg_str[] = "xchg";
+
+static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
static inline void console_verbose(void)
{
}
#ifdef CONFIG_DEBUG_USER
- printk(KERN_ERR "[%d] %s: old system call.\n", current->pid,
- current->comm);
+ printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", current->pid,
+ current->comm, n);
#endif
force_sig(SIGILL, current);
+ die_if_kernel("Oops", regs, n);
}
asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
}
#endif
+void __bug(const char *file, int line, void *data)
+{
+ printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
+ if (data)
+ printk(KERN_CRIT"extra data = %p\n", data);
+ *(int *)0 = 0;
+}
+
+void __readwrite_bug(const char *fn)
+{
+ printk("%s called, but not implemented", fn);
+ *(int *)0 = 0;
+}
+
+void __pte_error(const char *file, int line, unsigned long val)
+{
+ printk("%s:%d: bad pte %08lx.\n", file, line, val);
+}
+
+void __pmd_error(const char *file, int line, unsigned long val)
+{
+ printk("%s:%d: bad pmd %08lx.\n", file, line, val);
+}
+
+void __pgd_error(const char *file, int line, unsigned long val)
+{
+ printk("%s:%d: bad pgd %08lx.\n", file, line, val);
+}
+
asmlinkage void __div0(void)
{
- printk("Awooga, division by zero in kernel.\n");
+ printk("Division by zero in kernel.\n");
__backtrace();
}
static unsigned long ai_word;
static unsigned long ai_multi;
+#ifdef CONFIG_SYSCTL
static int proc_alignment_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
return len;
}
-#ifdef CONFIG_SYSCTL
/*
* This needs to be done after sysctl_init, otherwise sys/
* will be overwritten.
*/
void __init alignment_init(void)
{
- struct proc_dir_entry *e;
-
- e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL);
-
- if (e)
- e->read_proc = proc_alignment_read;
+ create_proc_read_entry("sys/debug/alignment", 0, NULL,
+ proc_alignment_read);
}
__initcall(alignment_init);
-#endif
+#endif /* CONFIG_SYSCTL */
static int
do_alignment_exception(struct pt_regs *regs)
extern void die(char *msg, struct pt_regs *regs, unsigned int err);
-void __bad_pmd(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-}
-
-void __bad_pmd_kernel(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-}
-
/*
* This is useful to dump out the page tables associated with
* 'addr' in mm 'mm'.
/*
* linux/arch/arm/mm/init.c
*
- * Copyright (C) 1995-1999 Russell King
+ * Copyright (C) 1995-1999 Russell King
*/
#include <linux/config.h>
#include <linux/swapctl.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h>
#endif
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/hardware.h>
+#include <asm/setup.h>
#include "map.h"
+static unsigned long totalram_pages;
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-#ifndef CONFIG_NO_PGT_CACHE
-struct pgtable_cache_struct quicklists;
-#endif
-extern unsigned long free_area_init(unsigned long, unsigned long);
extern void show_net_buffers(void);
-extern char _etext, _text, _edata, __bss_start, _end;
-extern char __init_begin, __init_end;
-
-int do_check_pgt_cache(int low, int high)
-{
- int freed = 0;
-#ifndef CONFIG_NO_PGT_CACHE
- if(pgtable_cache_size > high) {
- do {
- if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
- if(pmd_quicklist)
- free_pmd_slow(get_pmd_fast()), freed++;
- if(pte_quicklist)
- free_pte_slow(get_pte_fast()), freed++;
- } while(pgtable_cache_size > low);
- }
-#endif
- return freed;
-}
-
/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
+ * empty_bad_page is the page that is used for page faults when
+ * linux is out-of-memory. Older versions of linux just did a
* do_exit(), but using this instead means there is less risk
* for a process dying in kernel mode, possibly leaving a inode
* unused etc..
*
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
+ * empty_bad_pte_table is the accompanying page-table: it is
+ * initialized to point to BAD_PAGE entries.
*
- * ZERO_PAGE is a special page that is used for zero-initialized
- * data and COW.
+ * empty_zero_page is a special page that is used for
+ * zero-initialized data and COW.
*/
-pte_t *empty_bad_page_table;
+struct page *empty_zero_page;
+struct page *empty_bad_page;
+pte_t *empty_bad_pte_table;
-pte_t *__bad_pagetable(void)
+pte_t *get_bad_pte_table(void)
{
- pte_t bad_page;
+ pte_t v;
int i;
- bad_page = BAD_PAGE;
+ v = pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+
for (i = 0; i < PTRS_PER_PTE; i++)
- set_pte(empty_bad_page_table + i, bad_page);
+ set_pte(empty_bad_pte_table + i, v);
+
+ return empty_bad_pte_table;
+}
+
+void __handle_bad_pmd(pmd_t *pmd)
+{
+ pmd_ERROR(*pmd);
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
+}
- return empty_bad_page_table;
+void __handle_bad_pmd_kernel(pmd_t *pmd)
+{
+ pmd_ERROR(*pmd);
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table()));
}
-unsigned long *empty_zero_page;
-unsigned long *empty_bad_page;
+#ifndef CONFIG_NO_PGT_CACHE
+struct pgtable_cache_struct quicklists;
+
+int do_check_pgt_cache(int low, int high)
+{
+ int freed = 0;
-pte_t __bad_page(void)
+ if(pgtable_cache_size > high) {
+ do {
+ if(pgd_quicklist) {
+ free_pgd_slow(get_pgd_fast());
+ freed++;
+ }
+ if(pmd_quicklist) {
+ free_pmd_slow(get_pmd_fast());
+ freed++;
+ }
+ if(pte_quicklist) {
+ free_pte_slow(get_pte_fast());
+ freed++;
+ }
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
+}
+#else
+int do_check_pgt_cache(int low, int high)
{
- memzero (empty_bad_page, PAGE_SIZE);
- return pte_nocache(pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)));
+ return 0;
}
+#endif
void show_mem(void)
{
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
+
+ page = mem_map;
+ end = mem_map + max_mapnr;
+
+ do {
if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
page = page->next_hash;
+ if (page == NULL)
+ break;
}
total++;
if (PageReserved(page))
reserved++;
else if (PageSwapCache(page))
cached++;
- else if (!atomic_read(&page->count))
+ else if (!page_count(page))
free++;
else
shared += atomic_read(&page->count) - 1;
- }
+ page++;
+ } while (page < end);
+
printk("%d pages of RAM\n", total);
printk("%d free pages\n", free);
printk("%d reserved pages\n", reserved);
/*
* paging_init() sets up the page tables...
*/
-unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem)
+void __init paging_init(void)
{
- start_mem = PAGE_ALIGN(start_mem);
-
- empty_zero_page = (unsigned long *)start_mem;
- memzero(empty_zero_page, PAGE_SIZE);
- start_mem += PAGE_SIZE;
-
- empty_bad_page = (unsigned long *)start_mem;
- start_mem += PAGE_SIZE;
+ void *zero_page, *bad_page, *bad_table;
#ifdef CONFIG_CPU_32
- start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
+#define TABLE_OFFSET (PTRS_PER_PTE)
+#else
+#define TABLE_OFFSET 0
#endif
- empty_bad_page_table = (pte_t *)start_mem;
- start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
-
- start_mem = setup_page_tables(start_mem, end_mem);
-
+#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
+
+ /*
+ * allocate what we need for the bad pages
+ */
+ zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
+ bad_page = alloc_bootmem_low_pages(PAGE_SIZE);
+ bad_table = alloc_bootmem_low_pages(TABLE_SIZE);
+
+ /*
+ * initialise the page tables
+ */
+ pagetable_init();
flush_tlb_all();
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
+ free_area_init(max_low_pfn);
+
+ /*
+ * finish off the bad pages once
+ * the mem_map is initialised
+ */
+ memzero(zero_page, PAGE_SIZE);
+ memzero(bad_page, PAGE_SIZE);
- return free_area_init(start_mem, end_mem);
+ empty_zero_page = mem_map + MAP_NR(zero_page);
+ empty_bad_page = mem_map + MAP_NR(bad_page);
+ empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET;
}
static inline void free_unused_mem_map(void)
high = ((unsigned long)page->next_hash) & PAGE_MASK;
while (low < high) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(low)].flags);
+ ClearPageReserved(mem_map + MAP_NR(low));
low += PAGE_SIZE;
}
}
* memory is free. This is done after various parts of the system have
* claimed their memory after the kernel image.
*/
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+void __init mem_init(void)
{
int codepages = 0;
int reservedpages = 0;
int datapages = 0;
int initpages = 0, i, min_nr;
- unsigned long tmp;
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
- max_mapnr = MAP_NR(end_mem);
- num_physpages = 0;
-
- /* setup address validity bitmap */
- start_mem = create_mem_holes(start_mem, end_mem);
-
- start_mem = PAGE_ALIGN(start_mem);
-
- /* mark usable pages in the mem_map[] */
- mark_usable_memory_areas(start_mem, end_mem);
-
- /* free unused mem_map[] entries */
- free_unused_mem_map();
+ max_mapnr = max_low_pfn;
+ high_memory = (void *)__va(max_low_pfn * PAGE_SIZE);
-#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
- (w) < (unsigned long)(max))
-
- for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
- if (PageSkip(mem_map+MAP_NR(tmp))) {
- unsigned long next;
-
- next = mem_map[MAP_NR(tmp)].next_hash - mem_map;
-
- next = (next << PAGE_SHIFT) + PAGE_OFFSET;
-
- if (next < tmp || next >= end_mem)
- break;
- tmp = next;
- }
- num_physpages++;
- if (PageReserved(mem_map+MAP_NR(tmp))) {
- if (BETWEEN(tmp, &__init_begin, &__init_end))
- initpages++;
- else if (BETWEEN(tmp, &_text, &_etext))
- codepages++;
- else if (BETWEEN(tmp, &_etext, &_edata))
- datapages++;
- else if (BETWEEN(tmp, &__bss_start, start_mem))
- datapages++;
- else
- reservedpages++;
- continue;
- }
- atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
-#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end))
+#ifdef CONFIG_CPU_32
+ /*
+ * We may have non-contiguous memory. Setup the PageSkip stuff,
+ * and mark the areas of mem_map which can be freed
+ */
+ if (meminfo.nr_banks != 1)
+ create_memmap_holes();
#endif
- free_page(tmp);
- }
-#undef BETWEEN
+ /* this will put all unused low memory onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+ /*
+ * Since our memory may not be contiguous, calculate the
+ * real number of pages we have in this system
+ */
+ num_physpages = 0;
+ for (i = 0; i < meminfo.nr_banks; i++)
+ num_physpages += meminfo.bank[i].size >> PAGE_SHIFT;
printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10));
+ /*
+ * Correct freepages watermarks
+ */
i = nr_free_pages >> 7;
if (PAGE_SIZE < 32768)
min_nr = 10;
#endif
}
-static void free_area(unsigned long addr, unsigned long end, char *s)
+static inline void free_area(unsigned long addr, unsigned long end, char *s)
{
unsigned int size = (end - addr) >> 10;
+ struct page *page = mem_map + MAP_NR(addr);
- for (; addr < end; addr += PAGE_SIZE) {
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ for (; addr < end; addr += PAGE_SIZE, page ++) {
+ ClearPageReserved(page);
+ set_page_count(page, 1);
free_page(addr);
+ totalram_pages++;
}
if (size)
printk(" %dk %s", size, s);
}
-void free_initmem (void)
+void free_initmem(void)
{
+ extern char __init_begin, __init_end;
+
printk("Freeing unused kernel memory:");
free_area((unsigned long)(&__init_begin),
void si_meminfo(struct sysinfo *val)
{
- struct page *page, *end;
-
- val->totalram = 0;
+ val->totalram = totalram_pages;
val->sharedram = 0;
- val->freeram = nr_free_pages << PAGE_SHIFT;
- val->bufferram = atomic_read(&buffermem);
- for (page = mem_map, end = mem_map + max_mapnr;
- page < end; page++) {
- if (PageSkip(page)) {
- if (page->next_hash < page)
- break;
- page = page->next_hash;
- }
- if (PageReserved(page))
- continue;
- val->totalram++;
- if (!atomic_read(&page->count))
- continue;
- val->sharedram += atomic_read(&page->count) - 1;
- }
- val->totalram <<= PAGE_SHIFT;
- val->sharedram <<= PAGE_SHIFT;
- val->totalbig = 0;
- val->freebig = 0;
+ val->freeram = nr_free_pages;
+ val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = 0;
+ val->freehigh = 0;
+ val->mem_unit = PAGE_SIZE;
}
bufferable:1;
};
-struct mem_desc {
- unsigned long virt_start;
- unsigned long virt_end;
-};
-
extern struct map_desc io_desc[];
extern unsigned int io_desc_size;
-extern struct mem_desc mem_desc[];
-extern unsigned int mem_desc_size;
-extern void mark_usable_memory_areas(unsigned long start, unsigned long end);
-extern unsigned long create_mem_holes(unsigned long start, unsigned long end);
-extern unsigned long setup_page_tables(unsigned long start, unsigned long end);
+extern void create_memmap_holes(void);
+extern void pagetable_init(void);
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#define MEMC_TABLE_SIZE (256*sizeof(unsigned long))
#define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR)
-/*
- * FIXME: the following over-allocates by 6400%
- */
-static inline void *alloc_table(int size, int prio)
-{
- if (size != 128)
- printk("invalid table size\n");
- return (void *)get_page_8k(prio);
-}
+int page_nr;
+
+extern unsigned long get_page_2k(int prio);
+extern void free_page_2k(unsigned long);
+extern pte_t *get_bad_pte_table(void);
/*
* Allocate a page table. Note that we place the MEMC
* table before the page directory. This means we can
* easily get to both tightly-associated data structures
- * with a single pointer. This function is slightly
- * better - it over-allocates by only 711%
+ * with a single pointer.
+ *
+ * We actually only need 1152 bytes, 896 bytes is wasted.
+ * We could try to fit 7 PTEs into that slot somehow.
*/
static inline void *alloc_pgd_table(int priority)
{
- unsigned long pg8k;
+ unsigned long pg2k;
- pg8k = get_page_8k(priority);
- if (pg8k)
- pg8k += MEMC_TABLE_SIZE;
+ pg2k = get_page_2k(priority);
+ if (pg2k)
+ pg2k += MEMC_TABLE_SIZE;
- return (void *)pg8k;
+ return (void *)pg2k;
}
-void free_table(void *table)
+void free_pgd_slow(pgd_t *pgd)
{
- unsigned long tbl = (unsigned long)table;
+ unsigned long tbl = (unsigned long)pgd;
+
+ tbl -= MEMC_TABLE_SIZE;
+ free_page_2k(tbl);
+}
- tbl &= ~8191;
- free_page_8k(tbl);
+/*
+ * FIXME: the following over-allocates by 1600%
+ */
+static inline void *alloc_pte_table(int size, int prio)
+{
+ if (size != 128)
+ printk("invalid table size\n");
+ return (void *)get_page_2k(prio);
+}
+
+void free_pte_slow(pte_t *pte)
+{
+ unsigned long tbl = (unsigned long)pte;
+ free_page_2k(tbl);
}
pgd_t *get_pgd_slow(void)
if (pgd) {
pgd_t *init = pgd_offset(&init_mm, 0);
- memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t));
memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
/*
* On ARM, first page must always be allocated
nomem_pmd:
pmd_free(new_pmd);
nomem:
- free_table(pgd);
+ free_pgd_slow(pgd);
return NULL;
}
{
pte_t *pte;
- pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+ pte = (pte_t *)alloc_pte_table(PTRS_PER_PTE * sizeof(pte_t), GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
- set_pmd(pmd, mk_pmd(pte));
+ memzero(pte, PTRS_PER_PTE * sizeof(pte_t));
+ set_pmd(pmd, mk_user_pmd(pte));
return pte + offset;
}
- set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+ set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
return NULL;
}
- free_table((void *)pte);
+ free_pte_slow(pte);
if (pmd_bad(*pmd)) {
- __bad_pmd(pmd);
+ __handle_bad_pmd(pmd);
return NULL;
}
return (pte_t *) pmd_page(*pmd) + offset;
* some more work to get it to fit into our separate processor and
* architecture structure.
*/
-int page_nr;
-
-#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
-
-static inline void setup_swapper_dir (int index, pte_t *ptep)
+void __init pagetable_init(void)
{
- set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep));
-}
-
-unsigned long __init
-setup_page_tables(unsigned long start_mem, unsigned long end_mem)
-{
- unsigned int i;
- union { unsigned long l; pte_t *pte; } u;
+ pte_t *pte;
+ int i;
- page_nr = MAP_NR(end_mem);
+ page_nr = max_low_pfn;
- /* map in pages for (0x0000 - 0x8000) */
- u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1));
- start_mem = u.l + PTE_SIZE;
- memzero (u.pte, PTE_SIZE);
- u.pte[0] = mk_pte(PAGE_OFFSET + 491520, PAGE_READONLY);
- setup_swapper_dir (0, u.pte);
+ pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t));
+ memzero(pte, PTRS_PER_PTE * sizeof(pte_t));
+ pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY);
+ set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte));
for (i = 1; i < PTRS_PER_PGD; i++)
pgd_val(swapper_pg_dir[i]) = 0;
-
- return start_mem;
}
-unsigned long __init
-create_mem_holes(unsigned long start, unsigned long end)
+void __init create_memmap_holes(void)
{
- return start;
-}
-
-void __init
-mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem)
-{
- while (start_mem < end_mem) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
- start_mem += PAGE_SIZE;
- }
}
/*
- * arch/arm/mm/mm-armv.c
+ * linux/arch/arm/mm/mm-armv.c
*
- * Page table sludge for ARM v3 and v4 processor architectures.
+ * Page table sludge for ARM v3 and v4 processor architectures.
*
- * Copyright (C) 1998-1999 Russell King
+ * Copyright (C) 1998-1999 Russell King
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/io.h>
+#include <asm/setup.h>
#include "map.h"
unsigned long *valid_addr_bitmap;
+extern unsigned long get_page_2k(int priority);
+extern void free_page_2k(unsigned long page);
+extern pte_t *get_bad_pte_table(void);
+
/*
* need to get a 16k page for level 1
*/
pmd_t *new_pmd;
if (pgd) {
- pgd_t *init = pgd_offset(&init_mm, 0);
+ pgd_t *init = pgd_offset_k(0);
- memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t));
memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
- clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR);
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t));
/*
* On ARM, first page must always be allocated
pte_t *new_pte = pte_offset(new_pmd, 0);
pte_t *old_pte = pte_offset(old_pmd, 0);
- set_pte (new_pte, *old_pte);
+ set_pte(new_pte, *old_pte);
}
}
}
return NULL;
}
+void free_pgd_slow(pgd_t *pgd)
+{
+ if (pgd) { /* can pgd be NULL? */
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /* pgd is always present and good */
+ pmd = (pmd_t *)pgd;
+ if (pmd_none(*pmd))
+ goto free;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ goto free;
+ }
+
+ pte = pte_offset(pmd, 0);
+ pmd_clear(pmd);
+ pte_free(pte);
+ pmd_free(pmd);
+ }
+free:
+ free_pages((unsigned long) pgd, 2);
+}
+
pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
pte = (pte_t *)get_page_2k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
- clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t));
+ clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
pte += PTRS_PER_PTE;
set_pmd(pmd, mk_user_pmd(pte));
return pte + offset;
}
- set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+ set_pmd(pmd, mk_user_pmd(get_bad_pte_table()));
return NULL;
}
free_page_2k((unsigned long)pte);
if (pmd_bad(*pmd)) {
- __bad_pmd(pmd);
+ __handle_bad_pmd(pmd);
return NULL;
}
return (pte_t *) pmd_page(*pmd) + offset;
pte = (pte_t *)get_page_2k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
- clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t));
+ clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
pte += PTRS_PER_PTE;
set_pmd(pmd, mk_kernel_pmd(pte));
return pte + offset;
}
- set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+ set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table()));
return NULL;
}
free_page_2k((unsigned long)pte);
if (pmd_bad(*pmd)) {
- __bad_pmd_kernel(pmd);
+ __handle_bad_pmd_kernel(pmd);
return NULL;
}
return (pte_t *) pmd_page(*pmd) + offset;
}
+void free_pte_slow(pte_t *pte)
+{
+ free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
+}
+
/*
* Create a SECTION PGD between VIRT and PHYS in domain
* DOMAIN with protection PROT
* the hardware pte table.
*/
static inline void
-alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
+alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot)
{
pmd_t *pmdp;
pte_t *ptep;
pmdp = pmd_offset(pgd_offset_k(virt), virt);
-#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
-
if (pmd_none(*pmdp)) {
- unsigned long memory = *mem;
-
- memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1);
+ pte_t *ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
+ sizeof(pte_t));
- ptep = (pte_t *)memory;
- memzero(ptep, PTE_SIZE);
- memory += PTE_SIZE;
-
- ptep = (pte_t *)memory;
- memzero(ptep, PTE_SIZE);
+ memzero(ptep, 2 * PTRS_PER_PTE * sizeof(pte_t));
+ ptep += PTRS_PER_PTE;
set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
-
- *mem = memory + PTE_SIZE;
}
-
-#undef PTE_SIZE
-
ptep = pte_offset(pmdp, virt);
set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
* the clearance is done by the middle-level functions (pmd)
* rather than the top-level (pgd) functions.
*/
-static inline void
-free_init_section(unsigned long virt)
+static inline void free_init_section(unsigned long virt)
{
pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
}
* are able to cope here with varying sizes and address
* offsets, and we take full advantage of sections.
*/
-static void __init
-create_mapping(unsigned long *mem_ptr, struct map_desc *md)
+static void __init create_mapping(struct map_desc *md)
{
unsigned long virt, length;
int prot_sect, prot_pte;
length = md->length;
while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) {
- alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte);
+ alloc_init_page(virt, virt + off, md->domain, prot_pte);
virt += PAGE_SIZE;
length -= PAGE_SIZE;
}
while (length >= PAGE_SIZE) {
- alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte);
+ alloc_init_page(virt, virt + off, md->domain, prot_pte);
virt += PAGE_SIZE;
length -= PAGE_SIZE;
}
/*
- * Initial boot-time mapping. This covers just the
- * zero page, kernel and the flush area. NB: it
- * must be sorted by virtual address, and no
+ * Initial boot-time mapping. This covers just the zero page, kernel and
+ * the flush area. NB: it must be sorted by virtual address, and no
* virtual address overlaps.
- * init_map[2..4] are for architectures with small
- * amounts of banked memory.
+ * init_map[2..4] are for architectures with banked memory.
*/
static struct map_desc init_map[] __initdata = {
{ 0, 0, PAGE_SIZE, DOMAIN_USER, 0, 0, 1, 0 }, /* zero page */
{ 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* kernel memory */
- { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 },
+ { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* (4 banks) */
{ 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 },
{ 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 },
{ 0, 0, PGDIR_SIZE, DOMAIN_KERNEL, 1, 0, 1, 1 }, /* cache flush 1 */
#define NR_INIT_MAPS (sizeof(init_map) / sizeof(init_map[0]))
-unsigned long __init
-setup_page_tables(unsigned long start_mem, unsigned long end_mem)
+void __init pagetable_init(void)
{
unsigned long address = 0;
- int idx = 0;
+ int i;
/*
- * Correct the above mappings
+ * Setup the above mappings
*/
- init_map[0].physical =
- init_map[1].physical = __virt_to_phys(PAGE_OFFSET);
- init_map[1].virtual = PAGE_OFFSET;
- init_map[1].length = end_mem - PAGE_OFFSET;
+ init_map[0].physical = PHYS_OFFSET;
init_map[5].physical = FLUSH_BASE_PHYS;
init_map[5].virtual = FLUSH_BASE;
#ifdef FLUSH_BASE_MINICACHE
init_map[6].length = PGDIR_SIZE;
#endif
+ for (i = 0; i < meminfo.nr_banks; i++) {
+ init_map[i+1].physical = PHYS_OFFSET + meminfo.bank[i].start;
+ init_map[i+1].virtual = PAGE_OFFSET + meminfo.bank[i].start;
+ init_map[i+1].length = meminfo.bank[i].size;
+ }
+
/*
- * Firstly, go through the initial mappings,
- * but clear out any pgdir entries that are
- * not in the description.
+ * Go through the initial mappings, but clear out any
+ * pgdir entries that are not in the description.
*/
+ i = 0;
do {
- if (address < init_map[idx].virtual || idx == NR_INIT_MAPS) {
+ if (address < init_map[i].virtual || i == NR_INIT_MAPS) {
free_init_section(address);
address += PGDIR_SIZE;
} else {
- create_mapping(&start_mem, init_map + idx);
+ create_mapping(init_map + i);
- address = init_map[idx].virtual + init_map[idx].length;
+ address = init_map[i].virtual + init_map[i].length;
address = (address + PGDIR_SIZE - 1) & PGDIR_MASK;
do {
- idx += 1;
- } while (init_map[idx].length == 0 && idx < NR_INIT_MAPS);
+ i += 1;
+ } while (init_map[i].length == 0 && i < NR_INIT_MAPS);
}
} while (address != 0);
/*
- * Now, create the architecture specific mappings
+ * Create the architecture specific mappings
*/
- for (idx = 0; idx < io_desc_size; idx++)
- create_mapping(&start_mem, io_desc + idx);
+ for (i = 0; i < io_desc_size; i++)
+ create_mapping(io_desc + i);
flush_cache_all();
-
- return start_mem;
}
/*
- * The mem_map array can get very big. Mark the end of the
- * valid mem_map banks with PG_skip, and setup the address
- * validity bitmap.
+ * The mem_map array can get very big. Mark the end of the valid mem_map
+ * banks with PG_skip, and setup the address validity bitmap.
*/
-unsigned long __init
-create_mem_holes(unsigned long start_mem, unsigned long end_mem)
+void __init create_memmap_holes(void)
{
+ unsigned int start_pfn, end_pfn = -1;
struct page *pg = NULL;
unsigned int sz, i;
- if (!machine_is_riscpc())
- return start_mem;
+ for (i = 0; i < meminfo.nr_banks; i++) {
+ if (meminfo.bank[i].size == 0)
+ continue;
- sz = (end_mem - PAGE_OFFSET) >> 20;
- sz = (sz + 31) >> 3;
-
- valid_addr_bitmap = (unsigned long *)start_mem;
- start_mem += sz;
+ start_pfn = meminfo.bank[i].start >> PAGE_SHIFT;
- memset(valid_addr_bitmap, 0, sz);
+ /*
+ * subtle here - if we have a full bank, then
+ * start_pfn == end_pfn, and we don't want to
+ * set PG_skip, or next_hash
+ */
+ if (pg && start_pfn != end_pfn) {
+ set_bit(PG_skip, &pg->flags);
+ pg->next_hash = mem_map + start_pfn;
- if (start_mem > mem_desc[0].virt_end)
- printk(KERN_CRIT "*** Error: RAM bank 0 too small\n");
+ start_pfn = PAGE_ALIGN(__pa(pg + 1));
+ end_pfn = __pa(pg->next_hash) & PAGE_MASK;
- for (i = 0; i < mem_desc_size; i++) {
- unsigned int idx, end;
+ if (end_pfn != start_pfn)
+ free_bootmem(start_pfn, end_pfn - start_pfn);
- if (pg) {
- pg->next_hash = mem_map +
- MAP_NR(mem_desc[i].virt_start);
pg = NULL;
}
- idx = __kern_valid_idx(mem_desc[i].virt_start);
- end = __kern_valid_idx(mem_desc[i].virt_end);
-
- do
- set_bit(idx, valid_addr_bitmap);
- while (++idx < end);
-
- if (mem_desc[i].virt_end < end_mem) {
- pg = mem_map + MAP_NR(mem_desc[i].virt_end);
+ end_pfn = (meminfo.bank[i].start +
+ meminfo.bank[i].size) >> PAGE_SHIFT;
- set_bit(PG_skip, &pg->flags);
- }
+ if (end_pfn != meminfo.end >> PAGE_SHIFT)
+ pg = mem_map + end_pfn;
}
- if (pg)
+ if (pg) {
+ set_bit(PG_skip, &pg->flags);
pg->next_hash = NULL;
-
- return start_mem;
-}
-
-void __init
-mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem)
-{
- /*
- * Mark all of memory from the end of kernel to end of memory
- */
- while (start_mem < end_mem) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
- start_mem += PAGE_SIZE;
}
+#if 0
/*
- * Mark memory from page 1 to start of the swapper page directory
+ * setup address validity map
+ * - don't think this is used anymore?
*/
- start_mem = PAGE_OFFSET + PAGE_SIZE;
- while (start_mem < (unsigned long)&swapper_pg_dir) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
- start_mem += PAGE_SIZE;
+ sz = meminfo.end >> (PAGE_SHIFT + 8); /* in MB */
+ sz = (sz + 31) >> 3;
+
+ valid_addr_bitmap = alloc_bootmem(sz);
+ memzero(valid_addr_bitmap, sz);
+
+ for (i = 0; i < meminfo.nr_banks; i++) {
+ int idx, end;
+
+ idx = meminfo.bank[i].start >> 20;
+ end = (meminfo.bank[i].start +
+ meminfo.bank[i].size) >> 20;
+ do
+ set_bit(idx, valid_addr_bitmap);
+ while (++idx < end);
}
-}
+#endif
+}
#include "map.h"
-struct mem_desc mem_desc[] __initdata = {
- 0, 0
-};
-
-unsigned int __initdata mem_desc_size = 0;
-
const struct map_desc io_desc[] __initdata = {
{ IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
{ IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }
#endif
-struct mem_desc mem_desc[] __initdata = {
- 0, 0
-};
-
-unsigned int __initdata mem_desc_size = 0;
-
struct map_desc io_desc[] __initdata = {
MAPPING
};
#include "map.h"
-struct mem_desc mem_desc[] __initdata = {
- 0, 0
-};
-
-unsigned int __initdata mem_desc_size = 0;
-
const struct map_desc io_desc[] __initdata = {
{ 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
{ 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
#define SIZE(x) (sizeof(x) / sizeof(x[0]))
-struct mem_desc mem_desc[] __initdata = {
- { 0xc0000000, 0xc0000000 },
- { 0xc4000000, 0xc4000000 },
- { 0xc8000000, 0xc8000000 },
- { 0xcc000000, 0xcc000000 }
-};
-
-unsigned int __initdata mem_desc_size = SIZE(mem_desc);
-
-void __init
-init_dram_banks(struct param_struct *params)
-{
- unsigned int bank;
-
- for (bank = 0; bank < mem_desc_size; bank++)
- mem_desc[bank].virt_end += PAGE_SIZE *
- params->u1.s.pages_in_bank[bank];
-
- params->u1.s.nr_pages = mem_desc[3].virt_end - PAGE_OFFSET;
- params->u1.s.nr_pages /= PAGE_SIZE;
-}
-
struct map_desc io_desc[] __initdata = {
/* VRAM */
{ SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 },
#include "map.h"
-struct mem_desc mem_desc[] __initdata = {
- 0, 0
-};
-
-unsigned int __initdata mem_desc_size = 0;
-
/* Logical Physical
* 0xffff1000 0x00100000 DMA registers
* 0xffff2000 0x00200000 MPEG
arm3_elf_name: .asciz "v2"
.align
- .section ".proc.info", #alloc
+ .section ".proc.info", #alloc, #execinstr
.long 0x41560200
.long 0xfffffff0
.size cpu_elf_name, . - cpu_elf_name
.align
- .section ".proc.info", #alloc
+ .section ".proc.info", #alloc, #execinstr
.type __arm6_proc_info, #object
__arm6_proc_info:
bl cpu_sa110_flush_tlb_all
mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches
mrc p15, 0, r0, c1, c0, 0 @ ctrl register
- bic r0, r0, #1 @ ...............m
+ bic r0, r0, #0x000f @ ............wcam
+ bic r0, r0, #0x1100 @ ...i...s........
ldmfd sp!, {r1, pc}
/*
* Purpose : Function pointers used to access above functions - all calls
.align
.section ".proc.info", #alloc, #execinstr
+
.type __sa110_proc_info,#object
__sa110_proc_info:
.long 0x4401a100
#include <linux/swap.h>
#include <linux/smp.h>
-#if PAGE_SIZE == 4096
-/* 2K blocks */
-#define SMALL_ALLOC_SHIFT (11)
-#define NAME(x) x##_2k
-#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
-/* 8K blocks */
-#define SMALL_ALLOC_SHIFT (13)
-#define NAME(x) x##_8k
-#endif
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
-#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT)
-#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE)
-#define BLOCK_MASK ((1 << NR_BLOCKS) - 1)
+#define PEDANTIC
-#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
-#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off)
-#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off))
-#define ALL_USED BLOCK_MASK
-#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off)))
-#define SM_PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
- ((block) << SMALL_ALLOC_SHIFT)))
-
-#if NR_BLOCKS != 2 && NR_BLOCKS != 4
-#error I only support 2 or 4 blocks per page
-#endif
+/*
+ * Requirement:
+ * We need to be able to allocate naturally aligned memory of finer
+ * granularity than the page size. This is typically used for the
+ * second level page tables on 32-bit ARMs.
+ *
+ * Theory:
+ * We "misuse" the Linux memory management system. We use __get_pages
+ * to allocate a page and then mark it as reserved. The Linux memory
+ * management system will then ignore the "offset", "next_hash" and
+ * "pprev_hash" entries in the mem_map for this page.
+ *
+ * We then use a bitstring in the "offset" field to mark which segments
+ * of the page are in use, and manipulate this as required during the
+ * allocation and freeing of these small pages.
+ *
+ * We also maintain a queue of pages being used for this purpose using
+ * the "next_hash" and "pprev_hash" entries of mem_map;
+ */
-struct free_small_page {
- unsigned long next;
- unsigned long prev;
+struct order {
+ struct page *queue;
+ unsigned int mask; /* (1 << shift) - 1 */
+ unsigned int shift; /* (1 << shift) size of page */
+ unsigned int block_mask; /* nr_blocks - 1 */
+ unsigned int all_used; /* (1 << nr_blocks) - 1 */
};
-/*
- * To handle allocating small pages, we use the main get_free_page routine,
- * and split the page up into 4. The page is marked in mem_map as reserved,
- * so it can't be free'd by free_page. The count field is used to keep track
- * of which sections of this page are allocated.
- */
-static unsigned long small_page_ptr;
-
-static unsigned char offsets[1<<NR_BLOCKS] = {
- 0, /* 0000 */
- 1, /* 0001 */
- 0, /* 0010 */
- 2, /* 0011 */
-#if NR_BLOCKS == 4
- 0, /* 0100 */
- 1, /* 0101 */
- 0, /* 0110 */
- 3, /* 0111 */
- 0, /* 1000 */
- 1, /* 1001 */
- 0, /* 1010 */
- 2, /* 1011 */
- 0, /* 1100 */
- 1, /* 1101 */
- 0, /* 1110 */
- 4 /* 1111 */
+
+static struct order orders[] = {
+#if PAGE_SIZE == 4096
+ { NULL, 2047, 11, 1, 0x00000003 }
+#elif PAGE_SIZE == 32768
+ { NULL, 2047, 11, 15, 0x0000ffff },
+ { NULL, 8191, 13, 3, 0x0000000f }
+#else
+#error unsupported page size
#endif
};
-static inline void clear_page_links(unsigned long page)
-{
- struct free_small_page *fsp;
- int i;
+#define USED_MAP(pg) ((pg)->offset)
+#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &(pg)->offset))
+#define SET_USED(pg,off) (set_bit(off, &(pg)->offset))
- for (i = 0; i < NR_BLOCKS; i++) {
- fsp = SM_PAGE_PTR(page, i);
- fsp->next = fsp->prev = 0;
- }
-}
-
-static inline void set_page_links_prev(unsigned long page, unsigned long prev)
+static void add_page_to_queue(struct page *page, struct page **p)
{
- struct free_small_page *fsp;
- unsigned int mask;
- int i;
-
- if (!page)
- return;
-
- mask = USED(&mem_map[MAP_NR(page)]);
- for (i = 0; i < NR_BLOCKS; i++) {
- if (mask & (1 << i))
- continue;
- fsp = SM_PAGE_PTR(page, i);
- fsp->prev = prev;
- }
+#ifdef PEDANTIC
+ if (page->pprev_hash)
+ PAGE_BUG(page);
+#endif
+ page->next_hash = *p;
+ if (*p)
+ (*p)->pprev_hash = &page->next_hash;
+ *p = page;
+ page->pprev_hash = p;
}
-static inline void set_page_links_next(unsigned long page, unsigned long next)
+static void remove_page_from_queue(struct page *page)
{
- struct free_small_page *fsp;
- unsigned int mask;
- int i;
-
- if (!page)
- return;
-
- mask = USED(&mem_map[MAP_NR(page)]);
- for (i = 0; i < NR_BLOCKS; i++) {
- if (mask & (1 << i))
- continue;
- fsp = SM_PAGE_PTR(page, i);
- fsp->next = next;
+ if (page->pprev_hash) {
+ if (page->next_hash)
+ page->next_hash->pprev_hash = page->pprev_hash;
+ *page->pprev_hash = page->next_hash;
+ page->pprev_hash = NULL;
}
}
-unsigned long NAME(get_page)(int priority)
+static unsigned long __get_small_page(int priority, struct order *order)
{
- struct free_small_page *fsp;
- unsigned long new_page;
unsigned long flags;
struct page *page;
int offset;
save_flags(flags);
- if (!small_page_ptr)
+ if (!order->queue)
goto need_new_page;
+
cli();
+ page = order->queue;
again:
- page = mem_map + MAP_NR(small_page_ptr);
- offset = offsets[USED(page)];
+#ifdef PEDANTIC
+ if (USED_MAP(page) & ~order->all_used)
+ PAGE_BUG(page);
+#endif
+ offset = ffz(USED_MAP(page));
SET_USED(page, offset);
- new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset);
- if (USED(page) == ALL_USED) {
- fsp = (struct free_small_page *)new_page;
- set_page_links_prev (fsp->next, 0);
- small_page_ptr = fsp->next;
- }
+ if (USED_MAP(page) == order->all_used)
+ remove_page_from_queue(page);
restore_flags(flags);
- return new_page;
+
+ return page_address(page) + (offset << order->shift);
need_new_page:
- new_page = __get_free_page(priority);
- if (!small_page_ptr) {
- if (new_page) {
- set_bit (PG_reserved, &mem_map[MAP_NR(new_page)].flags);
- clear_page_links (new_page);
- cli();
- small_page_ptr = new_page;
- goto again;
- }
- restore_flags(flags);
- return 0;
+ page = __get_pages(priority, 0);
+ if (!order->queue) {
+ if (!page)
+ goto no_page;
+ SetPageReserved(page);
+ USED_MAP(page) = 0;
+ cli();
+ add_page_to_queue(page, &order->queue);
+ } else {
+ __free_page(page);
+ cli();
+ page = order->queue;
}
- free_page(new_page);
- cli();
goto again;
+
+no_page:
+ restore_flags(flags);
+ return 0;
}
-void NAME(free_page)(unsigned long spage)
+static void __free_small_page(unsigned long spage, struct order *order)
{
- struct free_small_page *ofsp, *cfsp;
unsigned long flags;
+ unsigned long nr;
struct page *page;
- int offset, oldoffset;
-
- if (!spage)
- goto none;
-
- offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
- spage -= offset << SMALL_ALLOC_SHIFT;
-
- page = mem_map + MAP_NR(spage);
- if (!PageReserved(page) || !USED(page))
- goto non_small;
-
- if (IS_FREE(page, offset))
- goto free;
-
- save_flags_cli (flags);
- oldoffset = offsets[USED(page)];
- CLEAR_USED(page, offset);
- ofsp = SM_PAGE_PTR(spage, oldoffset);
- cfsp = SM_PAGE_PTR(spage, offset);
-
- if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
- cfsp->prev = 0;
- cfsp->next = small_page_ptr;
- set_page_links_prev (small_page_ptr, spage);
- small_page_ptr = spage;
- } else if (!USED(page)) {
- set_page_links_prev (ofsp->next, ofsp->prev);
- set_page_links_next (ofsp->prev, ofsp->next);
- if (spage == small_page_ptr)
- small_page_ptr = ofsp->next;
- clear_bit (PG_reserved, &page->flags);
+
+ nr = MAP_NR(spage);
+ if (nr < max_mapnr) {
+ page = mem_map + nr;
+
+ /*
+ * The container-page must be marked Reserved
+ */
+ if (!PageReserved(page) || spage & order->mask)
+ goto non_small;
+
+#ifdef PEDANTIC
+ if (USED_MAP(page) & ~order->all_used)
+ PAGE_BUG(page);
+#endif
+
+ spage = spage >> order->shift;
+ spage &= order->block_mask;
+
+ /*
+ * the following must be atomic wrt get_page
+ */
+ save_flags_cli(flags);
+
+ if (USED_MAP(page) == order->all_used)
+ add_page_to_queue(page, &order->queue);
+
+ if (!TEST_AND_CLEAR_USED(page, spage))
+ goto already_free;
+
+ if (USED_MAP(page) == 0)
+ goto free_page;
+
restore_flags(flags);
- free_page (spage);
- } else
- *cfsp = *ofsp;
+ }
+ return;
+
+free_page:
+ /*
+ * unlink the page from the small page queue and free it
+ */
+ remove_page_from_queue(page);
restore_flags(flags);
+ ClearPageReserved(page);
+ __free_page(page);
return;
non_small:
- printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
- return;
-free:
- printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
-none:
+ printk("Trying to free non-small page from %p\n", __builtin_return_address(0));
return;
+already_free:
+ printk("Trying to free free small page from %p\n", __builtin_return_address(0));
}
+
+unsigned long get_page_2k(int priority)
+{
+ return __get_small_page(priority, orders+0);
+}
+
+void free_page_2k(unsigned long spage)
+{
+ __free_small_page(spage, orders+0);
+}
+
+#if PAGE_SIZE > 8192
+unsigned long get_page_8k(int priority)
+{
+ return __get_small_page(priority, orders+1);
+}
+
+void free_page_8k(unsigned long spage)
+{
+ __free_small_page(spage, orders+1);
+}
+#endif
SECTIONS
{
. = TEXTADDR;
- __init_begin = .;
+
+ __init_begin = .; /* Init code and data */
.text.init : { *(.text.init) }
__proc_info_begin = .;
.proc.info : { *(.proc.info) }
*(.init.task)
}
- _text = .; /* Text and read-only data */
+ _text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
}
+
.text.lock : { *(.text.lock) } /* out-of-line lock text */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
- . = ALIGN(16); /* Exception table */
+ . = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
- __start___ksymtab = .; /* Kernel symbol table */
+ __start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
- .got : { *(.got) } /* Global offset table */
+ .got : { *(.got) } /* Global offset table */
- _etext = .; /* End of text section */
+ _etext = .; /* End of text section */
- .data : { /* Data */
+ .data : { /* Data */
*(.data)
CONSTRUCTORS
}
- _edata = .; /* End of data section */
+ _edata = .; /* End of data section */
- __bss_start = .; /* BSS */
+ __bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
- /* Stabs debugging sections. */
+ /* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
/* -*- linux-c -*-
* APM BIOS driver for Linux
- * Copyright 1994-1998 Stephen Rothwell
- * (Stephen.Rothwell@canb.auug.org.au)
- * Development of this driver was funded by NEC Australia P/L
+ * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * Initial development of this driver was funded by NEC Australia P/L
* and NEC Corporation
*
* This program is free software; you can redistribute it and/or modify it
*/
static int __init apm_init(void)
{
- static struct proc_dir_entry *ent;
-
if (apm_bios_info.version == 0) {
printk(KERN_INFO "apm: BIOS not found.\n");
return -1;
}
#endif
- ent = create_proc_entry("apm", 0, 0);
- if (ent != NULL)
- ent->get_info = apm_get_info;
+ create_proc_info_entry("apm", 0, 0, apm_get_info);
misc_register(&apm_device);
if(mca_info == NULL) return; /* Should never happen */
- proc_register(&proc_mca, &(struct proc_dir_entry) {
+ proc_register(proc_mca, &(struct proc_dir_entry) {
PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO,
1, 0, 0, 0, &proc_mca_inode_operations,});
- proc_register(&proc_mca, &(struct proc_dir_entry) {
+ proc_register(proc_mca, &(struct proc_dir_entry) {
PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO,
1, 0, 0, 0, &proc_mca_inode_operations,});
node->name = mca_info->slot[i].procname;
node->mode = S_IFREG | S_IRUGO;
node->ops = &proc_mca_inode_operations;
- proc_register(&proc_mca, node);
+ proc_register(proc_mca, node);
}
} /* mca_do_proc_init() */
};
static struct proc_dir_entry proc_root_mtrr = {
- PROC_MTRR, 4, "mtrr",
+ 0, 4, "mtrr",
S_IFREG | S_IWUSR | S_IRUGO, 1, 0, 0,
0, &proc_mtrr_inode_operations
};
* could use the real zero-page, but it's safer
* this way if some buggy code writes to this page ...
*/
- apic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE));
+ apic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
memset((void *)apic_phys, 0, PAGE_SIZE);
+ apic_phys = __pa(apic_phys);
}
set_fixmap(FIX_APIC_BASE, apic_phys);
dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mpc_apicaddr;
} else {
- ioapic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE));
+ ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
memset((void *)ioapic_phys, 0, PAGE_SIZE);
+ ioapic_phys = __pa(ioapic_phys);
}
set_fixmap(idx,ioapic_phys);
dprintk("mapped IOAPIC to %08lx (%08lx)\n",
return p;
}
-static void fast_clear_page(long page)
+static void fast_clear_page(void *page)
{
int i;
if (!(current->flags & PF_USEDFPU))
stts();
}
-static void fast_copy_page(long to, long from)
+static void fast_copy_page(void *to, void *from)
{
int i;
if (!(current->flags & PF_USEDFPU))
* Favour MMX for page clear and copy.
*/
-static void slow_zero_page(long page)
+static void slow_zero_page(void * page)
{
int d0, d1;
__asm__ __volatile__( \
:"memory");
}
-void mmx_clear_page(long page)
+void mmx_clear_page(void * page)
{
if(in_interrupt())
slow_zero_page(page);
fast_clear_page(page);
}
-static void slow_copy_page(long to, long from)
+static void slow_copy_page(void *to, void *from)
{
int d0, d1, d2;
__asm__ __volatile__( \
}
-void mmx_copy_page(long to, long from)
+void mmx_copy_page(void *to, void *from)
{
if(in_interrupt())
slow_copy_page(to, from);
int iop_scc_present,iop_ism_present;
#ifdef CONFIG_PROC_FS
-
-/*
- * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c
- * anymore so we'll use it to debut the IOPs.
- */
-
-int iop_get_proc_info(char *, char **, off_t, int, int);
-
-static struct proc_dir_entry proc_mac_iop = {
- PROC_MAC_VIA, 7, "mac_iop",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- &iop_get_proc_info
-};
-
+static int iop_get_proc_info(char *, char **, off_t, int, int);
+#else
+static int iop_get_proc_info(char *, char **, off_t, int, int) {}
#endif /* CONFIG_PROC_FS */
/* structure for tracking channel listeners */
iop_listeners[IOP_NUM_ISM][i].handler = NULL;
}
-#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &proc_mac_iop);
-#endif
+ create_proc_info_entry("mac_iop",0,0,iop_get_proc_info);
}
/*
}
return (count > cnt) ? cnt : count;
}
+
#endif /* CONFIG_PROC_FS */
if [ "$CONFIG_SGI" = "y" ]; then
bool ' SGI Seeq ethernet controller support' CONFIG_SGISEEQ
fi
- if [ "$CONFIG_DECSTATION" = "y" ]; then
- bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE
- fi
- if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
- tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE
- tristate ' Baget Backplane Shared Memory support' CONFIG_BAGETBSM
- fi
+ if [ "$CONFIG_DECSTATION" = "y" ]; then
+ bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE
+ fi
+ if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
+ tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE
+ tristate ' Baget Backplane Shared Memory support' CONFIG_BAGETBSM
fi
fi
endmenu
mainmenu_option next_comment
- comment comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+ comment 'Old CD-ROM drivers (not SCSI, not IDE)'
bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
mainmenu_option next_comment
comment 'Platform support'
define_bool CONFIG_PPC y
endmenu
mainmenu_option next_comment
-comment 'General setup'
-
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
- bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
- bool 'Kernel module loader' CONFIG_KMOD
+ bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
+ bool ' Kernel module loader' CONFIG_KMOD
fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
if [ "$CONFIG_APUS" = "y" ]; then
define_bool CONFIG_PCI n
# Acorn Network device configuration
# These are for Acorn's Expansion card network interfaces
#
-tristate 'Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1
-tristate 'Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3
-tristate 'I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH
+tristate ' Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1
+tristate ' Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3
+tristate ' I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH
/*
- DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry.
+ DAC960_ProcDirectoryEntry is the DAC960 /proc/driver/rd directory entry.
*/
-static PROC_DirectoryEntry_T
- DAC960_ProcDirectoryEntry;
+static PROC_DirectoryEntry_T *
+ DAC960_ProcDirectoryEntry = NULL;
/*
/*
- DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960
- Driver.
+ DAC960_CreateProcEntries creates the /proc/driver/rd/... entries
+ for the DAC960 Driver.
*/
static void DAC960_CreateProcEntries(void)
{
- static PROC_DirectoryEntry_T StatusProcEntry;
+ static PROC_DirectoryEntry_T *StatusProcEntry;
int ControllerNumber;
- DAC960_ProcDirectoryEntry.name = "rd";
- DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name);
- DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO;
- proc_register(&proc_root, &DAC960_ProcDirectoryEntry);
- StatusProcEntry.name = "status";
- StatusProcEntry.namelen = strlen(StatusProcEntry.name);
- StatusProcEntry.mode = S_IFREG | S_IRUGO;
- StatusProcEntry.read_proc = DAC960_ProcReadStatus;
- proc_register(&DAC960_ProcDirectoryEntry, &StatusProcEntry);
+ DAC960_ProcDirectoryEntry = create_proc_entry("driver/rd", S_IFDIR, NULL);
+ StatusProcEntry = create_proc_read_entry("status", 0,
+ DAC960_ProcDirectoryEntry,
+ DAC960_ProcReadStatus, NULL);
for (ControllerNumber = 0;
ControllerNumber < DAC960_ControllerCount;
ControllerNumber++)
ControllerProcEntry->name = Controller->ControllerName;
ControllerProcEntry->namelen = strlen(ControllerProcEntry->name);
ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
- proc_register(&DAC960_ProcDirectoryEntry, ControllerProcEntry);
+ proc_register(DAC960_ProcDirectoryEntry, ControllerProcEntry);
InitialStatusProcEntry = &Controller->InitialStatusProcEntry;
InitialStatusProcEntry->name = "initial_status";
InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name);
static void DAC960_DestroyProcEntries(void)
{
- proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino);
+ remove_proc_entry("driver/rd", NULL);
}
static int revalidate_logvol(kdev_t dev, int maxusage);
static int revalidate_allvol(kdev_t dev);
+#ifdef CONFIG_PROC_FS
static void ida_procinit(int i);
static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+#else
+static void ida_procinit(int i) {}
+static int ida_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data) {}
+#endif
static void ida_geninit(struct gendisk *g)
{
};
+#ifdef CONFIG_PROC_FS
+
/*
* Get us a file in /proc/array that says something about each controller.
* Create /proc/array if it doesn't exist yet.
*/
-static void ida_procinit(int i)
+static void __init ida_procinit(int i)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *pd;
-
if (proc_array == NULL) {
- proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO,
- &proc_root);
+ proc_array = create_proc_entry("driver/array", S_IFDIR, NULL);
if (!proc_array) return;
}
- pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array);
- if (!pd) return;
- pd->read_proc = ida_proc_get_info;
- pd->data = hba[i];
-#endif
+ create_proc_read_entry(hba[i]->devname, 0, proc_array,
+ ida_proc_get_info, hba[i]);
}
/*
len = length;
return len;
}
+#endif /* CONFIG_PROC_FS */
#ifdef MODULE
EXPORT_NO_SYMBOLS;
/* This is a bit of a hack... */
-int init_module(void)
+int __init init_module(void)
{
int i, j;
cpqarray_init();
}
return 0;
}
+
void cleanup_module(void)
{
int i;
struct gendisk *g;
+ remove_proc_entry("driver/array", NULL);
+
for(i=0; i<nr_ctlr; i++) {
hba[i]->access.set_intr_mask(hba[i], 0);
free_irq(hba[i]->intr, hba[i]);
}
}
}
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("array", &proc_root);
-#endif
+
kfree(ida);
kfree(ida_sizes);
kfree(ida_hardsizes);
kfree(ida_blocksizes);
-
-
}
#endif /* MODULE */
* This is it. Find all the controllers and register them. I really hate
* stealing all these major device numbers.
*/
-void cpqarray_init(void)
+void __init cpqarray_init(void)
{
void (*request_fns[MAX_CTLR])(void) = {
do_ida_request0, do_ida_request1,
*/
static void
ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) {
- struct hd_driveid *id = drive->id;
static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
const byte *headp = dm_head_vals;
unsigned long total, tracks;
* 1024*255*63. Now take S=63, H the first in the sequence
* 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
*/
- if (id)
- total = id->cyls * id->heads * id->sectors;
- else
- total = drive->cyl * drive->head * drive->sect;
+ total = DRIVER(drive)->capacity(drive);
*s = 63;
void proc_ide_create(void)
{
- struct proc_dir_entry *ent;
proc_ide_root = create_proc_entry("ide", S_IFDIR, 0);
if (!proc_ide_root) return;
+
create_proc_ide_interfaces();
- ent = create_proc_entry("drivers", 0, proc_ide_root);
- if (!ent) return;
- ent->read_proc = proc_ide_read_drivers;
+ create_proc_read_entry("drivers",0,proc_ide_root,
+ proc_ide_read_drivers, NULL);
+
#ifdef CONFIG_BLK_DEV_ALI15X3
- if ((ali_display_info) && (ali_proc)) {
- ent = create_proc_entry("ali", 0, proc_ide_root);
- ent->get_info = ali_display_info;
- }
+ if ((ali_display_info) && (ali_proc))
+ create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
#endif /* CONFIG_BLK_DEV_ALI15X3 */
#ifdef CONFIG_BLK_DEV_SIS5513
- if ((sis_display_info) && (sis_proc)) {
- ent = create_proc_entry("sis", 0, proc_ide_root);
- ent->get_info = sis_display_info;
- }
+ if ((sis_display_info) && (sis_proc))
+ create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
#endif /* CONFIG_BLK_DEV_SIS5513 */
#ifdef CONFIG_BLK_DEV_VIA82CXXX
- if ((via_display_info) && (via_proc)) {
- ent = create_proc_entry("via", 0, proc_ide_root);
- ent->get_info = via_display_info;
- }
+ if ((via_display_info) && (via_proc))
+ create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
#endif /* CONFIG_BLK_DEV_VIA82CXXX */
}
EXPORT_SYMBOL(md_do_sync);
#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_md = {
- PROC_MD, 6, "mdstat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
-};
+static int md_status_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int sz = 0, i, j, size;
+ int begin = 0;
+
+ sz=sprintf( page, "Personalities : ");
+ for (i=0; i<MAX_PERSONALITY; i++)
+ if (pers[i])
+ sz+=sprintf (page+sz, "[%d %s] ", i, pers[i]->name);
+ page[sz-1]='\n';
+
+ sz+=sprintf (page+sz, "read_ahead ");
+ if (read_ahead[MD_MAJOR]==INT_MAX)
+ sz+=sprintf (page+sz, "not set\n");
+ else
+ sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]);
+
+ for (i=0; i<MAX_MD_DEV; i++) {
+ if (sz < off) {
+ begin += sz;
+ off -= sz;
+ sz = 0;
+ }
+ if (sz >= off+count) {
+ *eof = 1;
+ break;
+ }
+ sz+=sprintf (page+sz, "md%d : %sactive",
+ i, md_dev[i].pers ? "" : "in");
+
+ if (md_dev[i].pers)
+ sz+=sprintf (page+sz, " %s", md_dev[i].pers->name);
+
+ for (j=0, size=0; j<md_dev[i].nb_dev; j++) {
+ sz+=sprintf (page+sz, " %s",
+ partition_name(md_dev[i].devices[j].dev));
+ size+=md_dev[i].devices[j].size;
+ }
+
+ if (md_dev[i].nb_dev) {
+ if (md_dev[i].pers)
+ sz+=sprintf (page+sz, " %d blocks", md_size[i]);
+ else
+ sz+=sprintf (page+sz, " %d blocks", size);
+ }
+
+ if (!md_dev[i].pers) {
+ sz+=sprintf (page+sz, "\n");
+ continue;
+ }
+
+ if (md_dev[i].pers->max_invalid_dev)
+ sz+=sprintf (page+sz, " maxfault=%ld",
+ MAX_FAULT(md_dev+i));
+
+ sz+=md_dev[i].pers->status (page+sz, i, md_dev+i);
+ sz+=sprintf (page+sz, "\n");
+ }
+
+ sz -= off;
+ *start = page + off;
+ if (sz>count)
+ sz = count;
+ if (sz<0)
+ sz = 0;
+ return sz;
+}
#endif
static void md_geninit (struct gendisk *gdisk)
max_readahead[MD_MAJOR] = md_maxreadahead;
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &proc_md);
+ create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL);
#endif
}
return 0;
}
-int get_md_status (char *page)
-{
- int sz=0, i, j, size;
-
- sz+=sprintf( page+sz, "Personalities : ");
- for (i=0; i<MAX_PERSONALITY; i++)
- if (pers[i])
- sz+=sprintf (page+sz, "[%d %s] ", i, pers[i]->name);
-
- page[sz-1]='\n';
-
- sz+=sprintf (page+sz, "read_ahead ");
- if (read_ahead[MD_MAJOR]==INT_MAX)
- sz+=sprintf (page+sz, "not set\n");
- else
- sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]);
-
- for (i=0; i<MAX_MD_DEV; i++)
- {
- sz+=sprintf (page+sz, "md%d : %sactive", i, md_dev[i].pers ? "" : "in");
-
- if (md_dev[i].pers)
- sz+=sprintf (page+sz, " %s", md_dev[i].pers->name);
-
- size=0;
- for (j=0; j<md_dev[i].nb_dev; j++)
- {
- sz+=sprintf (page+sz, " %s",
- partition_name(md_dev[i].devices[j].dev));
- size+=md_dev[i].devices[j].size;
- }
-
- if (md_dev[i].nb_dev) {
- if (md_dev[i].pers)
- sz+=sprintf (page+sz, " %d blocks", md_size[i]);
- else
- sz+=sprintf (page+sz, " %d blocks", size);
- }
-
- if (!md_dev[i].pers)
- {
- sz+=sprintf (page+sz, "\n");
- continue;
- }
-
- if (md_dev[i].pers->max_invalid_dev)
- sz+=sprintf (page+sz, " maxfault=%ld", MAX_FAULT(md_dev+i));
-
- sz+=md_dev[i].pers->status (page+sz, i, md_dev+i);
- sz+=sprintf (page+sz, "\n");
- }
-
- return (sz);
-}
-
int register_md_personality (int p_num, struct md_personality *p)
{
int i=(p_num >> PERSONALITY_SHIFT);
*
* The H8 is used to deal with the power and thermal environment
* of a system.
+ *
+ * Fixes:
+ * June 1999, AV added releasing /proc/driver/h8
*/
#include <linux/config.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/linkage.h>
-#ifdef CONFIG_PROC_FS
#include <linux/stat.h>
#include <linux/proc_fs.h>
-#endif
#include <linux/miscdevice.h>
#include <linux/lists.h>
#include <linux/ioport.h>
#ifdef CONFIG_PROC_FS
static int h8_get_info(char *, char **, off_t, int, int);
+#else
+static int h8_get_info(char *, char **, off_t, int, int) {}
#endif
/*
&h8_fops
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry h8_proc_entry = {
- 0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info
-};
-#endif
-
union intr_buf intrbuf;
int intr_buf_ptr;
union intr_buf xx;
misc_register(&h8_device);
request_region(h8_base, 8, "h8");
-#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &h8_proc_entry);
-#endif
+ create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
void cleanup_module(void)
{
+ remove_proc_entry("driver/h8", NULL);
misc_deregister(&h8_device);
release_region(h8_base, 8);
free_irq(h8_irq, NULL);
}
printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
-#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &h8_proc_entry);
-#endif
+ create_proc_info_entry("driver/h8", 0, NULL, h8_get_info);
misc_register(&h8_device);
request_region(h8_base, 8, "h8");
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
- unsigned long offset = vma->vm_offset;
-
- if (offset & ~PAGE_MASK)
- return -ENXIO;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
/*
* Accessing memory above the top the kernel knows about or
extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
extern int dsp56k_init(void);
-extern int nvram_init(void);
extern int radio_init(void);
extern int pc110pad_init(void);
extern int pmu_device_init(void);
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
-static struct proc_dir_entry *proc_misc;
-
int __init misc_init(void)
{
- proc_misc = create_proc_entry("misc", 0, 0);
- if (proc_misc)
- proc_misc->read_proc = misc_read_proc;
+ create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
#ifdef CONFIG_BUSMOUSE
bus_mouse_init();
#endif
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
-#ifdef CONFIG_NVRAM
- nvram_init();
-#endif
#ifdef CONFIG_MISC_RADIO
radio_init();
#endif
#include <linux/mc146818rtc.h>
#include <linux/nvram.h>
#include <linux/init.h>
-#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
-#endif
#include <asm/io.h>
#include <asm/uaccess.h>
#ifdef CONFIG_PROC_FS
-
-struct proc_dir_entry *proc_nvram;
+static int nvram_read_proc( char *buffer, char **start, off_t offset,
+ int size, int *eof,
+ void *data) {}
+#else
static int nvram_read_proc( char *buffer, char **start, off_t offset,
int size, int *eof, void *data )
} \
} while(0)
-#endif
+#endif /* CONFIG_PROC_FS */
static struct file_operations nvram_fops = {
nvram_llseek,
};
-int __init nvram_init(void)
+static int __init nvram_init(void)
{
/* First test whether the driver should init at all */
if (!CHECK_DRIVER_INIT())
printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
misc_register( &nvram_dev );
-#ifdef CONFIG_PROC_FS
- if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
- proc_nvram->read_proc = nvram_read_proc;
-#endif
-
+ create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL);
return( 0 );
}
-#ifdef MODULE
-int init_module (void)
-{
- return( nvram_init() );
-}
-
-void cleanup_module (void)
+static void __exit nvram_cleanup_module (void)
{
-#ifdef CONFIG_PROC_FS
- if (proc_nvram)
- remove_proc_entry( "nvram", 0 );
-#endif
+ remove_proc_entry( "driver/nvram", 0 );
misc_deregister( &nvram_dev );
}
-#endif
+
+module_init(nvram_init);
+module_exit(nvram_cleanup_module);
/*
static __u8 rdsin=0,rdsout=0,rdsstat=0;
static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
-static int cadet_probe(void);
/*
* Signal Strength Threshold Values
NULL
};
-int __init cadet_init(struct video_init *v)
-{
-#ifndef MODULE
- if(cadet_probe()<0) {
- return EINVAL;
- }
-#endif
- if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1)
- return -EINVAL;
-
- request_region(io,2,"cadet");
- printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
- return 0;
-}
-
-
#ifndef MODULE
static int cadet_probe(void)
{
}
#endif
+int __init cadet_init(void)
+{
+#ifndef MODULE
+ io = cadet_probe ();
+#endif
+
+ if(io < 0) {
+#ifdef MODULE
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+#endif
+ return EINVAL;
+ }
+ if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io,2,"cadet");
+ printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
+ return 0;
+}
-#ifdef MODULE
MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
- return -EINVAL;
- }
- return cadet_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit cadet_cleanup_module(void)
{
video_unregister_device(&cadet_radio);
release_region(io,2);
}
-#endif
+module_init(cadet_init);
+module_exit(cadet_cleanup_module);
NULL
};
-int __init rtrack2_init(struct video_init *v)
+static int __init rtrack2_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
+ return -EINVAL;
+ }
if (check_region(io, 4))
{
printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("Ben Pfaff");
MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
- return -EINVAL;
- }
- return rtrack2_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit rtrack2_cleanup_module(void)
{
video_unregister_device(&rtrack2_radio);
release_region(io,4);
}
-#endif
+module_init(rtrack2_init);
+module_exit(rtrack2_cleanup_module);
/*
Local variables:
NULL
};
-int __init fmi_init(struct video_init *v)
+static int __init fmi_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
if (check_region(io, 2))
{
printk(KERN_ERR "fmi: port 0x%x already in use\n", io);
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
MODULE_DESCRIPTION("A driver for the SF16MI radio.");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
- return -EINVAL;
- }
- return fmi_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit fmi_cleanup_module(void)
{
video_unregister_device(&fmi_radio);
release_region(io,2);
}
-#endif
+module_init(fmi_init);
+module_exit(fmi_cleanup_module);
+
NULL
};
-int __init terratec_init(struct video_init *v)
+static int __init terratec_init(void)
{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
if (check_region(io, 2))
{
printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("R.OFFERMANNS & others");
MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
- return -EINVAL;
- }
- return terratec_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit terratec_cleanup_module(void)
{
video_unregister_device(&terratec_radio);
release_region(io,2);
printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
}
-#endif
+module_init(terratec_init);
+module_exit(terratec_cleanup_module);
+
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
-#endif /* MODULE */
-
static void __exit cleanup_trust_module(void)
{
video_unregister_device(&trust_radio);
static int typhoon_read_proc(char *buf, char **start, off_t offset, int len,
int unused);
#endif
-#ifdef MODULE
-int init_module(void);
-void cleanup_module(void);
-int typhoon_init(struct video_init *v);
-#else
-int typhoon_init(struct video_init *v) __init;
-#endif
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
{
return len;
}
-static struct proc_dir_entry typhoon_proc_entry = {
- 0, /* low_ino: inode is dynamic */
- 13, "radio-typhoon", /* length of name and name */
- S_IFREG | S_IRUGO, /* mode */
- 1, 0, 0, /* nlinks, owner, group */
- 0, /* size -- not used */
- NULL, /* operations -- use default */
- &typhoon_read_proc, /* function used to read data */
- /* nothing more */
-};
-
#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */
-int typhoon_init(struct video_init *v)
-{
- printk(KERN_INFO BANNER);
- if (check_region(typhoon_unit.iobase, 8)) {
- printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
- typhoon_unit.iobase);
- return -EBUSY;
- }
-
- typhoon_radio.priv = &typhoon_unit;
- if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1)
- return -EINVAL;
-
- request_region(typhoon_unit.iobase, 8, "typhoon");
- printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase);
- printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n",
- typhoon_unit.mutefreq);
- typhoon_unit.mutefreq <<= 4;
-
- /* mute card - prevents noisy bootups */
- typhoon_mute(&typhoon_unit);
-
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-
- if (proc_register(&proc_root, &typhoon_proc_entry))
- printk(KERN_ERR "radio-typhoon: registering /proc/radio-typhoon failed\n");
-
-#endif
-
- return 0;
-}
-
-#ifdef MODULE
-
MODULE_AUTHOR("Dr. Henrik Seidel");
MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
static int io = -1;
+
+#ifdef MODULE
static unsigned long mutefreq = 0;
+#endif
-int init_module(void)
+static int __init typhoon_init(void)
{
+#ifdef MODULE
if (io == -1) {
printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n");
return -EINVAL;
return -EINVAL;
}
typhoon_unit.mutefreq = mutefreq;
+#endif /* MODULE */
- return typhoon_init(NULL);
-}
+ printk(KERN_INFO BANNER);
+ io = typhoon_unit.iobase;
+ if (check_region(io, 8)) {
+ printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n",
+ typhoon_unit.iobase);
+ return -EBUSY;
+ }
-void cleanup_module(void)
-{
+ typhoon_radio.priv = &typhoon_unit;
+ if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1)
+ return -EINVAL;
+
+ request_region(typhoon_unit.iobase, 8, "typhoon");
+ printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase);
+ printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n",
+ typhoon_unit.mutefreq);
+ typhoon_unit.mutefreq <<= 4;
+
+ /* mute card - prevents noisy bootups */
+ typhoon_mute(&typhoon_unit);
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
+ if (!create_proc_read_entry("driver/radio-typhoon", 0, NULL,
+ typhoon_read_proc, NULL))
+ printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+#endif
+
+ return 0;
+}
- if (proc_unregister(&proc_root, typhoon_proc_entry.low_ino))
- printk(KERN_ERR "radio-typhoon: unregistering /proc/radio-typhoon failed\n");
+static void __exit typhoon_cleanup_module(void)
+{
+#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
+ remove_proc_entry("driver/radio-typhoon");
#endif
video_unregister_device(&typhoon_radio);
release_region(io, 8);
}
-#endif
-
+module_init(typhoon_init);
+module_exit(typhoon_cleanup_module);
NULL
};
-int __init zoltrix_init(struct video_init *v)
+static int __init zoltrix_init(void)
{
+ if (io == -1) {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
if (check_region(io, 2)) {
printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
return -EBUSY;
return 0;
}
-#ifdef MODULE
-
MODULE_AUTHOR("C.van Schaik");
MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
MODULE_PARM(io, "i");
EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- if (io == -1) {
- printk(KERN_ERR "You must set an I/O address with io=0x???\n");
- return -EINVAL;
- }
- return zoltrix_init(NULL);
-}
-
-void cleanup_module(void)
+static void __exit zoltrix_cleanup_module(void)
{
video_unregister_device(&zoltrix_radio);
release_region(io, 2);
}
-#endif
+module_init(zoltrix_init);
+module_exit(zoltrix_cleanup_module);
+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+#define RS_EVENT_WRITE_WAKEUP 0
+
DECLARE_TASK_QUEUE(tq_riscom);
#define RISCOM_TYPE_NORMAL 1
#endif
#endif /* NEW_MODULES */
#include <linux/module.h>
-
+#include <linux/types.h>
#ifdef LOCAL_HEADERS
#include "serial_local.h"
#else
-#include <linux/serialP.h>
#include <linux/serial.h>
+#include <linux/serialP.h>
#include <linux/serial_reg.h>
#include <asm/serial.h>
static char *serial_version = "4.30";
DECLARE_TASK_QUEUE(tq_specialix);
-
+#undef RS_EVENT_WRITE_WAKEUP
+#define RS_EVENT_WRITE_WAKEUP 0
#define SPECIALIX_TYPE_NORMAL 1
#define SPECIALIX_TYPE_CALLOUT 2
#endif
+#undef RS_EVENT_WRITE_WAKEUP
+#define RS_EVENT_WRITE_WAKEUP 0
#include "generic_serial.h"
#ifdef CONFIG_VIDEO_PLANB
extern int init_planbs(struct video_init *);
#endif
-#ifdef CONFIG_RADIO_RTRACK2
-extern int rtrack2_init(struct video_init *);
-#endif
-#ifdef CONFIG_RADIO_SF16FMI
-extern int fmi_init(struct video_init *);
-#endif
-#ifdef CONFIG_RADIO_TYPHOON
-extern int typhoon_init(struct video_init *);
-#endif
-#ifdef CONFIG_RADIO_CADET
-extern int cadet_init(struct video_init *);
-#endif
-#ifdef CONFIG_RADIO_TERRATEC
-extern int terratec_init(struct video_init *);
-#endif
#ifdef CONFIG_VIDEO_ZORAN
extern int init_zoran_cards(struct video_init *);
#endif
#ifdef CONFIG_VIDEO_PLANB
{"planb", init_planbs},
#endif
-#ifdef CONFIG_RADIO_RTRACK2
- {"RTrack2", rtrack2_init},
-#endif
-#ifdef CONFIG_RADIO_SF16FMI
- {"SF16FMI", fmi_init},
-#endif
-#ifdef CONFIG_RADIO_CADET
- {"Cadet", cadet_init},
-#endif
-#ifdef CONFIG_RADIO_TYPHOON
- {"radio-typhoon", typhoon_init},
-#endif
-#ifdef CONFIG_RADIO_TERRATEC
- {"radio-terratec", terratec_init},
-#endif
#ifdef CONFIG_VIDEO_ZORAN
{"zoran", init_zoran_cards},
#endif
if (dev->mem_start) { /* Shared memory transfer */
unsigned long dest_addr = dev->mem_start +
((start_page - ei_status.tx_start_page) << 8);
- memcpy_toio(dest_addr, buf, count);
+ isa_memcpy_toio(dest_addr, buf, count);
outb(EGACFR_NORM, E33G_GACFR); /* Back to bank1 in case on bank0 */
return;
}
unsigned short word;
if (dev->mem_start) { /* Use the shared memory. */
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+ isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
return;
}
if (dev->mem_start + ring_offset + count > end_of_ring) {
/* We must wrap the input move. */
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
- memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
+ isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
count -= semi_count;
- memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
+ isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
}
return;
}
* Apple Powermacs. Assumes it's under a DBDMA controller.
*
* Copyright (C) 1998 Randy Gobbel.
+ *
+ * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
+ * dynamic procfs inode.
*/
#include <linux/config.h>
#include <linux/module.h>
if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM;
-#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_BMAC, 4, "bmac",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- bmac_proc_info
- });
-#endif
+ proc_net_create ("bmac", 0, bmac_proc_info);
return 0;
}
bp = (struct bmac_data *) bmac_devs->priv;
unregister_netdev(bmac_devs);
+ proc_net_remove("bmac");
free_irq(bmac_devs->irq, bmac_misc_intr);
free_irq(bp->tx_dma_intr, bmac_txdma_intr);
printk(KERN_INFO "AX.25 ethernet driver version 0.01\n");
-#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_AX25_BPQETHER, 8, "bpqether",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- bpq_get_info
- });
-#endif
+ proc_net_create ("bpqether", 0, bpq_get_info);
read_lock_bh(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) {
unregister_netdevice_notifier(&bpq_dev_notifier);
-#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_AX25_BPQETHER);
-#endif
+ proc_net_remove ("bpqether");
for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next)
unregister_netdev(&bpq->axdev);
}
#ifdef CONFIG_PROC_FS
-
-struct proc_dir_entry scc_proc_dir_entry =
-{
- PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0,
- &proc_net_inode_operations, scc_net_get_info
-};
-
-#define scc_net_procfs_init() proc_net_register(&scc_proc_dir_entry);
-#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530);
+#define scc_net_procfs_init() proc_net_create("z8530drv",0,scc_net_get_info)
+#define scc_net_procfs_remove() proc_net_remove("z8530drv")
#else
#define scc_net_procfs_init()
#define scc_net_procfs_remove()
}
#ifdef CONFIG_INET
-
-#ifndef PROC_NET_YAM
-#define PROC_NET_YAM (PROC_NET_LAST+10) /* Sorry again... */
-#endif
-
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry yam_proc_dir_entry =
-{
- PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0,
- &proc_net_inode_operations, yam_net_get_info
-};
-
-#define yam_net_procfs_init() proc_net_register(&yam_proc_dir_entry);
-#define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM);
+#define yam_net_procfs_init() proc_net_create("yam",0,yam_net_get_info)
+#define yam_net_procfs_remove() proc_net_remove("yam")
#else
#define yam_net_procfs_init()
#define yam_net_procfs_remove()
-#endif
+#endif /* CONFIG_PROC_FS */
#else
#define yam_net_procfs_init()
#define yam_net_procfs_remove()
-#endif
+#endif /* CONFIG_INET */
/* --------------------------------------------------------------------- */
#include <linux/if_arp.h>
#include <linux/if_strip.h>
#include <linux/proc_fs.h>
-#include <linux/serialP.h>
#include <linux/serial.h>
+#include <linux/serialP.h>
#include <net/arp.h>
#include <linux/ip.h>
return(calc_start_len(buffer, start, req_offset, req_len, total, buf));
}
-static const char proc_strip_status_name[] = "strip";
-
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_strip_get_status_info =
-{
- PROC_NET_STRIP_STATUS, /* unsigned short low_ino */
- sizeof(proc_strip_status_name)-1, /* unsigned short namelen */
- proc_strip_status_name, /* const char *name */
- S_IFREG | S_IRUGO, /* mode_t mode */
- 1, /* nlink_t nlink */
- 0, 0, 0, /* uid_t uid, gid_t gid, unsigned long size */
- &proc_net_inode_operations, /* struct inode_operations * ops */
- &get_status_info, /* int (*get_info)(...) */
- NULL, /* void (*fill_inode)(struct inode *); */
- NULL, NULL, NULL, /* struct proc_dir_entry *next, *parent, *subdir; */
- NULL /* void *data; */
-};
-#endif /* CONFIG_PROC_FS */
-
/************************************************************************/
/* Sending routines */
/*
* Register the status file with /proc
*/
-#ifdef CONFIG_PROC_FS
- if (proc_net_register(&proc_strip_get_status_info) != 0)
- {
- printk(KERN_ERR "strip: status proc_net_register() failed.\n");
- }
-#endif
+ proc_net_create ("strip", S_IFREG | S_IRUGO, get_status_info);
#ifdef MODULE
return status;
strip_free(struct_strip_list);
/* Unregister with the /proc/net file here. */
-#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_STRIP_STATUS);
-#endif
+ proc_net_remove ("strip");
if ((i = tty_register_ldisc(N_STRIP, NULL)))
printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
- memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+ isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
#else
- ((unsigned int*)hdr)[0] = readl(hdr_start);
+ ((unsigned int*)hdr)[0] = isa_readl(hdr_start);
#endif
}
if (xfer_start + count > dev->rmem_end) {
/* We must wrap the input move. */
int semi_count = dev->rmem_end - xfer_start;
- memcpy_fromio(skb->data, xfer_start, semi_count);
+ isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ isa_eth_io_copy_and_csum(skb, xfer_start, count, 0);
}
/* Turn off 16 bit access so that reboot works. ISA brain-damage */
if (ei_status.word16) {
/* Turn on and off 16 bit access so that reboot works. */
outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
- memcpy_toio(shmem, buf, count);
+ isa_memcpy_toio(shmem, buf, count);
outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
} else
- memcpy_toio(shmem, buf, count);
+ isa_memcpy_toio(shmem, buf, count);
}
return strlen(ptr);
}
-/* We're going to have to be a bit more sophisticated about this, I
- think, because it doesn't really seem to work right when you do a
- full listing of boards and devices */
-int get_nubus_list(char *buf)
+static int nubus_read_proc(char *buf, char **start, off_t off,
+ int count, int *eof, void *data)
{
- int nprinted, len, size;
- struct nubus_board* board;
-#define MSG "\nwarning: page-size limit reached!\n"
-
- /* reserve same for truncation warning message: */
- size = PAGE_SIZE - (strlen(MSG) + 1);
- len = sprintf(buf, "Nubus boards found:\n");
+ int nprinted, len, begin = 0;
+ int slot;
+ len = sprintf(buf, "Nubus devices found:\n");
/* Walk the list of NuBus boards */
for (board = nubus_boards; board != NULL; board = board->next)
{
nprinted = sprint_nubus_board(board, buf + len, size - len);
- if (nprinted < 0) {
- return len + sprintf(buf + len, MSG);
- }
+ if (nprinted < 0)
+ break;
len += nprinted;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ if (len+begin >= off+count)
+ break;
}
+ if (slot==16 || len+begin < off)
+ *eof = 1;
+ off -= begin;
+ *strat = buf + off;
+ len -= off;
+ if (len>count)
+ len = count;
+ if (len<0)
+ len = 0;
return len;
}
-
-static struct proc_dir_entry proc_old_nubus = {
- PROC_NUBUS, 5, "nubus",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif /* CONFIG_PROC_FS */
+#endif
void __init nubus_scan_bus(void)
{
nubus_scan_bus();
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &proc_old_nubus);
+ create_proc_read_entry("nubus", 0, NULL, nubus_read_proc, NULL);
nubus_proc_init();
#endif
}
return (count > cnt) ? cnt : count;
}
-static struct proc_dir_entry proc_nubus_devices = {
- PROC_BUS_NUBUS_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- get_nubus_dev_info
-};
-
static struct proc_dir_entry *proc_bus_nubus_dir;
static void nubus_proc_subdir(struct nubus_dev* dev,
if (!MACH_IS_MAC)
return;
proc_bus_nubus_dir = create_proc_entry("nubus", S_IFDIR, proc_bus);
- proc_register(proc_bus_nubus_dir, &proc_nubus_devices);
+ create_proc_info_entry("devices", 0, proc_bus_nubus_dir,
+ get_nubus_dev_info);
proc_bus_nubus_add_devices();
}
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_simple_probe);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_detach_device);
return (count > cnt) ? cnt : count;
}
-static struct proc_dir_entry proc_pci_devices = {
- PROC_BUS_PCI_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- get_pci_dev_info
-};
-
static struct proc_dir_entry *proc_bus_pci_dir;
int pci_proc_attach_device(struct pci_dev *dev)
return len;
}
-
-static struct proc_dir_entry proc_old_pci = {
- PROC_PCI, 3, "pci",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-
/*
* Return list of PCI devices as a character string for /proc/pci.
* BUF is a buffer that is PAGE_SIZE bytes long.
*/
-int get_pci_list(char *buf)
+static int pci_read_proc(char *buf, char **start, off_t off,
+ int count, int *eof, void *data)
{
- int nprinted, len, size;
+ int nprinted, len, begin = 0;
struct pci_dev *dev;
-# define MSG "\nwarning: page-size limit reached!\n"
- /* reserve same for truncation warning message: */
- size = PAGE_SIZE - (strlen(MSG) + 1);
len = sprintf(buf, "PCI devices found:\n");
for (dev = pci_devices; dev; dev = dev->next) {
- nprinted = sprint_dev_config(dev, buf + len, size - len);
- if (nprinted < 0) {
- len += sprintf(buf + len, MSG);
- proc_old_pci.size = len;
- return len;
- }
+ nprinted = sprint_dev_config(dev, buf + len, count - len);
+ if (nprinted < 0)
+ break;
len += nprinted;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ if (len+begin >= off+count)
+ break;
}
- proc_old_pci.size = len;
+ if (!dev || len+begin < off)
+ *eof = 1;
+ off -= begin;
+ *start = buf + off;
+ len -= off;
+ if (len>count)
+ len = count;
+ if (len<0)
+ len = 0;
return len;
}
{
if (pci_present()) {
proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus);
- proc_register(proc_bus_pci_dir, &proc_pci_devices);
+ create_proc_info_entry("devices",0, proc_bus_pci_dir,
+ get_pci_dev_info);
proc_bus_pci_add(pci_root);
- proc_register(&proc_root, &proc_old_pci);
+ create_proc_read_entry("pci", 0, NULL, pci_read_proc, NULL);
}
return 0;
}
* replaced current->state = x with set_current_state(x)
* 03.09.99 0.30 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
+ * 28.10.99 0.31 More waitqueue races fixed
*
* some important things missing in Ensoniq documentation:
*
if (s->dma_dac1.mapped || !s->dma_dac1.ready)
return 0;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac1.wait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
if (s->dma_dac2.mapped || !s->dma_dac2.ready)
return 0;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac2.wait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
static ssize_t es1370_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct es1370_state *s = (struct es1370_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
+ add_wait_queue(&s->dma_adc.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
swptr = s->dma_adc.swptr;
cnt = s->dma_adc.dmasize-swptr;
if (s->dma_adc.count < cnt)
cnt = s->dma_adc.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_adc.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
ret += cnt;
start_adc(s);
}
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct es1370_state *s = (struct es1370_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
ret = 0;
+ add_wait_queue(&s->dma_dac2.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac2.count < 0) {
cnt = s->dma_dac2.dmasize-swptr;
if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac2(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac2.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac2.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac2.swptr = swptr;
ret += cnt;
start_dac2(s);
}
+ remove_wait_queue(&s->dma_dac2.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static int es1370_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1370_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
dealloc_dmabuf(&s->dma_adc);
}
s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct es1370_state *s = (struct es1370_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret = 0;
unsigned long flags;
unsigned swptr;
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
+ add_wait_queue(&s->dma_dac1.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac1.count < 0) {
cnt = s->dma_dac1.dmasize-swptr;
if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac1(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac1.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac1.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac1.swptr = swptr;
ret += cnt;
start_dac1(s);
}
+ remove_wait_queue(&s->dma_dac1.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static int es1370_open_dac(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1370_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
stop_dac1(s);
dealloc_dmabuf(&s->dma_dac1);
s->open_mode &= ~FMODE_DAC;
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
cnt = MIDIINBUF - ptr;
if (s->midi.icnt < cnt)
cnt = s->midi.icnt;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
cnt = MIDIOUTBUF - ptr;
if (s->midi.ocnt + cnt > MIDIOUTBUF)
cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0)
+ if (cnt <= 0) {
+ __set_current_state(TASK_INTERRUPTIBLE);
es1370_handle_midi(s);
+ }
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
static int es1370_midi_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1370_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
outl(s->ctrl, s->io+ES1370_REG_CONTROL);
}
spin_unlock_irqrestore(&s->lock, flags);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
if (!RSRCISIOREGION(pcidev, 0))
* replaced current->state = x with set_current_state(x)
* 03.09.99 0.18 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
- *
+ * 21.10.99 0.19 Round sampling rates, requested by
+ * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
+ * 27.10.99 0.20 Added SigmaTel 3D enhancement string
+ * Codec ID printing changes
+ * 28.10.99 0.21 More waitqueue races fixed
+ * Joe Cotellese <joec@ensoniq.com>
+ * Changed PCI detection routine so we can more easily
+ * detect ES137x chip and derivatives.
*/
/*****************************************************************************/
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
#define ES1371_DEBUG
+#define DBG(x) {}
+/*#define DBG(x) {x}*/
/* --------------------------------------------------------------------- */
#ifndef PCI_VENDOR_ID_ENSONIQ
#define PCI_VENDOR_ID_ENSONIQ 0x1274
#endif
+
+#ifndef PCI_VENDOR_ID_ECTIVA
+#define PCI_VENDOR_ID_ECTIVA 0x1102
+#endif
+
#ifndef PCI_DEVICE_ID_ENSONIQ_ES1371
#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
#endif
+#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880
+#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880
+#endif
+
+#ifndef PCI_DEVICE_ID_ECTIVA_EV1938
+#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
+#endif
+
/* ES1371 chip ID */
/* This is a little confusing because all ES1371 compatible chips have the
same DEVICE_ID, the only thing differentiating them is the REV_ID field.
#define ES1371REV_ES1373_A 0x04
#define ES1371REV_ES1373_B 0x06
#define ES1371REV_CT5880_A 0x07
+#define CT5880REV_CT5880_C 0x02
#define ES1371REV_ES1371_B 0x09
-
+#define EV1938REV_EV1938_A 0x00
#define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
#define JOY_EXTENT 8
#define ES1371_REG_CONTROL 0x00
-#define ES1371_REG_STATUS 0x04
+#define ES1371_REG_STATUS 0x04 /* on the 5880 it is control/status */
#define ES1371_REG_UART_DATA 0x08
#define ES1371_REG_UART_STATUS 0x09
#define ES1371_REG_UART_CONTROL 0x09
#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
+#define CSTAT_5880_AC97_RST 0x20000000 /* CT5880 Reset bit */
#define STAT_EN_SPDIF 0x00040000 /* enable S/PDIF circuitry */
#define STAT_TS_SPDIF 0x00020000 /* test S/PDIF circuitry */
#define STAT_TESTMODE 0x00010000 /* test ASIC */
"NVidea 3D Stereo Enhancement",
"Philips Incredible Sound",
"Texas Instruments 3D Stereo Enhancement",
- "VLSI Technology 3D Stereo Enhancement"
+ "VLSI Technology 3D Stereo Enhancement",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SigmaTel SS3D"
};
/* --------------------------------------------------------------------- */
/* hardware resources */
unsigned long io; /* long for SPARC */
unsigned int irq;
+
+ /* PCI ID's */
+ u16 vendor;
+ u16 device;
u8 rev; /* the chip revision */
-
+
#ifdef ES1371_DEBUG
/* debug /proc entry */
struct proc_dir_entry *ps;
rate = 48000;
if (rate < 4000)
rate = 4000;
- freq = (rate << 15) / 3000;
- s->dac1rate = (freq * 3000) >> 15;
+ freq = ((rate << 15) + 1500) / 3000;
+ s->dac1rate = (freq * 3000 + 16384) >> 15;
spin_lock_irqsave(&s->lock, flags);
r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1;
outl(r, s->io + ES1371_REG_SRCONV);
rate = 48000;
if (rate < 4000)
rate = 4000;
- freq = (rate << 15) / 3000;
- s->dac2rate = (freq * 3000) >> 15;
- printk (KERN_DEBUG "dac2 freq: %d\n", freq);
+ freq = ((rate << 15) + 1500) / 3000;
+ s->dac2rate = (freq * 3000 + 16384) >> 15;
spin_lock_irqsave(&s->lock, flags);
r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
outl(r, s->io + ES1371_REG_SRCONV);
if (s->dma_dac1.mapped || !s->dma_dac1.ready)
return 0;
-
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac1.wait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
+ DBG(printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
set_current_state(TASK_RUNNING);
if (s->dma_dac2.mapped || !s->dma_dac2.ready)
return 0;
-
- __set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&s->dma_dac2.wait, &wait);
for (;;) {
+ __set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
+ DBG(printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
set_current_state(TASK_RUNNING);
static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct es1371_state *s = (struct es1371_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
+ add_wait_queue(&s->dma_adc.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
swptr = s->dma_adc.swptr;
cnt = s->dma_adc.dmasize-swptr;
if (s->dma_adc.count < cnt)
cnt = s->dma_adc.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_adc.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
ret += cnt;
start_adc(s);
}
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct es1371_state *s = (struct es1371_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
ret = 0;
+ add_wait_queue(&s->dma_dac2.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac2.count < 0) {
cnt = s->dma_dac2.dmasize-swptr;
if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac2(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac2.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac2.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac2.swptr = swptr;
ret += cnt;
start_dac2(s);
}
+ remove_wait_queue(&s->dma_dac2.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
if (file->f_mode & FMODE_WRITE) {
stop_dac2(s);
s->dma_dac2.ready = 0;
- printk (KERN_DEBUG "es137x: setting DAC2 rate: %d\n", val);
set_dac2_rate(s, val);
}
}
static int es1371_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1371_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct es1371_state *s = (struct es1371_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret = 0;
unsigned long flags;
unsigned swptr;
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
+ add_wait_queue(&s->dma_dac1.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac1.count < 0) {
cnt = s->dma_dac1.dmasize-swptr;
if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac1(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac1.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac1.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac1.swptr = swptr;
ret += cnt;
start_dac1(s);
}
+ remove_wait_queue(&s->dma_dac1.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static int es1371_open_dac(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1371_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
cnt = MIDIINBUF - ptr;
if (s->midi.icnt < cnt)
cnt = s->midi.icnt;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
cnt = MIDIOUTBUF - ptr;
if (s->midi.ocnt + cnt > MIDIOUTBUF)
cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0)
+ if (cnt <= 0) {
+ __set_current_state(TASK_INTERRUPTIBLE);
es1371_handle_midi(s);
+ }
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
static int es1371_midi_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct es1371_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-
-static int __init init_es1371(void)
+static int __init probe_chip(struct pci_dev *pcidev, int index)
{
struct es1371_state *s;
- struct pci_dev *pcidev = NULL;
mm_segment_t fs;
- int i, val, val2, index = 0;
- unsigned cssr;
-
- if (!pci_present()) /* No PCI bus in this machine! */
- return -ENODEV;
- printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n");
- while (index < NR_DEVICE &&
- (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
- if (!RSRCISIOREGION(pcidev, 0))
- continue;
- if (pcidev->irq == 0)
- continue;
- if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
- printk(KERN_WARNING "es1371: out of memory\n");
- continue;
- }
- memset(s, 0, sizeof(struct es1371_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac1.wait);
- init_waitqueue_head(&s->dma_dac2.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- init_MUTEX(&s->open_sem);
- spin_lock_init(&s->lock);
- s->magic = ES1371_MAGIC;
- s->io = RSRCADDRESS(pcidev, 0);
- s->irq = pcidev->irq;
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
- if (check_region(s->io, ES1371_EXTENT)) {
- printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
- goto err_region;
- }
- request_region(s->io, ES1371_EXTENT, "es1371");
- if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
- printk(KERN_ERR "es1371: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n"
- KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]);
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)
- goto err_dev2;
- if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0)
- goto err_dev3;
- if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
- goto err_dev4;
+ int i, val, val2;
+ unsigned char id[4];
+ unsigned long tmo;
+ signed long tmo2;
+ unsigned int cssr;
+
+ if (!RSRCISIOREGION(pcidev, 0))
+ return -1;
+ if (pcidev->irq == 0)
+ return -1;
+ if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
+ printk(KERN_WARNING "es1371: out of memory\n");
+ return -1;
+ }
+ memset(s, 0, sizeof(struct es1371_state));
+ init_waitqueue_head(&s->dma_adc.wait);
+ init_waitqueue_head(&s->dma_dac1.wait);
+ init_waitqueue_head(&s->dma_dac2.wait);
+ init_waitqueue_head(&s->open_wait);
+ init_waitqueue_head(&s->midi.iwait);
+ init_waitqueue_head(&s->midi.owait);
+ init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
+ s->magic = ES1371_MAGIC;
+ s->io = RSRCADDRESS(pcidev, 0);
+ s->irq = pcidev->irq;
+ s->vendor = pcidev->vendor;
+ s->device = pcidev->device;
+ pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
+ printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n",
+ s->vendor, s->device, s->rev);
+ if (check_region(s->io, ES1371_EXTENT)) {
+ printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
+ goto err_region;
+ }
+ request_region(s->io, ES1371_EXTENT, "es1371");
+ if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
+ printk(KERN_ERR "es1371: irq %u in use\n", s->irq);
+ goto err_irq;
+ }
+ printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n"
+ KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]);
+ /* register devices */
+ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
+ goto err_dev1;
+ if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)
+ goto err_dev2;
+ if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0)
+ goto err_dev3;
+ if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
+ goto err_dev4;
#ifdef ES1371_DEBUG
- /* intialize the debug proc device */
- s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
- if (s->ps)
- s->ps->read_proc = proc_es1371_dump;
+ /* intialize the debug proc device */
+ s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
+ if (s->ps)
+ s->ps->read_proc = proc_es1371_dump;
#endif /* ES1371_DEBUG */
-
- /* initialize codec registers */
- s->ctrl = 0;
- if ((joystick[index] & ~0x18) == 0x200) {
- if (check_region(joystick[index], JOY_EXTENT))
- printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]);
- else {
- s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
- }
- }
- s->sctrl = 0;
- cssr = 0;
- /* check to see if s/pdif mode is being requested */
- if (spdif[index]) {
- if (s->rev >= 4) {
- printk(KERN_INFO "es1371: enabling S/PDIF output\n");
- cssr |= STAT_EN_SPDIF;
- s->ctrl |= CTRL_SPDIFEN_B;
- } else {
- printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
- }
+
+ /* initialize codec registers */
+ s->ctrl = 0;
+ if ((joystick[index] & ~0x18) == 0x200) {
+ if (check_region(joystick[index], JOY_EXTENT))
+ printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]);
+ else {
+ s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
}
- /* initialize the chips */
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
- outl(0, s->io+ES1371_REG_LEGACY);
- pci_set_master(pcidev); /* enable bus mastering */
- /* AC97 warm reset to start the bitclk */
- outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL);
- udelay(2);
- outl(s->ctrl, s->io+ES1371_REG_CONTROL);
- /* init the sample rate converter */
- src_init(s);
- /* codec init */
- wrcodec(s, AC97_RESET, 0); /* reset codec */
- s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */
- val = rdcodec(s, AC97_VENDOR_ID1);
- val2 = rdcodec(s, AC97_VENDOR_ID2);
- printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n",
- (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff);
- printk(KERN_INFO "es1371: codec features");
- if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC)
- printk(" dedicated MIC PCM in");
- if (s->mix.codec_id & CODEC_ID_MODEMCODEC)
- printk(" Modem Line Codec");
- if (s->mix.codec_id & CODEC_ID_BASSTREBLE)
- printk(" Bass & Treble");
- if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO)
- printk(" Simulated Stereo");
- if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT)
- printk(" Headphone out");
- if (s->mix.codec_id & CODEC_ID_LOUDNESS)
- printk(" Loudness");
- if (s->mix.codec_id & CODEC_ID_18BITDAC)
- printk(" 18bit DAC");
- if (s->mix.codec_id & CODEC_ID_20BITDAC)
- printk(" 20bit DAC");
- if (s->mix.codec_id & CODEC_ID_18BITADC)
- printk(" 18bit ADC");
- if (s->mix.codec_id & CODEC_ID_20BITADC)
- printk(" 20bit ADC");
- printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
- val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
- printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown");
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ s->sctrl = 0;
+ cssr = 0;
+ /* check to see if s/pdif mode is being requested */
+ if (spdif[index]) {
+ if (s->rev >= 4) {
+ printk(KERN_INFO "es1371: enabling S/PDIF output\n");
+ cssr |= STAT_EN_SPDIF;
+ s->ctrl |= CTRL_SPDIFEN_B;
+ } else {
+ printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
}
- set_fs(fs);
- /* turn on S/PDIF output driver if requested */
+ }
+ /* initialize the chips */
+ outl(s->ctrl, s->io+ES1371_REG_CONTROL);
+ outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
+ outl(0, s->io+ES1371_REG_LEGACY);
+ pci_set_master(pcidev); /* enable bus mastering */
+ /* if we are a 5880 turn on the AC97 */
+ if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
+ s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 &&
+ s->rev == CT5880REV_CT5880_C) {
+ cssr |= CSTAT_5880_AC97_RST;
outl(cssr, s->io+ES1371_REG_STATUS);
- /* queue it for later freeing */
- s->next = devs;
- devs = s;
- index++;
- continue;
+ /* need to delay around 20ms(bleech) to give
+ some CODECs enough time to wakeup */
+ tmo = jiffies + (HZ / 50) + 1;
+ for (;;) {
+ tmo2 = tmo - jiffies;
+ if (tmo2 <= 0)
+ break;
+ schedule_timeout(tmo2);
+ }
+ }
+ /* AC97 warm reset to start the bitclk */
+ outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL);
+ udelay(2);
+ outl(s->ctrl, s->io+ES1371_REG_CONTROL);
+ /* init the sample rate converter */
+ src_init(s);
+ /* codec init */
+ wrcodec(s, AC97_RESET, 0); /* reset codec */
+ s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */
+ val = rdcodec(s, AC97_VENDOR_ID1);
+ val2 = rdcodec(s, AC97_VENDOR_ID2);
+ id[0] = val >> 8;
+ id[1] = val;
+ id[2] = val2 >> 8;
+ id[3] = 0;
+ if (id[0] <= ' ' || id[0] > 0x7f)
+ id[0] = ' ';
+ if (id[1] <= ' ' || id[1] > 0x7f)
+ id[1] = ' ';
+ if (id[2] <= ' ' || id[2] > 0x7f)
+ id[2] = ' ';
+ printk(KERN_INFO "es1371: codec vendor %s (0x%04x%02x) revision %d (0x%02x)\n",
+ id, val & 0xffff, (val2 >> 8) & 0xff, val2 & 0xff, val2 & 0xff);
+ printk(KERN_INFO "es1371: codec features");
+ if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC)
+ printk(" dedicated MIC PCM in");
+ if (s->mix.codec_id & CODEC_ID_MODEMCODEC)
+ printk(" Modem Line Codec");
+ if (s->mix.codec_id & CODEC_ID_BASSTREBLE)
+ printk(" Bass & Treble");
+ if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO)
+ printk(" Simulated Stereo");
+ if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT)
+ printk(" Headphone out");
+ if (s->mix.codec_id & CODEC_ID_LOUDNESS)
+ printk(" Loudness");
+ if (s->mix.codec_id & CODEC_ID_18BITDAC)
+ printk(" 18bit DAC");
+ if (s->mix.codec_id & CODEC_ID_20BITDAC)
+ printk(" 20bit DAC");
+ if (s->mix.codec_id & CODEC_ID_18BITADC)
+ printk(" 18bit ADC");
+ if (s->mix.codec_id & CODEC_ID_20BITADC)
+ printk(" 20bit ADC");
+ printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
+ val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
+ printk(KERN_INFO "es1371: stereo enhancement: %s\n",
+ (val <= 26 && stereo_enhancement[val]) ? stereo_enhancement[val] : "unknown");
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ val = SOUND_MASK_LINE;
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ val = initvol[i].vol;
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ set_fs(fs);
+ /* turn on S/PDIF output driver if requested */
+ outl(cssr, s->io+ES1371_REG_STATUS);
+ /* queue it for later freeing */
+ s->next = devs;
+ devs = s;
+ return 0;
+
+ err_dev4:
+ unregister_sound_dsp(s->dev_dac);
+ err_dev3:
+ unregister_sound_mixer(s->dev_mixer);
+ err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+ printk(KERN_ERR "es1371: cannot register misc device\n");
+ free_irq(s->irq, s);
+ err_irq:
+ release_region(s->io, ES1371_EXTENT);
+ err_region:
+ kfree_s(s, sizeof(struct es1371_state));
+ return -1;
+}
- err_dev4:
- unregister_sound_dsp(s->dev_dac);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "es1371: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->io, ES1371_EXTENT);
- err_region:
- kfree_s(s, sizeof(struct es1371_state));
+
+static int __init init_es1371(void)
+{
+ struct pci_dev *pcidev = NULL;
+ int index = 0;
+
+ if (!pci_present()) /* No PCI bus in this machine! */
+ return -ENODEV;
+ printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) {
+ if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) {
+ if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 &&
+ pcidev->device != PCI_DEVICE_ID_ENSONIQ_CT5880)
+ continue;
+ } else if (pcidev->vendor == PCI_VENDOR_ID_ECTIVA) {
+ if (pcidev->device != PCI_DEVICE_ID_ECTIVA_EV1938)
+ continue;
+ } else
+ continue;
+ if (!probe_chip(pcidev, index))
+ index++;
}
if (!devs)
return -ENODEV;
* OSS more closely; remove possible wakeup race
* 07.10.99 0.9 Fix initialization; complain if sequencer writes time out
* Revised resource grabbing for the FM synthesizer
+ * 28.10.99 0.10 More waitqueue races fixed
*
*/
#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
-#define DDMABASE_OFFSET 0x10 /* chip bug workaround kludge */
+#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */
#define DDMABASE_EXTENT 16
#define IOBASE_EXTENT 16
if (s->dma_dac.mapped)
return 0;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct solo1_state *s = (struct solo1_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
+ add_wait_queue(&s->dma_adc.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
swptr = s->dma_adc.swptr;
cnt = s->dma_adc.dmasize-swptr;
if (s->dma_adc.count < cnt)
cnt = s->dma_adc.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
#endif
if (inb(s->ddmabase+15) & 1)
printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
#ifdef DEBUGREC
printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
#endif
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_adc.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
#endif
}
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct solo1_state *s = (struct solo1_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
#endif
ret = 0;
+ add_wait_queue(&s->dma_dac.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac.count < 0) {
cnt = s->dma_dac.dmasize-swptr;
if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac.swptr = swptr;
ret += cnt;
start_dac(s);
}
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
dealloc_dmabuf(&s->dma_adc);
}
s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
static int solo1_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct solo1_state *s = devs;
while (s && ((s->dev_audio ^ minor) & ~0xf))
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
cnt = MIDIINBUF - ptr;
if (s->midi.icnt < cnt)
cnt = s->midi.icnt;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
cnt = MIDIOUTBUF - ptr;
if (s->midi.ocnt + cnt > MIDIOUTBUF)
cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0)
+ if (cnt <= 0) {
+ __set_current_state(TASK_INTERRUPTIBLE);
solo1_handle_midi(s);
+ }
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
static int solo1_midi_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct solo1_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
del_timer(&s->midi.timer);
}
spin_unlock_irqrestore(&s->lock, flags);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
static int solo1_dmfm_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct solo1_state *s = devs;
while (s && s->dev_dmfm != minor)
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
outb(0, s->sbbase+3);
}
release_region(s->sbbase, FMSYNTH_EXTENT);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.10 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
if (!RSRCISIOREGION(pcidev, 0) ||
* replaced current->state = x with set_current_state(x)
* 03.09.99 0.21 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
+ * 28.10.99 0.22 More waitqueue races fixed
*
*/
if (s->dma_dac.mapped || !s->dma_dac.ready)
return 0;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct sv_state *s = (struct sv_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
return -EFAULT;
ret = 0;
#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
+ spin_lock_irqsave(&s->lock, flags);
+ sv_update_ptr(s);
+ spin_unlock_irqrestore(&s->lock, flags);
#endif
+ add_wait_queue(&s->dma_adc.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
swptr = s->dma_adc.swptr;
cnt = s->dma_adc.dmasize-swptr;
if (s->dma_adc.count < cnt)
cnt = s->dma_adc.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ if (!schedule_timeout(HZ)) {
printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
s->dma_adc.hwptr, s->dma_adc.swptr);
s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
spin_unlock_irqrestore(&s->lock, flags);
}
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_adc.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
ret += cnt;
start_adc(s);
}
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t sv_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct sv_state *s = (struct sv_state *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
unsigned long flags;
unsigned swptr;
return -EFAULT;
ret = 0;
#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
+ spin_lock_irqsave(&s->lock, flags);
+ sv_update_ptr(s);
+ spin_unlock_irqrestore(&s->lock, flags);
#endif
+ add_wait_queue(&s->dma_dac.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac.count < 0) {
cnt = s->dma_dac.dmasize-swptr;
if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
cnt = s->dma_dac.dmasize - s->dma_dac.count;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ if (!schedule_timeout(HZ)) {
printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
s->dma_dac.hwptr, s->dma_dac.swptr);
s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
spin_unlock_irqrestore(&s->lock, flags);
}
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
continue;
}
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
+ if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
swptr = (swptr + cnt) % s->dma_dac.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_dac.swptr = swptr;
ret += cnt;
start_dac(s);
}
+ remove_wait_queue(&s->dma_dac.wait, &wait);
+ set_current_state(TASK_RUNNING);
return ret;
}
static int sv_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct sv_state *s = devs;
unsigned char fmtm = ~0, fmts = 0;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
dealloc_dmabuf(&s->dma_adc);
}
s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
cnt = MIDIINBUF - ptr;
if (s->midi.icnt < cnt)
cnt = s->midi.icnt;
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
cnt = MIDIOUTBUF - ptr;
if (s->midi.ocnt + cnt > MIDIOUTBUF)
cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0)
+ if (cnt <= 0) {
+ __set_current_state(TASK_INTERRUPTIBLE);
sv_handle_midi(s);
+ }
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
static int sv_midi_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct sv_state *s = devs;
unsigned long flags;
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
del_timer(&s->midi.timer);
}
spin_unlock_irqrestore(&s->lock, flags);
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
static int sv_dmfm_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
struct sv_state *s = devs;
while (s && s->dev_dmfm != minor)
up(&s->open_sem);
return -EBUSY;
}
+ add_wait_queue(&s->open_wait, &wait);
+ __set_current_state(TASK_INTERRUPTIBLE);
up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
+ schedule();
+ remove_wait_queue(&s->open_wait, &wait);
+ set_current_state(TASK_RUNNING);
if (signal_pending(current))
return -ERESTARTSYS;
down(&s->open_sem);
outb(regb, s->iosynth+2);
outb(0, s->iosynth+3);
}
- up(&s->open_sem);
wake_up(&s->open_wait);
+ up(&s->open_sem);
MOD_DEC_USE_COUNT;
return 0;
}
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
return len;
}
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_root_sound = {
- PROC_SOUND, 5, "sound",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL, sound_proc_get_info
-};
-#endif
-
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
/* printk("Sound: mmap() called twice for the same DMA buffer\n");*/
return -EIO;
}
- if (vma->vm_offset != 0)
+ if (vma->vm_pgoff != 0)
{
/* printk("Sound: mmap() offset must be 0.\n");*/
return -EINVAL;
}
#endif
#ifdef CONFIG_PROC_FS
- if (proc_register(&proc_root, &proc_root_sound))
+ if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info))
printk(KERN_ERR "sound: registering /proc/sound failed\n");
#endif
}
{
return;
}
-#ifdef CONFIG_PROC_FS
- if (proc_unregister(&proc_root, PROC_SOUND))
- printk(KERN_ERR "sound: unregistering /proc/sound failed\n");
-#endif
+ remove_proc_entry("sound", NULL);
if (chrdev_registered)
destroy_special_devices();
#define CTRL_STAT_DTR 1
#define CTRL_STAT_RTS 2
+static struct usb_driver acm_driver;
+
static int acm_refcount;
static struct tty_driver acm_tty_driver;
struct acm_state {
struct usb_device *dev; //the coresponding usb device
+ int cfgnum; //configuration number on this device
struct tty_struct *tty; //the coresponding tty
char present; //a device for this struct was detected => this tty is used
char active; //someone has this acm's device open
info("ACM_READ_IRQ: state %d, %d bytes\n", state, count);
if (state) {
printk( "acm_read_irq: strange state received: %x\n", state );
- return 1;
+ return 0;
}
if (!ACM_READY)
tty_insert_flip_char(tty,data[i],0);
tty_flip_buffer_push(tty);
- return 1; /* continue transfer */
+ return 0; /* Never return 1 from this routine. It makes uhci do bad things. */
}
static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
return -1;
}
-static int acm_probe(struct usb_device *dev)
+static void * acm_probe(struct usb_device *dev, unsigned int ifnum)
{
struct acm_state *acm;
struct usb_interface_descriptor *interface;
if (0>(acmno=get_free_acm())) {
info("Too many acm devices connected\n");
- return -1;
+ return NULL;
}
acm = &acm_state_table[acmno];
if (dev->descriptor.bDeviceClass != 2 ||
dev->descriptor.bDeviceSubClass != 0 ||
dev->descriptor.bDeviceProtocol != 0)
- return -1;
+ return NULL;
#define IFCLASS(if) ((if->bInterfaceClass << 24) | (if->bInterfaceSubClass << 16) | (if->bInterfaceProtocol << 8) | (if->bNumEndpoints))
+ /* FIXME: should the driver really be doing the configuration
+ * selecting or should the usbcore? [different configurations
+ * can have different bandwidth requirements] -greg */
+
/* Now scan all configs for a ACM configuration*/
for (cfgnum=0;cfgnum<dev->descriptor.bNumConfigurations;cfgnum++) {
/* The first one should be Communications interface? */
interface->bNumEndpoints != 2)
continue;
- /* if ((endpoint->bEndpointAddress & 0x80) == 0x80) */
+ /* make sure both interfaces are available for our use */
+ if (usb_interface_claimed(&dev->config[cfgnum].interface[0]) ||
+ usb_interface_claimed(&dev->config[cfgnum].interface[1])) {
+ printk("usb-acm: required interface already has a driver\n");
+ continue;
+ }
+
+ endpoint = &interface->endpoint[0];
if ((endpoint->bEndpointAddress & 0x80) != 0x80)
swapped = 1;
usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
acm->dev=dev;
- dev->private=acm;
acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].bEndpointAddress;
acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp);
acm->reading=0;
if (!acm->readbuffer) {
printk("ACM: Couldn't allocate readbuffer\n");
- return -1;
+ return NULL;
}
acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress;
if (!acm->writebuffer) {
printk("ACM: Couldn't allocate writebuffer\n");
kfree(acm->readbuffer);
- return -1;
+ return NULL;
}
acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress;
acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp);
acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval;
+ acm->cfgnum = cfgnum;
acm->present=1;
MOD_INC_USE_COUNT;
- return 0;
+
+ usb_driver_claim_interface(&acm_driver,
+ &dev->config[cfgnum].interface[0], acm);
+ usb_driver_claim_interface(&acm_driver,
+ &dev->config[cfgnum].interface[1], acm);
+ return acm;
}
- return -1;
+ return NULL;
}
-static void acm_disconnect(struct usb_device *dev)
+static void acm_disconnect(struct usb_device *dev, void *ptr)
{
- struct acm_state *acm = (struct acm_state *) dev->private;
+ struct acm_state *acm = ptr;
info("acm_disconnect\n");
kfree(acm->writebuffer);
kfree(acm->readbuffer);
+ /* release the interfaces so that other drivers can have at them */
+ usb_driver_release_interface(&acm_driver,
+ &dev->config[acm->cfgnum].interface[0]);
+ usb_driver_release_interface(&acm_driver,
+ &dev->config[acm->cfgnum].interface[1]);
+
MOD_DEC_USE_COUNT;
}
acm=&acm_state_table[i];
if (acm->present) {
printk("disconnecting %d\n",i);
- acm_disconnect(acm->dev);
+ acm_disconnect(acm->dev, acm);
}
}
tty_unregister_driver(&acm_tty_driver);
i = u->flags;
spin_unlock_irqrestore(&as->lock, flags);
while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
+ if (signal_pending(current)) {
+ if (i & FLG_ID0RUNNING)
+ usb_kill_isoc(u->dataiso[0]);
+ if (i & FLG_ID1RUNNING)
+ usb_kill_isoc(u->dataiso[1]);
+ if (i & FLG_SYNC0RUNNING)
+ usb_kill_isoc(u->synciso[0]);
+ if (i & FLG_SYNC1RUNNING)
+ usb_kill_isoc(u->synciso[1]);
+ break;
+ }
spin_lock_irqsave(&as->lock, flags);
i = u->flags;
spin_unlock_irqrestore(&as->lock, flags);
}
+ set_current_state(TASK_RUNNING);
if (u->dataiso[0])
usb_free_isoc(u->dataiso[0]);
if (u->dataiso[1])
printk(KERN_DEBUG "usbin_completed: killing id\n");
usb_kill_isoc(id);
printk(KERN_DEBUG "usbin_completed: id killed\n");
+ wake_up(&u->dma.wait);
}
spin_unlock_irqrestore(&as->lock, flags);
return 0;
printk(KERN_DEBUG "usbin_sync_completed: killing id\n");
usb_kill_isoc(id);
printk(KERN_DEBUG "usbin_sync_completed: id killed\n");
+ wake_up(&u->dma.wait);
}
spin_unlock_irqrestore(&as->lock, flags);
return 0;
spin_unlock_irqrestore(&as->lock, flags);
printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i);
while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
+ if (signal_pending(current)) {
+ if (i & FLG_ID0RUNNING)
+ usb_kill_isoc(u->dataiso[0]);
+ if (i & FLG_ID1RUNNING)
+ usb_kill_isoc(u->dataiso[1]);
+ if (i & FLG_SYNC0RUNNING)
+ usb_kill_isoc(u->synciso[0]);
+ if (i & FLG_SYNC1RUNNING)
+ usb_kill_isoc(u->synciso[1]);
+ break;
+ }
spin_lock_irqsave(&as->lock, flags);
i = u->flags;
spin_unlock_irqrestore(&as->lock, flags);
printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i);
}
+ set_current_state(TASK_RUNNING);
if (u->dataiso[0])
usb_free_isoc(u->dataiso[0]);
if (u->dataiso[1])
printk(KERN_DEBUG "usbout_completed: killing id\n");
usb_kill_isoc(id);
printk(KERN_DEBUG "usbout_completed: id killed\n");
+ wake_up(&u->dma.wait);
}
spin_unlock_irqrestore(&as->lock, flags);
return 0;
printk(KERN_DEBUG "usbout_sync_completed: killing id\n");
usb_kill_isoc(id);
printk(KERN_DEBUG "usbout_sync_completed: id killed\n");
+ wake_up(&u->dma.wait);
}
spin_unlock_irqrestore(&as->lock, flags);
return 0;
if (as->usbout.dma.mapped || !as->usbout.dma.ready)
return 0;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&as->usbout.dma.wait, &wait);
for (;;) {
- spin_lock_irqsave(&as->lock, flags);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&as->lock, flags);
count = as->usbout.dma.count;
spin_unlock_irqrestore(&as->lock, flags);
if (count <= 0)
}
tmo = 3 * HZ * count / as->usbout.dma.srate;
tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
- if (!schedule_timeout(tmo + 1))
+ if (!schedule_timeout(tmo + 1)) {
printk(KERN_DEBUG "usbaudio: dma timed out??\n");
+ break;
+ }
}
remove_wait_queue(&as->usbout.dma.wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&as->usbin.dma.wait, &wait);
while (count > 0) {
spin_lock_irqsave(&as->lock, flags);
ptr = as->usbin.dma.rdptr;
cnt = as->usbin.dma.count;
+ /* set task state early to avoid wakeup races */
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&as->lock, flags);
if (cnt > count)
cnt = count;
return ret;
if (!access_ok(VERIFY_READ, buffer, count))
return -EFAULT;
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&as->usbout.dma.wait, &wait);
while (count > 0) {
+#if 0
+ printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n",
+ count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
+ as->usbout.flags, current->state);
+#endif
spin_lock_irqsave(&as->lock, flags);
if (as->usbout.dma.count < 0) {
as->usbout.dma.count = 0;
}
ptr = as->usbout.dma.wrptr;
cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
+ /* set task state early to avoid wakeup races */
+ if (cnt <= 0)
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&as->lock, flags);
if (cnt > count)
cnt = count;
* zero bandwidth (idle) config and one or more live one pers interface.
*/
-static int usb_audio_probe(struct usb_device *dev);
-static void usb_audio_disconnect(struct usb_device *dev);
+static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver usb_audio_driver = {
"audio",
usb_audio_probe,
usb_audio_disconnect,
- { NULL, NULL }
+ /*{ NULL, NULL }, */ LIST_HEAD_INIT(usb_audio_driver.driver_list),
+ NULL,
+ 0
};
list_add_tail(&ms->list, &s->mixerlist);
}
-static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
+static void * usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
{
struct usb_audio_state *s;
struct usb_config_descriptor *config = dev->actconfig;
unsigned int i, j, numifin = 0, numifout = 0;
if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
- return -1;
+ return NULL;
memset(s, 0, sizeof(struct usb_audio_state));
INIT_LIST_HEAD(&s->audiolist);
INIT_LIST_HEAD(&s->mixerlist);
/* note: this requires the data endpoint to be ep0 and the optional sync
ep to be ep1, which seems to be the case */
if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
- if (numifin < USB_MAXINTERFACES)
+ if (numifin < USB_MAXINTERFACES) {
ifin[numifin++] = j;
+ usb_driver_claim_interface(&usb_audio_driver, iface, s);
+ }
} else {
- if (numifout < USB_MAXINTERFACES)
+ if (numifout < USB_MAXINTERFACES) {
ifout[numifout++] = j;
+ usb_driver_claim_interface(&usb_audio_driver, iface, s);
+ }
}
}
printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
ret:
if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
kfree(s);
- return -1;
+ return NULL;
}
/* everything successful */
- dev->private = s;
down(&open_sem);
list_add_tail(&s->audiodev, &audiodevs);
up(&open_sem);
MOD_INC_USE_COUNT;
- return 0;
+ return s;
}
/* we only care for the currently active configuration */
-static int usb_audio_probe(struct usb_device *dev)
+static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_config_descriptor *config = dev->actconfig;
unsigned char *buffer;
goto audioctrlfound;
printk(KERN_DEBUG "usb_audio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n",
dev->descriptor.idVendor, dev->descriptor.idProduct);
- return -1;
+ return NULL;
audioctrlfound:
/* find which configuration number is active */
if (dev->config+i == config)
goto configfound;
printk(KERN_ERR "usb_audio: cannot find active configuration number of device %d\n", dev->devnum);
- return -1;
+ return NULL;
configfound:
- if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
- printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
- return -1;
- }
ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
if (ret) {
printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
- return -1;
+ return NULL;
}
if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
printk(KERN_ERR "usb_audio: invalid config descriptor %d of device %d\n", i, dev->devnum);
- return -1;
+ return NULL;
}
buflen = buf[2] | (buf[3] << 8);
if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
- return -1;
+ return NULL;
ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
if (ret) {
kfree(buffer);
printk(KERN_ERR "usb_audio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
- return -1;
+ return NULL;
}
/* find first audio control interface; we currently cannot handle more than one */
for (i = 0; i < config->bNumInterfaces; i++) {
config->interface[i].altsetting[0].bInterfaceSubClass != 1)
continue;
/* audiocontrol interface found */
- if (!usb_audio_parsecontrol(dev, buffer, buflen, i))
- return 0;
+ return usb_audio_parsecontrol(dev, buffer, buflen, i);
}
- return -1;
+ return NULL;
}
/* a revoke facility would make things simpler */
-static void usb_audio_disconnect(struct usb_device *dev)
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_audio_state *s = (struct usb_audio_state *)dev->private;
+ struct usb_audio_state *s = (struct usb_audio_state *)ptr;
struct list_head *list;
struct usb_audiodev *as;
struct usb_mixerdev *ms;
#endif
release(s);
wake_up(&open_wait);
- dev->private = NULL;
}
int usb_audio_init(void)
#define MDEBUG(x) do { } while(0) /* Debug memory management */
+static struct usb_driver cpia_driver;
+
/* Given PGD from the address space's page table, return the kernel
* virtual mapping of the physical memory mapped at ADR.
*/
struct usb_device *dev = cpia->dev;
unsigned char version[4];
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
- printk(KERN_INFO "cpia: usb_set_configuration failed\n");
- return -EBUSY;
- }
+ /* claim interface 1 */
+ usb_driver_claim_interface(&cpia_driver,
+ &dev->actconfig->interface[1], cpia);
- /* Set packet size to 0 */
+ /* Set altsetting 0 on interface 1 */
if (usb_set_interface(dev, 1, 0) < 0) {
printk(KERN_INFO "usb_set_interface error\n");
return -EBUSY;
error:
video_unregister_device(&cpia->vdev);
+ usb_driver_release_interface(&cpia_driver,
+ &dev->actconfig->interface[1]);
kfree(cpia);
return -EBUSY;
}
-static int cpia_probe(struct usb_device *dev)
+static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
struct usb_cpia *cpia;
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
- return -1;
+ return NULL;
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
/* Is it a CPiA? */
if (dev->descriptor.idVendor != 0x0553)
- return -1;
+ return NULL;
if (dev->descriptor.idProduct != 0x0002)
- return -1;
+ return NULL;
/* Checking vendor/product should be enough, but what the hell */
if (interface->bInterfaceClass != 0xFF)
- return -1;
+ return NULL;
if (interface->bInterfaceSubClass != 0x00)
- return -1;
+ return NULL;
/* We found a CPiA */
printk("USB CPiA camera found\n");
if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
printk("couldn't kmalloc cpia struct\n");
- return -1;
+ return NULL;
}
memset(cpia, 0, sizeof(*cpia));
- dev->private = cpia;
cpia->dev = dev;
- return usb_cpia_configure(cpia);
+ if (!usb_cpia_configure(cpia)) {
+ return cpia;
+ } else return NULL;
}
-static void cpia_disconnect(struct usb_device *dev)
+static void cpia_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_cpia *cpia = dev->private;
+ struct usb_cpia *cpia = (struct usb_cpia *) ptr;
video_unregister_device(&cpia->vdev);
+ usb_driver_release_interface(&cpia_driver,
+ &cpia->dev->actconfig->interface[1]);
+
/* Free the memory */
kfree(cpia);
}
/* --------------------------------------------------------------------- */
-static int ezusb_probe(struct usb_device *usbdev)
+static void * ezusb_probe(struct usb_device *usbdev, unsigned int ifnum)
{
struct ezusb *ez = &ezusb[0];
struct usb_interface_descriptor *interface;
/* the 1234:5678 is just a self assigned test ID */
if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) &&
(usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678))
- return -1;
+ return NULL;
/* We don't handle multiple configurations */
if (usbdev->descriptor.bNumConfigurations != 1)
- return -1;
+ return NULL;
#if 0
/* We don't handle multiple interfaces */
- if (usbdev->config[0].bNumInterfaces != 1)
- return -1;
+ if (usbdev->actconfig.bNumInterfaces != 1)
+ return NULL;
#endif
down(&ez->mutex);
if (ez->usbdev) {
up(&ez->mutex);
printk(KERN_INFO "ezusb: device already used\n");
- return -1;
+ return NULL;
}
ez->usbdev = usbdev;
- usbdev->private = ez;
- if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) {
- printk(KERN_ERR "ezusb: set_configuration failed\n");
- goto err;
- }
- interface = &usbdev->config[0].interface[0].altsetting[1];
- if (usb_set_interface(usbdev, 0, 1) < 0) {
+ interface = &usbdev->actconfig->interface[ifnum].altsetting[1];
+ if (usb_set_interface(usbdev, ifnum, 1) < 0) {
printk(KERN_ERR "ezusb: set_interface failed\n");
goto err;
}
up(&ez->mutex);
MOD_INC_USE_COUNT;
- return 0;
+ return ez;
err:
up(&ez->mutex);
ez->usbdev = NULL;
- usbdev->private = NULL;
- return -1;
+ return NULL;
}
-static void ezusb_disconnect(struct usb_device *usbdev)
+static void ezusb_disconnect(struct usb_device *usbdev, void *ptr)
{
- struct ezusb *ez = (struct ezusb *)usbdev->private;
+ struct ezusb *ez = (struct ezusb *) ptr;
down(&ez->mutex);
destroy_all_async(ez);
ez->usbdev = NULL;
up(&ez->mutex);
wake_up(&ez->wait);
- usbdev->private = NULL;
MOD_DEC_USE_COUNT;
}
return read_count;
}
-static int
-probe_scanner(struct usb_device *dev)
+static void *
+probe_scanner(struct usb_device *dev, unsigned int ifnum)
{
struct hpscan_usb_data *hps = &hpscan;
* soon. */
if (dev->descriptor.idVendor != 0x3f0 ) {
printk(KERN_INFO "Scanner is not an HP Scanner.\n");
- return -1;
+ return NULL;
}
if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */
dev->descriptor.idProduct != 0x202 && /* HP 5100C */
dev->descriptor.idProduct != 0x601) { /* HP 6300C */
printk(KERN_INFO "Scanner model not supported/tested.\n");
- return -1;
+ return NULL;
}
printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum);
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk(KERN_DEBUG "Failed to set configuration\n");
- return -1;
- }
-
hps->present = 1;
hps->hpscan_dev = dev;
if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
- return -ENOMEM;
+ return NULL;
}
if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
- return -ENOMEM;
+ return NULL;
}
- return 0;
+ return hps;
}
static void
-disconnect_scanner(struct usb_device *dev)
+disconnect_scanner(struct usb_device *dev, void *ptr)
{
- struct hpscan_usb_data *hps = &hpscan;
+ struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr;
if (hps->isopen) {
/* better let it finish - the release will do whats needed */
kfree(hps->ibuf);
kfree(hps->obuf);
- dev->private = NULL; /* just in case */
hps->present = 0;
}
/* Wakes up khubd */
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */
struct usb_hub_status *hubsts;
int i;
- /* Set it to the first configuration */
- usb_set_configuration(dev, dev->config[0].bConfigurationValue);
-
/* Get the length first */
if (usb_get_hub_descriptor(dev, buffer, 4))
return -1;
return 0;
}
-static int hub_probe(struct usb_device *dev)
+static void * hub_probe(struct usb_device *dev, unsigned int i)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
unsigned long flags;
int ret;
- /* We don't handle multi-config hubs */
- if (dev->descriptor.bNumConfigurations != 1)
- return -1;
-
- /* We don't handle multi-interface hubs */
- if (dev->config[0].bNumInterfaces != 1)
- return -1;
-
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[i].altsetting[0];
/* Is it a hub? */
if (interface->bInterfaceClass != USB_CLASS_HUB)
- return -1;
+ return NULL;
/* Some hubs have a subclass of 1, which AFAICT according to the */
/* specs is not defined, but it works */
if ((interface->bInterfaceSubClass != 0) &&
(interface->bInterfaceSubClass != 1))
- return -1;
+ return NULL;
/* Multiple endpoints? What kind of mutant ninja-hub is this? */
if (interface->bNumEndpoints != 1)
- return -1;
+ return NULL;
endpoint = &interface->endpoint[0];
/* Output endpoint? Curiousier and curiousier.. */
if (!(endpoint->bEndpointAddress & USB_DIR_IN))
- return -1;
+ return NULL;
/* If it's not an interrupt endpoint, we'd better punt! */
if ((endpoint->bmAttributes & 3) != 3)
- return -1;
+ return NULL;
/* We found a hub */
printk(KERN_INFO "USB hub found\n");
if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "couldn't kmalloc hub struct\n");
- return -1;
+ return NULL;
}
memset(hub, 0, sizeof(*hub));
- dev->private = hub;
-
INIT_LIST_HEAD(&hub->event_list);
hub->dev = dev;
/* Record the new hub's existence */
- spin_lock_irqsave(&hub_list_lock, flags);
+ spin_lock_irqsave(&hub_event_lock, flags);
INIT_LIST_HEAD(&hub->hub_list);
list_add(&hub->hub_list, &hub_list);
- spin_unlock_irqrestore(&hub_list_lock, flags);
+ spin_unlock_irqrestore(&hub_event_lock, flags);
if (usb_hub_configure(hub) >= 0) {
hub->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
hub, &hub->irq_handle);
if (ret) {
printk (KERN_WARNING "usb-hub: usb_request_irq failed (0x%x)\n", ret);
- /* FIXME: need to free <hub> but first clean up its list. */
- return -1;
+ /* free hub, but first clean up its list. */
+ spin_lock_irqsave(&hub_event_lock, flags);
+
+ /* Delete it and then reset it */
+ list_del(&hub->event_list);
+ INIT_LIST_HEAD(&hub->event_list);
+ list_del(&hub->hub_list);
+ INIT_LIST_HEAD(&hub->hub_list);
+
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+
+ kfree(hub);
+
+ return NULL;
}
/* Wake up khubd */
wake_up(&khubd_wait);
}
- return 0;
+ return hub;
}
-static void hub_disconnect(struct usb_device *dev)
+static void hub_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_hub *hub = dev->private;
+ struct usb_hub *hub = ptr;
unsigned long flags;
spin_lock_irqsave(&hub_event_lock, flags);
void usb_hub_cleanup(void);
int usb_kbd_init(void);
void usb_major_init(void);
+void usb_major_cleanup(void);
void usb_mouse_cleanup(void);
int usb_hp_scanner_init(void);
void usb_hp_scanner_cleanup(void);
extern unsigned char usb_kbd_map[];
-static int usb_kbd_probe(struct usb_device *dev);
-static void usb_kbd_disconnect(struct usb_device *dev);
+static void * usb_kbd_probe(struct usb_device *dev, unsigned int i);
+static void usb_kbd_disconnect(struct usb_device *dev, void *ptr);
static void usb_kbd_repeat(unsigned long dummy);
static LIST_HEAD(usb_kbd_list);
return 1;
}
-static int
-usb_kbd_probe(struct usb_device *dev)
+static void *
+usb_kbd_probe(struct usb_device *dev, unsigned int i)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_keyboard *kbd;
int ret;
- if (dev->descriptor.bNumConfigurations < 1)
- return -1;
-
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[i].altsetting[0];
endpoint = &interface->endpoint[0];
if(interface->bInterfaceClass != 3
|| interface->bInterfaceSubClass != 1
|| interface->bInterfaceProtocol != 1)
{
- return -1;
+ return NULL;
}
printk(KERN_INFO "USB HID boot protocol keyboard detected.\n");
{
memset(kbd, 0, sizeof(*kbd));
kbd->dev = dev;
- dev->private = kbd;
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO " Failed usb_set_configuration: kbd\n");
- goto probe_err;
- }
usb_set_protocol(dev, 0);
usb_set_idle(dev, 0, 0);
list_add(&kbd->list, &usb_kbd_list);
- return 0;
+ return kbd;
}
probe_err:
if (kbd)
kfree (kbd);
- return -1;
+ return NULL;
}
static void
-usb_kbd_disconnect(struct usb_device *dev)
+usb_kbd_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private;
+ struct usb_keyboard *kbd = (struct usb_keyboard*) ptr;
if (kbd)
{
usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe);
- dev->private = NULL;
list_del(&kbd->list);
del_timer(&kbd->repeat_timer);
kfree(kbd);
fasync_mouse,
};
-static int mouse_probe(struct usb_device *dev)
+static void* mouse_probe(struct usb_device *dev, unsigned int i)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct mouse_state *mouse = &static_mouse_state;
int ret;
- /* We don't handle multi-config mice */
- if (dev->descriptor.bNumConfigurations != 1)
- return -1;
-
- /* We don't handle multi-interface mice */
- if (dev->config[0].bNumInterfaces != 1)
- return -1;
-
/* Is it a mouse interface? */
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[i].altsetting[0];
if (interface->bInterfaceClass != 3)
- return -1;
+ return NULL;
if (interface->bInterfaceSubClass != 1)
- return -1;
+ return NULL;
if (interface->bInterfaceProtocol != 2)
- return -1;
+ return NULL;
/* Multiple endpoints? What kind of mutant ninja-mouse is this? */
if (interface->bNumEndpoints != 1)
- return -1;
+ return NULL;
endpoint = &interface->endpoint[0];
/* Output endpoint? Curiousier and curiousier.. */
if (!(endpoint->bEndpointAddress & 0x80))
- return -1;
+ return NULL;
/* If it's not an interrupt endpoint, we'd better punt! */
if ((endpoint->bmAttributes & 3) != 3)
- return -1;
+ return NULL;
printk("USB mouse found\n");
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO " Failed usb_set_configuration: mouse\n");
- return -1;
- }
-
/* these are used to request the irq when the mouse is opened */
mouse->dev = dev;
mouse->bEndpointAddress = endpoint->bEndpointAddress;
NULL, &mouse->irq_handle);
if (ret) {
printk (KERN_WARNING "usb-mouse: usb_request_irq failed (0x%x)\n", ret);
- return ret;
+ return NULL;
}
mouse->suspended = 0;
}
- return 0;
+ return mouse;
}
-static void mouse_disconnect(struct usb_device *dev)
+static void mouse_disconnect(struct usb_device *dev, void *ptr)
{
- struct mouse_state *mouse = &static_mouse_state;
+ struct mouse_state *mouse = ptr;
/* stop the usb interrupt transfer */
if (mouse->present) {
/* this might need work */
mouse->present = 0;
- printk("Mouse disconnected\n");
+ printk("USB Mouse disconnected\n");
}
static struct usb_driver mouse_driver = {
# endif
while(!list_empty(&ohci_hcd_list)) {
ohci = list_entry(ohci_hcd_list.next, struct ohci, ohci_hcd_list);
- list_del(ohci->ohci_hcd_list);
- INIT_LIST_HEAD(ohci->ohci_hcd_list);
+ list_del(&ohci->ohci_hcd_list);
+ INIT_LIST_HEAD(&ohci->ohci_hcd_list);
release_ohci(ohci);
}
}
return read_count;
}
-static int printer_probe(struct usb_device *dev)
+static void * printer_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
+ struct pp_usb_data *pp;
int i;
/*
if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER &&
dev->descriptor.bDeviceClass != 0) ||
dev->descriptor.bNumConfigurations != 1 ||
- dev->config[0].bNumInterfaces != 1) {
- return -1;
+ dev->actconfig->bNumInterfaces != 1) {
+ return NULL;
}
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
/* Let's be paranoid (for the moment). */
if (interface->bInterfaceClass != USB_CLASS_PRINTER ||
interface->bInterfaceSubClass != 1 ||
(interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1) ||
interface->bNumEndpoints > 2) {
- return -1;
+ return NULL;
}
/* Does this (these) interface(s) support bulk transfers? */
if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_BULK) {
- return -1;
+ return NULL;
}
if ((interface->bNumEndpoints > 1) &&
((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_BULK)) {
- return -1;
+ return NULL;
}
/*
(interface->bNumEndpoints > 1 &&
(interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK)
!= USB_DIR_OUT)) {
- return -1;
+ return NULL;
}
for (i=0; i<MAX_PRINTERS; i++) {
}
if (i >= MAX_PRINTERS) {
printk("No minor table space available for USB Printer\n");
- return -1;
+ return NULL;
}
printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum);
- if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
+ if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
printk(KERN_DEBUG "usb_printer: no memory!\n");
- return -1;
+ return NULL;
}
- memset(dev->private, 0, sizeof(struct pp_usb_data));
- minor_data[i] = PPDATA(dev->private);
+ memset(pp, 0, sizeof(struct pp_usb_data));
+ minor_data[i] = PPDATA(pp);
minor_data[i]->minor = i;
minor_data[i]->pusb_dev = dev;
minor_data[i]->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE;
interface->endpoint[minor_data[i]->bulk_in_index].wMaxPacketSize;
}
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk(KERN_INFO " Failed usb_set_configuration: printer\n");
- return -1;
- }
-
printk(KERN_INFO "USB Printer Summary:\n");
printk(KERN_INFO "index=%d, maxout=%d, noinput=%d\n",
i, minor_data[i]->maxout, minor_data[i]->noinput);
printk(KERN_INFO " USB Printer ID is %s\n",
&ieee_id[2]);
}
- status = printer_read_status(PPDATA(dev->private));
+ status = printer_read_status(PPDATA(pp));
printk(KERN_INFO " Status is %s,%s,%s\n",
(status & LP_PSELECD) ? "Selected" : "Not Selected",
(status & LP_POUTPA) ? "No Paper" : "Paper",
(status & LP_PERRORP) ? "No Error" : "Error");
}
#endif
- return 0;
+ return pp;
}
-static void printer_disconnect(struct usb_device *dev)
+static void printer_disconnect(struct usb_device *dev, void *ptr)
{
- struct pp_usb_data *pp = dev->private;
+ struct pp_usb_data *pp = ptr;
if (pp->isopen) {
/* better let it finish - the release will do whats needed */
}
minor_data[pp->minor] = NULL;
kfree(pp);
- dev->private = NULL; /* just in case */
}
static struct file_operations usb_printer_fops = {
static char *format_topo =
-/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */
- "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n";
+/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
+ "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
static char *format_bandwidth =
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
static char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */
- "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+ "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
return 0;
}
-static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc,
- char *buf, int *len)
+static int usb_dump_interface_descriptor (const struct usb_interface *iface,
+ int setno, char *buf, int *len)
{
+ struct usb_interface_descriptor *desc =
+ &iface->altsetting[setno];
+
*len += sprintf (buf + *len, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bInterfaceClass,
class_decode (desc->bInterfaceClass),
desc->bInterfaceSubClass,
- desc->bInterfaceProtocol
+ desc->bInterfaceProtocol,
+ iface->driver ? iface->driver->name : "(none)"
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
}
-static int usb_dump_interface (const struct usb_interface_descriptor *interface,
- char *buf, int *len)
+static int usb_dump_interface (const struct usb_interface *iface,
+ int setno, char *buf, int *len)
{
int i;
+ struct usb_interface_descriptor *desc =
+ &iface->altsetting[setno];
- if (usb_dump_interface_descriptor (interface, buf, len) < 0)
+ if (usb_dump_interface_descriptor (iface, setno, buf, len) < 0)
return -1;
- for (i = 0; i < interface->bNumEndpoints; i++) {
- if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0)
+ for (i = 0; i < desc->bNumEndpoints; i++) {
+ if (usb_dump_endpoint (desc->endpoint + i, buf, len) < 0)
return -1;
}
break;
for (j = 0; j < interface->num_altsetting; j++)
- if (usb_dump_interface (interface->altsetting + j, buf, len) < 0)
+ if (usb_dump_interface (interface, j, buf, len) < 0)
return -1;
}
level, parent_devnum, index, count,
usbdev->devnum,
usbdev->slow ? "1.5" : "12 ",
- usbdev->ifnum, usbdev->maxchild,
- usbdev->driver ? usbdev->driver->name :
- (level == 0) ? "(root hub)" : "(none)"
+ usbdev->maxchild
);
/*
* level = topology-tier level;
return -1;
}
- driversdir = create_proc_entry ("drivers", 0, usbdir);
+ driversdir = create_proc_read_entry("drivers", 0, usbdir,
+ usb_driver_list_dump, NULL);
if (!driversdir) {
printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n");
proc_usb_cleanup ();
return -1;
}
- driversdir->read_proc = usb_driver_list_dump;
- devicesdir = create_proc_entry ("devices", 0, usbdir);
+ devicesdir = create_proc_read_entry ("devices", 0, usbdir,
+ usb_bus_list_dump_devices, NULL);
if (!devicesdir) {
printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n");
proc_usb_cleanup ();
return -1;
}
- devicesdir->read_proc = usb_bus_list_dump_devices;
return 0;
}
*/
void cleanup_drivers(void)
{
+ usb_major_cleanup();
#ifdef CONFIG_USB_PROC
proc_usb_cleanup ();
#endif
/* into dynamically creating them at insertion time. */
-static int usb_serial_probe(struct usb_device *dev);
-static void usb_serial_disconnect(struct usb_device *dev);
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
typedef enum {
unknown = 0,
}
-static int usb_serial_probe(struct usb_device *dev)
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial_state *serial;
struct usb_interface_descriptor *interface;
}
if (type == unknown)
- return (-1);
+ return NULL;
printk (KERN_INFO "USB serial converter detected.\n");
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO " Failed usb_set_configuration: serial\n");
- return (-1);
- }
-
if (0>(serial_num = Get_Free_Serial())) {
debug_info("USB Serial: Too many devices connected\n");
- return (-1);
+ return NULL;
}
serial = &serial_state_table[serial_num];
memset(serial, 0, sizeof(serial));
serial->dev = dev;
serial->type = type;
- dev->private = serial;
/* we should have 1 bulk in, 1 bulk out, and 1 interrupt in endpoints */
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
for (i = 0; i < interface->bNumEndpoints; ++i) {
endpoint = &interface->endpoint[i];
serial->present = 1;
MOD_INC_USE_COUNT;
- return (0);
+ return serial;
probe_error:
if (serial) {
if (serial->interrupt_in_buffer)
kfree (serial->interrupt_in_buffer);
}
- return (-1);
+ return NULL;
}
-static void usb_serial_disconnect(struct usb_device *dev)
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_serial_state *serial = (struct usb_serial_state *)dev->private;
+ struct usb_serial_state *serial = (struct usb_serial_state *) ptr;
if (serial) {
if (!serial->present) {
serial->present = 0;
serial->active = 0;
}
- dev->private = NULL;
MOD_DEC_USE_COUNT;
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
#include "usb.h"
-static int usb_find_driver(struct usb_device *);
+/*
+ * Prototypes for the device driver probing/loading functions
+ */
+static void usb_find_drivers(struct usb_device *);
+static int usb_find_interface_driver(struct usb_device *, unsigned int);
static void usb_check_support(struct usb_device *);
-static void usb_driver_purge(struct usb_driver *, struct usb_device *);
/*
* We have a per-interface "registered driver" list.
static LIST_HEAD(usb_driver_list);
static LIST_HEAD(usb_bus_list);
+static struct usb_busmap busmap;
+
static struct usb_driver *usb_minors[16];
int usb_register(struct usb_driver *new_driver)
return 0;
}
+/*
+ * This function is part of a depth-first search down the device tree,
+ * removing any instances of a device driver.
+ */
+static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
+{
+ int i;
+
+ if (!dev) {
+ printk(KERN_ERR "usbcore: null device being purged!!!\n");
+ return;
+ }
+
+ for (i=0; i<USB_MAXCHILDREN; i++)
+ if (dev->children[i])
+ usb_drivers_purge(driver, dev->children[i]);
+
+ if (!dev->actconfig)
+ return;
+
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *interface = &dev->actconfig->interface[i];
+
+ if (interface->driver == driver) {
+ driver->disconnect(dev, interface->private_data);
+ usb_driver_release_interface(driver, interface);
+ /*
+ * This will go through the list looking for another
+ * driver that can handle the device
+ */
+ usb_find_interface_driver(dev, i);
+ }
+ }
+}
+
+/*
+ * Unlink a driver from the driver list when it is unloaded
+ */
void usb_deregister(struct usb_driver *driver)
{
struct list_head *tmp;
struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
tmp = tmp->next;
- usb_driver_purge(driver, bus->root_hub);
+ usb_drivers_purge(driver, bus->root_hub);
}
}
-/*
- * This function is part of a depth-first search down the device tree,
- * removing any instances of a device driver.
- */
-static void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev)
-{
- int i;
-
- if (!dev) {
- printk(KERN_ERR "usbcore: null device being purged!!!\n");
- return;
- }
-
- for (i=0; i<USB_MAXCHILDREN; i++)
- if (dev->children[i])
- usb_driver_purge(driver, dev->children[i]);
-
- /* now we check this device */
- if (dev->driver == driver) {
- /*
- * Note: this is not the correct way to do this, this
- * uninitializes and reinitializes EVERY driver
- */
- printk(KERN_INFO "disconnect driverless device %d\n",
- dev->devnum);
- dev->driver->disconnect(dev);
- dev->driver = NULL;
-
- /*
- * This will go back through the list looking for a driver
- * that can handle the device
- */
- usb_find_driver(dev);
- }
-}
/*
* calc_bus_time:
bus->op = op;
bus->root_hub = NULL;
bus->hcpriv = NULL;
+ bus->busnum = -1;
bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
void usb_register_bus(struct usb_bus *bus)
{
+ int busnum;
+
+ busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
+ if (busnum < USB_MAXBUS) {
+ set_bit(busnum, busmap.busmap);
+ bus->busnum = busnum;
+ } else
+ printk(KERN_INFO "usb: too many bus'\n");
+
proc_usb_add_bus(bus);
/* Add it to the list of buses */
list_add(&bus->bus_list, &usb_bus_list);
- printk("New USB bus registered\n");
+ printk("New USB bus registered, assigned bus number %d\n", bus->busnum);
}
void usb_deregister_bus(struct usb_bus *bus)
{
+ printk("usbcore: USB bus %d deregistered\n", bus->busnum);
+
/*
* NOTE: make sure that all the devices are removed by the
* controller code, as well as having it call this when cleaning
list_del(&bus->bus_list);
proc_usb_remove_bus(bus);
+
+ clear_bit(bus->busnum, busmap.busmap);
}
/*
if (dev->children[i])
usb_check_support(dev->children[i]);
+ if (!dev->actconfig)
+ return;
+
/* now we check this device */
- if (!dev->driver && dev->devnum > 0)
- usb_find_driver(dev);
+ if (dev->devnum > 0)
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+ usb_find_interface_driver(dev, i);
+}
+
+
+/*
+ * This is intended to be used by usb device drivers that need to
+ * claim more than one interface on a device at once when probing
+ * (audio and acm are good examples). No device driver should have
+ * to mess with the internal usb_interface or usb_device structure
+ * members.
+ */
+void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
+{
+ if (!iface || !driver)
+ return;
+
+ printk(KERN_DEBUG "usbcore: %s driver claimed interface %p\n", driver->name, iface);
+
+ iface->driver = driver;
+ iface->private_data = priv;
+} /* usb_driver_claim_interface() */
+
+/*
+ * This should be used by drivers to check other interfaces to see if
+ * they are available or not.
+ */
+int usb_interface_claimed(struct usb_interface *iface)
+{
+ if (!iface)
+ return 0;
+
+ return (iface->driver != NULL);
+} /* usb_interface_claimed() */
+
+/*
+ * This should be used by drivers to release their claimed interfaces
+ */
+void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
+{
+ /* this should never happen, don't release something that's not ours */
+ if (iface->driver != driver || !iface)
+ return;
+
+ iface->driver = NULL;
+ iface->private_data = NULL;
}
/*
* This entrypoint gets called for each new device.
*
* We now walk the list of registered USB drivers,
- * looking for one that will accept this device as
- * his..
+ * looking for one that will accept this interface.
+ *
+ * The probe return value is changed to be a private pointer. This way
+ * the drivers don't have to dig around in our structures to set the
+ * private pointer if they only need one interface.
+ *
+ * Returns: 0 if a driver accepted the interface, -1 otherwise
*/
-static int usb_find_driver(struct usb_device *dev)
+static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
{
struct list_head *tmp = usb_driver_list.next;
-
- while (tmp != &usb_driver_list) {
- struct usb_driver *driver = list_entry(tmp, struct usb_driver,
- driver_list);
- tmp = tmp->next;
- if (driver->probe(dev))
- continue;
- dev->driver = driver;
- return 1;
+ struct usb_interface *interface;
+
+ if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
+ printk(KERN_ERR "usb-core: bad find_interface_driver params\n");
+ return -1;
}
- /*
- * Ok, no driver accepted the device, so show the info
- * for debugging..
- */
- return 0;
+ interface = &dev->actconfig->interface[ifnum];
+
+ if (usb_interface_claimed(interface))
+ return -1;
+
+ while (tmp != &usb_driver_list) {
+ void *private;
+ struct usb_driver *driver = list_entry(tmp, struct usb_driver,
+ driver_list);
+
+ tmp = tmp->next;
+ if (!(private = driver->probe(dev, ifnum)))
+ continue;
+ usb_driver_claim_interface(driver, interface, private);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * This entrypoint gets called for each new device.
+ *
+ * All interfaces are scanned for matching drivers.
+ */
+static void usb_find_drivers(struct usb_device *dev)
+{
+ unsigned ifnum;
+ unsigned rejected = 0;
+
+ for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
+ /* if this interface hasn't already been claimed */
+ if (!usb_interface_claimed(dev->actconfig->interface)) {
+ if (usb_find_interface_driver(dev, ifnum))
+ rejected++;
+ }
+ }
+
+ if (rejected) {
+ printk(KERN_DEBUG "usbcore: unhandled interfaces on device.\n");
+ }
}
/*
{
dev->devnum = -1;
dev->slow = 0;
+ dev->actconfig = NULL;
}
/*
*pdev = NULL;
- printk("USB disconnect on device %d\n", dev->devnum);
+ printk("usbcore: USB disconnect on device %d\n", dev->devnum);
- if (dev->driver)
- dev->driver->disconnect(dev);
+ if (dev->actconfig) {
+ for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+ struct usb_interface *interface = &dev->actconfig->interface[i];
+ struct usb_driver *driver = interface->driver;
+ if (driver) {
+ driver->disconnect(dev, interface->private_data);
+ usb_driver_release_interface(driver, interface);
+ }
+ }
+ }
/* Free up all the children.. */
for (i = 0; i < USB_MAXCHILDREN; i++) {
if (err)
return err;
- dev->ifnum = interface;
dev->actconfig->interface[interface].act_altsetting = alternate;
usb_set_maxpacket(dev);
return 0;
}
dev->actconfig = dev->config;
- dev->ifnum = 0;
usb_set_maxpacket(dev);
+ /* we set the default configuration here */
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+ printk(KERN_ERR "usbcore: failed to set default configuration\n");
+ return -1;
+ }
+
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
usb_show_string(dev, "Product", dev->descriptor.iProduct);
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
/* now that the basic setup is over, add a /proc/bus/usb entry */
proc_usb_add_device(dev);
- if (!usb_find_driver(dev)) {
- /*
- * Ok, no driver accepted the device, so show the info for
- * debugging
- */
- printk(KERN_DEBUG "Unknown new USB device:\n");
- usb_show_device(dev);
- }
+ /* find drivers willing to handle this device */
+ usb_find_drivers(dev);
return 0;
}
* returns the current frame number for the parent USB bus/controller
* of the given USB device.
*/
-int usb_get_current_frame_number (struct usb_device *usb_dev)
+int usb_get_current_frame_number(struct usb_device *usb_dev)
{
return usb_dev->bus->op->get_frame_number (usb_dev);
}
-int usb_init_isoc (struct usb_device *usb_dev,
+int usb_init_isoc(struct usb_device *usb_dev,
unsigned int pipe,
int frame_count,
void *context,
struct usb_driver *c = usb_minors[minor/16];
file->f_op = NULL;
- if ((file->f_op = c->fops) && file->f_op->open)
+ if (c && (file->f_op = c->fops) && file->f_op->open)
return file->f_op->open(inode,file);
else
return -ENODEV;
void usb_major_init(void)
{
- if (register_chrdev(180,"usb",&usb_fops)) {
+ if (register_chrdev(USB_MAJOR,"usb",&usb_fops)) {
printk("unable to get major %d for usb devices\n",
- MISC_MAJOR);
+ USB_MAJOR);
}
}
+void usb_major_cleanup(void)
+{
+ unregister_chrdev(USB_MAJOR, "usb");
+}
+
#ifdef CONFIG_PROC_FS
struct list_head *usb_driver_get_list(void)
#include <linux/list.h>
#include <linux/sched.h>
+#define USB_MAJOR 180
+
extern int usb_hub_init(void);
extern int usb_kbd_init(void);
extern int usb_cpia_init(void);
unsigned long devicemap[128 / (8*sizeof(unsigned long))];
};
+#define USB_MAXBUS 64
+
+struct usb_busmap {
+ unsigned long busmap[USB_MAXBUS / (8*sizeof(unsigned long))];
+};
+
/*
* This is a USB device descriptor.
*
int act_altsetting; /* active alternate setting */
int num_altsetting; /* number of alternate settings */
+
+ struct usb_driver *driver; /* driver */
+ void *private_data;
};
/* Configuration descriptor information.. */
struct usb_driver {
const char *name;
- int (*probe)(struct usb_device *);
- void (*disconnect)(struct usb_device *);
+ void * (*probe)(struct usb_device *, unsigned int);
+ void (*disconnect)(struct usb_device *, void *);
struct list_head driver_list;
* Allocated per bus we have
*/
struct usb_bus {
+ int busnum; /* Bus number (in order of reg) */
+
struct usb_devmap devmap; /* Device map */
struct usb_operations *op; /* Operations (specific to the HC) */
struct usb_device *root_hub; /* Root hub */
struct usb_config_descriptor *actconfig;/* the active configuration */
int epmaxpacketin[16]; /* INput endpoint specific maximums */
int epmaxpacketout[16]; /* OUTput endpoint specific maximums */
- int ifnum; /* active interface number */
struct usb_device *parent;
struct usb_bus *bus; /* Bus we're part of */
- struct usb_driver *driver; /* Driver */
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
int string_langid; /* language ID for strings */
void *hcpriv; /* Host Controller private data */
- void *private; /* Upper layer private data */
void *audiopriv; /* May be both audio and HID */
/* procfs entry */
struct proc_dir_entry *proc_entry;
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
+/* used these for multi-interface device registration */
+extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv);
+extern int usb_interface_claimed(struct usb_interface *iface);
+extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
+
extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
extern void usb_free_bus(struct usb_bus *);
extern void usb_register_bus(struct usb_bus *);
#define PIPE_CONTROL 2
#define PIPE_BULK 3
+#define USB_ISOCHRONOUS 0
+#define USB_INTERRUPT 1
+#define USB_CONTROL 2
+#define USB_BULK 3
+
#define usb_maxpacket(dev, pipe, out) (out \
? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
: (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
struct usb_scsi_filter *filter; /* filter driver */
void *fdata; /* filter data */
unsigned int flags; /* from filter initially*/
+ __u8 ifnum; /* interface number */
__u8 ep_in; /* in endpoint */
__u8 ep_out; /* out ....... */
__u8 ep_int; /* interrupt . */
static struct usb_scsi_filter *filters;
-static int scsi_probe(struct usb_device *dev);
-static void scsi_disconnect(struct usb_device *dev);
+static void * scsi_probe(struct usb_device *dev, unsigned int ifnum);
+static void scsi_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver scsi_driver = {
"usb_scsi",
scsi_probe,
cmd[1] = 4;
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
- 0, us->pusb_dev->ifnum, cmd, sizeof(cmd), HZ*5);
+ 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
/* long wait for reset */
}
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
- 0, us->pusb_dev->ifnum,
+ 0, us->ifnum,
cmd, us->fixedlength, HZ*5);
if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)
&& cmd[0] == TEST_UNIT_READY && result) {
cmd[4] = 1; /* start */
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
- 0, us->pusb_dev->ifnum,
+ 0, us->ifnum,
cmd, us->fixedlength, HZ*5);
wait_ms(100);
retry++;
} else {
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE,
- 0, us->pusb_dev->ifnum,
+ 0, us->ifnum,
srb->cmnd, srb->cmd_len, HZ*5);
}
if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
while (retry--) {
result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_STANDARD | USB_RT_DEVICE,
- 0, 0,
+ 0, us->ifnum,
status, sizeof(status), HZ*5);
if (result != USB_ST_TIMEOUT)
break;
result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
US_BULK_RESET, USB_TYPE_CLASS | USB_RT_INTERFACE,
- US_BULK_RESET_HARD, 0,
+ US_BULK_RESET_HARD, us->ifnum,
NULL, 0, HZ*5);
if (result)
US_DEBUGP("Bulk hard reset failed %d\n", result);
return 0;
}
-static int scsi_probe(struct usb_device *dev)
+static void * scsi_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
int i;
protocol = US_PR_CB;
subclass = US_SC_8070; /* an assumption */
} else if (dev->descriptor.bDeviceClass != 0 ||
- dev->config[0].interface[0].altsetting[0].bInterfaceClass !=
+ dev->actconfig->interface[ifnum].altsetting[0].bInterfaceClass !=
USB_CLASS_MASS_STORAGE ||
- dev->config[0].interface[0].altsetting[0].bInterfaceSubClass < US_SC_MIN ||
- dev->config[0].interface[0].altsetting[0].bInterfaceSubClass > US_SC_MAX) {
- return -1;
+ dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass < US_SC_MIN ||
+ dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass > US_SC_MAX) {
+ return NULL;
}
/* now check if we have seen it before */
printk(KERN_WARNING USB_SCSI "Out of memory\n");
if (filter)
filter->release(fdata);
- return -1;
+ return NULL;
}
memset(ss, 0, sizeof(struct us_data));
}
- interface = &dev->config[0].interface[0].altsetting[0];
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
ss->filter = filter;
ss->fdata = fdata;
ss->flags = flags;
US_DEBUGP("Endpoints In %d Out %d Int %d\n",
ss->ep_in, ss->ep_out, ss->ep_int);
+ /* save the interface number */
+ ss->ifnum = ifnum;
+
/* exit if strange looking */
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) ||
- usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
+ if (usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
!ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
US_DEBUGP("Problems with device\n");
if (ss->host) {
if (filter)
filter->release(fdata);
kfree(ss);
- return -1; /* no endpoints */
+ return NULL; /* no endpoints */
}
- if (dev->config[0].iConfiguration && usb_string(dev, dev->config[0].iConfiguration))
+ if (dev->actconfig->iConfiguration && usb_string(dev, dev->actconfig->iConfiguration))
US_DEBUGP("Configuration %s\n",
- usb_string(dev, dev->config[0].iConfiguration));
+ usb_string(dev, dev->actconfig->iConfiguration));
if (interface->iInterface && usb_string(dev, interface->iInterface))
US_DEBUGP("Interface %s\n",
usb_string(dev, interface->iInterface));
if (filter)
filter->release(fdata);
kfree(ss);
- return -1;
+ return NULL;
}
memcpy(htmplt, &my_host_template, sizeof(my_host_template));
ss->host_number = my_host_number++;
/* shuttle E-USB */
result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0),
1, 0xC0,
- 0, 0,
+ 0, ss->ifnum,
qstat, 2, HZ*5);
US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
init_waitqueue_head(&ss->ip_waitq);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe, pop_CBI_irq,
0, (void *)ss, &ss->irq_handle);
if (result)
- return -1;
+ return NULL;
interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6);
} else if (ss->protocol == US_PR_CBI)
if (filter)
filter->release(fdata);
kfree(ss);
- return -1;
+ return NULL;
}
/* wait for it to start */
printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum);
- dev->private = ss;
- return 0;
+ return ss;
}
-static void scsi_disconnect(struct usb_device *dev)
+static void scsi_disconnect(struct usb_device *dev, void *ptr)
{
- struct us_data *ss = dev->private;
+ struct us_data *ss = ptr;
if (!ss)
return;
if (ss->filter)
ss->filter->release(ss->fdata);
ss->pusb_dev = NULL;
- dev->private = NULL; /* just in case */
MOD_DEC_USE_COUNT;
}
/* --------------------------------------------------------------------- */
-static int uss720_probe(struct usb_device *usbdev)
+static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) &&
(usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) &&
(usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284))
- return -1;
+ return NULL;
- /* We don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1)
- return -1;
+ /* our known interfaces have 3 alternate settings */
+ if (usbdev->actconfig->interface[ifnum].num_altsetting != 3)
+ return NULL;
- /* We don't handle multiple interfaces */
- if (usbdev->config[0].bNumInterfaces != 1)
- return -1;
-
- /* We don't handle multiple interfaces */
- if (usbdev->config[0].interface[0].num_altsetting != 3)
- return -1;
-
- printk(KERN_DEBUG "uss720: set configuration\n");
- usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue);
-
- i = usb_set_interface(usbdev, 0, 2);
+ i = usb_set_interface(usbdev, ifnum, 2);
printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
- interface = &usbdev->config[0].interface[0].altsetting[2];
-
- //printk(KERN_DEBUG "uss720: get interface\n");
- //i = usb_get_interface(usbdev, 0);
- //printk(KERN_DEBUG "uss720: is in alternate setting %d\n", i);
+ interface = &usbdev->actconfig->interface[ifnum].altsetting[2];
/*
* Allocate parport interface
printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
- return -1;
+ return NULL;
if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
- kfree(priv);
- return -1;
+ printk(KERN_WARNING "usb-uss720: could not register parport\n");
+ goto probe_abort;
}
+
pp->private_data = priv;
- usbdev->private = pp;
priv->usbdev = usbdev;
pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
pp, &priv->irqhandle);
if (i) {
printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
- /* FIXME: undo some stuff and free some memory. */
- return -1;
+ goto probe_abort_port;
}
#endif
parport_proc_register(pp);
parport_announce_port(pp);
MOD_INC_USE_COUNT;
- return 0;
+ return pp;
+
+probe_abort_port:
+ parport_unregister_port(pp);
+probe_abort:
+ kfree(priv);
+ return NULL;
}
-static void uss720_disconnect(struct usb_device *usbdev)
+static void uss720_disconnect(struct usb_device *usbdev, void *ptr)
{
- struct parport *pp = (struct parport *)usbdev->private;
+ struct parport *pp = (struct parport *)ptr;
struct parport_uss720_private *priv = pp->private_data;
-#if 0
usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
-#endif
- usbdev->private = NULL;
priv->usbdev = NULL;
parport_proc_unregister(pp);
parport_unregister_port(pp);
/*
- * linux/drivers/video/acorn.c
+ * linux/drivers/video/acornfb.c
*
* Copyright (C) 1998,1999 Russell King
*
#include <video/fbcon-cfb16.h>
#include <video/fbcon-cfb32.h>
+#include "acornfb.h"
+
/*
* Default resolution.
* NOTE that it has to be supported in the table towards
*/
#define DEFAULT_XRES 640
#define DEFAULT_YRES 480
-
/*
- * define this to debug the video mode selection
+ * The order here defines which BPP we
+ * pick depending on which resolutions
+ * we have configured.
*/
-#undef DEBUG_MODE_SELECTION
-
-#if defined(HAS_VIDC20)
-#define VIDC_PALETTE_SIZE 256
-#define VIDC_NAME "VIDC20"
-#elif defined(HAS_VIDC)
-#include <asm/memc.h>
-#define VIDC_PALETTE_SIZE 16
-#define VIDC_NAME "VIDC"
+#if defined(FBCON_HAS_CFB4)
+# define DEFAULT_BPP 4
+#elif defined(FBCON_HAS_CFB8)
+# define DEFAULT_BPP 8
+#elif defined(FBCON_HAS_CFB16)
+# define DEFAULT_BPP 16
+#elif defined(FBCON_HAS_CFB2)
+# define DEFAULT_BPP 2
+#elif defined(FBCON_HAS_MFB)
+# define DEFAULT_BPP 1
+#else
+#error No suitable framebuffers configured
#endif
-#define EXTEND8(x) ((x)|(x)<<8)
-#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12)
-
-struct vidc20_palette {
- u_int red:8;
- u_int green:8;
- u_int blue:8;
- u_int ext:4;
- u_int unused:4;
-};
-
-struct vidc_palette {
- u_int red:4;
- u_int green:4;
- u_int blue:4;
- u_int trans:1;
- u_int sbz1:13;
- u_int reg:4;
- u_int sbz2:2;
-};
-
-union palette {
- struct vidc20_palette vidc20;
- struct vidc_palette vidc;
- u_int p;
-};
-struct acornfb_par {
- unsigned long screen_base;
- unsigned long screen_base_p;
- unsigned long screen_end;
- unsigned long screen_size;
- unsigned int dram_size;
- unsigned int vram_half_sam;
- unsigned int palette_size;
- signed int montype;
- signed int currcon;
- unsigned int allow_modeset : 1;
- unsigned int using_vram : 1;
- unsigned int dpms : 1;
-
- union palette palette[VIDC_PALETTE_SIZE];
-
- union {
- unsigned short cfb16[16];
- unsigned long cfb32[16];
- } cmap;
-};
+/*
+ * define this to debug the video mode selection
+ */
+#undef DEBUG_MODE_SELECTION
/*
* Translation from RISC OS monitor types to actual
* HSYNC and VSYNC frequency ranges. These are
- * probably not right...
+ * probably not right, but they're the best info I
+ * have. Allow 1% either way on the nominal for TVs.
*/
#define NR_MONTYPES 6
static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
- { 15625, 15625, 50, 50, 0 }, /* TV */
+ { 15469, 15781, 49, 51, 0 }, /* TV */
{ 0, 99999, 0, 99, 0 }, /* Multi Freq */
{ 58608, 58608, 64, 64, 0 }, /* Hi-res mono */
{ 30000, 70000, 60, 60, 0 }, /* VGA */
static struct display global_disp;
static struct fb_info fb_info;
static struct acornfb_par current_par;
+static struct vidc_timing current_vidc;
static struct fb_var_screeninfo __initdata init_var = {};
extern int acornfb_depth; /* set by setup.c */
extern unsigned int vram_size; /* set by setup.c */
-
-static struct vidc_timing {
- u_int h_cycle;
- u_int h_sync_width;
- u_int h_border_start;
- u_int h_display_start;
- u_int h_display_end;
- u_int h_border_end;
- u_int h_interlace;
-
- u_int v_cycle;
- u_int v_sync_width;
- u_int v_border_start;
- u_int v_display_start;
- u_int v_display_end;
- u_int v_border_end;
-
- u_int control;
-
- /* VIDC20 only */
- u_int pll_ctl;
-} current_vidc;
-
#ifdef HAS_VIDC
-#define VID_CTL_VS_NVSYNC (1 << 3)
-#define VID_CTL_HS_NHSYNC (1 << 2)
-#define VID_CTL_24MHz (0)
-#define VID_CTL_25MHz (1)
-#define VID_CTL_36MHz (2)
-
-#define VIDC_CTRL_INTERLACE (1 << 6)
-#define VIDC_CTRL_FIFO_0_4 (0 << 4)
-#define VIDC_CTRL_FIFO_1_5 (1 << 4)
-#define VIDC_CTRL_FIFO_2_6 (2 << 4)
-#define VIDC_CTRL_FIFO_3_7 (3 << 4)
-#define VIDC_CTRL_1BPP (0 << 2)
-#define VIDC_CTRL_2BPP (1 << 2)
-#define VIDC_CTRL_4BPP (2 << 2)
-#define VIDC_CTRL_8BPP (3 << 2)
-#define VIDC_CTRL_DIV3 (0 << 0)
-#define VIDC_CTRL_DIV2 (1 << 0)
-#define VIDC_CTRL_DIV1_5 (2 << 0)
-#define VIDC_CTRL_DIV1 (3 << 0)
-
/* CTL VIDC Actual
* 24.000 0 8.000
* 25.175 0 8.392
#endif
#ifdef HAS_VIDC20
-/*
- * VIDC20 registers
- */
-#define VIDC20_CTRL 0xe0000000
-#define VIDC20_CTRL_PIX_VCLK (0 << 0)
-#define VIDC20_CTRL_PIX_HCLK (1 << 0)
-#define VIDC20_CTRL_PIX_RCLK (2 << 0)
-#define VIDC20_CTRL_PIX_CK (0 << 2)
-#define VIDC20_CTRL_PIX_CK2 (1 << 2)
-#define VIDC20_CTRL_PIX_CK3 (2 << 2)
-#define VIDC20_CTRL_PIX_CK4 (3 << 2)
-#define VIDC20_CTRL_PIX_CK5 (4 << 2)
-#define VIDC20_CTRL_PIX_CK6 (5 << 2)
-#define VIDC20_CTRL_PIX_CK7 (6 << 2)
-#define VIDC20_CTRL_PIX_CK8 (7 << 2)
-#define VIDC20_CTRL_1BPP (0 << 5)
-#define VIDC20_CTRL_2BPP (1 << 5)
-#define VIDC20_CTRL_4BPP (2 << 5)
-#define VIDC20_CTRL_8BPP (3 << 5)
-#define VIDC20_CTRL_16BPP (4 << 5)
-#define VIDC20_CTRL_32BPP (6 << 5)
-#define VIDC20_CTRL_FIFO_NS (0 << 8)
-#define VIDC20_CTRL_FIFO_4 (1 << 8)
-#define VIDC20_CTRL_FIFO_8 (2 << 8)
-#define VIDC20_CTRL_FIFO_12 (3 << 8)
-#define VIDC20_CTRL_FIFO_16 (4 << 8)
-#define VIDC20_CTRL_FIFO_20 (5 << 8)
-#define VIDC20_CTRL_FIFO_24 (6 << 8)
-#define VIDC20_CTRL_FIFO_28 (7 << 8)
-#define VIDC20_CTRL_INT (1 << 12)
-#define VIDC20_CTRL_DUP (1 << 13)
-#define VIDC20_CTRL_PDOWN (1 << 14)
-
-#define VIDC20_ECTL 0xc0000000
-#define VIDC20_ECTL_REG(x) ((x) & 0xf3)
-#define VIDC20_ECTL_ECK (1 << 2)
-#define VIDC20_ECTL_REDPED (1 << 8)
-#define VIDC20_ECTL_GREENPED (1 << 9)
-#define VIDC20_ECTL_BLUEPED (1 << 10)
-#define VIDC20_ECTL_DAC (1 << 12)
-#define VIDC20_ECTL_LCDGS (1 << 13)
-#define VIDC20_ECTL_HRM (1 << 14)
-
-#define VIDC20_ECTL_HS_MASK (3 << 16)
-#define VIDC20_ECTL_HS_HSYNC (0 << 16)
-#define VIDC20_ECTL_HS_NHSYNC (1 << 16)
-#define VIDC20_ECTL_HS_CSYNC (2 << 16)
-#define VIDC20_ECTL_HS_NCSYNC (3 << 16)
-
-#define VIDC20_ECTL_VS_MASK (3 << 18)
-#define VIDC20_ECTL_VS_VSYNC (0 << 18)
-#define VIDC20_ECTL_VS_NVSYNC (1 << 18)
-#define VIDC20_ECTL_VS_CSYNC (2 << 18)
-#define VIDC20_ECTL_VS_NCSYNC (3 << 18)
-
-#define VIDC20_DCTL 0xf0000000
-/* 0-9 = number of words in scanline */
-#define VIDC20_DCTL_SNA (1 << 12)
-#define VIDC20_DCTL_HDIS (1 << 13)
-#define VIDC20_DCTL_BUS_NS (0 << 16)
-#define VIDC20_DCTL_BUS_D31_0 (1 << 16)
-#define VIDC20_DCTL_BUS_D63_32 (2 << 16)
-#define VIDC20_DCTL_BUS_D63_0 (3 << 16)
-#define VIDC20_DCTL_VRAM_DIS (0 << 18)
-#define VIDC20_DCTL_VRAM_PXCLK (1 << 18)
-#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18)
-#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18)
-
-#define acornfb_valid_pixrate(rate) (1)
-
-/*
- * Try to find the best PLL parameters for the pixel clock.
- * This algorithm seems to give best predictable results,
- * and produces the same values as detailed in the VIDC20
- * data sheet.
- */
-static inline u_int
-acornfb_vidc20_find_pll(u_int pixclk)
-{
- u_int r, best_r = 2, best_v = 2;
- int best_d = 0x7fffffff;
-
- for (r = 2; r <= 32; r++) {
- u_int rr, v, p;
- int d;
-
- rr = 41667 * r;
-
- v = (rr + pixclk / 2) / pixclk;
-
- if (v > 32 || v < 2)
- continue;
-
- p = (rr + v / 2) / v;
-
- d = pixclk - p;
-
- if (d < 0)
- d = -d;
-
- if (d < best_d) {
- best_d = d;
- best_v = v - 1;
- best_r = r - 1;
- }
-
- if (d == 0)
- break;
- }
-
- return best_v << 8 | best_r;
-}
-
-static inline void
-acornfb_vidc20_find_rates(struct vidc_timing *vidc,
- struct fb_var_screeninfo *var)
-{
- u_int div, bandwidth;
-
- /* Select pixel-clock divisor to keep PLL in range */
- div = var->pixclock / 9090; /*9921*/
-
- /* Limit divisor */
- if (div == 0)
- div = 1;
- if (div > 8)
- div = 8;
-
- /* Encode divisor to VIDC20 setting */
- switch (div) {
- case 1: vidc->control |= VIDC20_CTRL_PIX_CK; break;
- case 2: vidc->control |= VIDC20_CTRL_PIX_CK2; break;
- case 3: vidc->control |= VIDC20_CTRL_PIX_CK3; break;
- case 4: vidc->control |= VIDC20_CTRL_PIX_CK4; break;
- case 5: vidc->control |= VIDC20_CTRL_PIX_CK5; break;
- case 6: vidc->control |= VIDC20_CTRL_PIX_CK6; break;
- case 7: vidc->control |= VIDC20_CTRL_PIX_CK7; break;
- case 8: vidc->control |= VIDC20_CTRL_PIX_CK8; break;
- }
-
- /* Calculate bandwidth */
- bandwidth = var->pixclock * 8 / var->bits_per_pixel;
-
- /* Encode bandwidth as VIDC20 setting */
- if (bandwidth > 33334)
- vidc->control |= VIDC20_CTRL_FIFO_16; /* < 30.0MB/s */
- else if (bandwidth > 26666)
- vidc->control |= VIDC20_CTRL_FIFO_20; /* < 37.5MB/s */
- else if (bandwidth > 22222)
- vidc->control |= VIDC20_CTRL_FIFO_24; /* < 45.0MB/s */
- else
- vidc->control |= VIDC20_CTRL_FIFO_28; /* > 45.0MB/s */
-
- /* Find the PLL values */
- vidc->pll_ctl = acornfb_vidc20_find_pll(var->pixclock / div);
-}
+#include <asm/arch/acornfb.h>
/* VIDC20 has a different set of rules from the VIDC:
* hcr : must be multiple of 4
vidc.v_display_start = vidc.v_border_start;
vidc.v_display_end = vidc.v_display_start + var->yres;
vidc.v_border_end = vidc.v_display_end;
- vidc.control = VIDC20_CTRL_PIX_VCLK;
+ vidc.control = acornfb_default_control();
vcr = var->vsync_len + var->upper_margin + var->yres +
var->lower_margin;
outl(fsize, IOMD_FSIZE);
- ext_ctl = VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3);
+ ext_ctl = acornfb_default_econtrol();
if (var->sync & FB_SYNC_HOR_HIGH_ACT)
ext_ctl |= VIDC20_ECTL_HS_HSYNC;
* the resolution to fit the rules.
*/
static int
-acornfb_pre_adjust_timing(struct fb_var_screeninfo *var, int con)
+acornfb_adjust_timing(struct fb_var_screeninfo *var, int con)
{
u_int font_line_len;
u_int fontht;
if (var->yoffset + var->yres > var->yres_virtual)
var->yoffset = var->yres_virtual - var->yres;
}
- return 0;
-}
-/*
- * After selecting the timing parameters, adjust
- * the timing to suit the chip.
- * NOTE! Only minor adjustments should be made here.
- */
-static void
-acornfb_post_adjust_timing(struct fb_var_screeninfo *var)
-{
/* hsync_len must be even */
var->hsync_len = (var->hsync_len + 1) & ~1;
if (var->vsync_len < 1)
var->vsync_len = 1;
+
+ return 0;
+}
+
+static int
+acornfb_validate_timing(struct fb_var_screeninfo *var,
+ struct fb_monspecs *monspecs)
+{
+ unsigned long hs, vs;
+
+ /*
+ * hs(Hz) = 10^12 / (pixclock * xtotal)
+ * vs(Hz) = hs(Hz) / ytotal
+ *
+ * No need to do long long divisions or anything
+ * like that if you factor it correctly
+ */
+ hs = 1953125000 / var->pixclock;
+ hs = hs * 512 /
+ (var->xres + var->left_margin + var->right_margin + var->hsync_len);
+ vs = hs /
+ (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
+
+ return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
+ hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
}
static inline void
return -EINVAL;
/*
- * Validate and adjust the resolution
- * before using it.
+ * Validate and adjust the resolution to
+ * match the video generator hardware.
+ */
+ err = acornfb_adjust_timing(var, con);
+ if (err)
+ return err;
+
+ /*
+ * Validate the timing against the
+ * monitor hardware.
*/
- err = acornfb_pre_adjust_timing(var, con);
+ err = acornfb_validate_timing(var, &fb_info.monspecs);
if (err)
return err;
var->blue = var->red;
var->transp.length = 1;
#endif
- /*
- * Now adjust the timing parameters
- */
- acornfb_post_adjust_timing(var);
-
return 0;
}
acornfb_palette_write(i, p);
}
- } else {
+ }
+#ifdef FBCON_HAS_CFB16
+ else {
p.p = 0;
for (i = 0; i < 256; i++) {
acornfb_palette_write(i, current_par.palette[i]);
}
}
+#endif
}
/*
* Everything after here is initialisation!!!
*/
-struct modey_params {
- u_int y_res;
- u_int u_margin;
- u_int b_margin;
- u_int vsync_len;
- u_int vf;
-};
-
-struct modex_params {
- u_int x_res;
- u_int l_margin;
- u_int r_margin;
- u_int hsync_len;
- u_int clock;
- u_int hf;
- const struct modey_params *modey;
-};
-
-static const struct modey_params modey_640_15600[] __initdata = {
- { 250, 38, 21, 3, 50 }, /* 640x 250, 50Hz */
- { 256, 35, 18, 3, 50 }, /* 640x 256, 50Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_640_26800[] __initdata = {
- { 512, 18, 1, 3, 50 }, /* 640x 512, 50Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_640_31500[] __initdata = {
- { 250, 109, 88, 2, 70 }, /* 640x 250, 70Hz */
- { 256, 106, 85, 2, 70 }, /* 640x 256, 70Hz */
- { 352, 58, 37, 2, 70 }, /* 640x 352, 70Hz */
- { 480, 32, 11, 2, 60 }, /* 640x 480, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_800_35200[] __initdata = {
- { 600, 22, 1, 2, 56 }, /* 800x 600, 56Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_896_21800[] __initdata = {
- { 352, 9, 0, 3, 60 }, /* 896x 352, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-/* everything after here is not supported */
-static const struct modey_params modey_1024_uk[] __initdata = {
- { 768, 0, 0, 0, 0 }, /* 1024x 768 */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1056_uk[] __initdata = {
- { 250, 0, 0, 0, 0 }, /* 1056x 250 */
- { 256, 0, 0, 0, 0 }, /* 1056x 256 */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1152_uk[] __initdata = {
- { 896, 0, 0, 0, 0 }, /* 1152x 896 */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1280_63600[] __initdata = {
- { 1024, 0, 0, 0, 60 }, /* 1280x1024, 60Hz */
- { 0, 0, 0, 0, 0 }
-};
-
-static const struct modey_params modey_1600_uk[] __initdata = {
- { 1280, 0, 0, 0, 0 }, /* 1600x1280 */
- { 0, 0, 0, 0, 0 }
-};
-
-/*
- * Horizontal video programming requirements.
- * This table is searched for the required horizontal
- * and required frequency, and then the tables above
- * are then searched for the required vertical
- * resolution.
- *
- * NOTE! we can match multiple entries, so we search
- * all horizontal entries for which the hfreq is within
- * the monitor's range.
- */
-static const struct modex_params modex_params[] __initdata = {
- { /* X: 640, 15.6kHz */
- 640, 185, 123, 76, 16000, 15625, modey_640_15600
- },
- { /* X: 640, 26.8kHz */
- 640, 113, 87, 56, 24000, 26800, modey_640_26800
- },
- { /* X: 640, 31.5kHz */
- 640, 48, 16, 96, 25175, 31500, modey_640_31500
- },
- { /* X: 800, 35.2kHz */
- 800, 101, 23, 100, 36000, 35200, modey_800_35200
- },
- { /* X: 896, 21.8kHz */
- 896, 59, 27, 118, 24000, 21800, modey_896_21800
- },
- { /* X: 1024 */
- 1024, 0, 0, 0, 0, 0, modey_1024_uk
- },
- { /* X: 1056 */
- 1056, 0, 0, 0, 0, 0, modey_1056_uk
- },
- { /* X: 1152 */
- 1152, 0, 0, 0, 0, 0, modey_1152_uk
- },
- { /* X: 1280, 63.6kHz */
- 1280, 0, 0, 0, 0, 63600, modey_1280_63600
- },
- { /* X: 1600 */
- 1600, 0, 0, 0, 0, 0, modey_1600_uk
- },
- {
+static struct fb_videomode modedb[] __initdata = {
+ { /* 640x250 @ 50Hz, 15.6 kHz hsync */
+ NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3,
0,
- }
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */
+ NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */
+ NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */
+ NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */
+ NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */
+ NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2,
+ 0,
+ FB_VMODE_NONINTERLACED
+ }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */
+ NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3,
+ 0,
+ FB_VMODE_NONINTERLACED
+ },
};
-static int __init
-acornfb_lookup_timing(struct fb_var_screeninfo *var)
-{
- const struct modex_params *x;
- const struct modey_params *y;
-
- /*
- * We must adjust the resolution parameters
- * before selecting the timing parameters.
- */
- acornfb_pre_adjust_timing(var, -1);
-
- for (x = modex_params; x->x_res; x++) {
-
- /*
- * Is this resolution one we're looking for?
- */
- if (x->x_res != var->xres)
- continue;
-
- /*
- * Is the hsync frequency ok for our monitor?
- */
- if (x->hf > fb_info.monspecs.hfmax ||
- x->hf < fb_info.monspecs.hfmin)
- continue;
-
- /*
- * Try to find a vertical resolution
- */
- for (y = x->modey; y->y_res; y++) {
- /*
- * Is this resolution one we're looking for?
- */
- if (y->y_res != var->yres)
- continue;
-
- /*
- * Is the vsync frequency ok for our monitor?
- */
- if (y->vf > fb_info.monspecs.vfmax ||
- y->vf < fb_info.monspecs.vfmin)
- continue;
-
- goto found;
- }
- }
-
- var->pixclock = 0;
-
- return -EINVAL;
-
-found:
- /*
- * Why is pixclock in picoseconds?
- */
- switch (x->clock) {
- case 36000: var->pixclock = 27778; break;
- case 25175: var->pixclock = 39722; break;
- case 24000: var->pixclock = 41667; break;
- case 16000: var->pixclock = 62500; break;
- case 12000: var->pixclock = 83333; break;
- case 8000: var->pixclock = 125000; break;
- default: var->pixclock = 0; break;
- }
-
-#ifdef DEBUG_MODE_SELECTION
- printk(KERN_DEBUG "Found %dx%d at %d.%3dkHz, %dHz, pix %d\n",
- x->x_res, y->y_res,
- x->hf / 1000, x->hf % 1000,
- y->vf, var->pixclock);
-#endif
-
- var->left_margin = x->l_margin;
- var->right_margin = x->r_margin;
- var->upper_margin = y->u_margin;
- var->lower_margin = y->b_margin;
- var->hsync_len = x->hsync_len;
- var->vsync_len = y->vsync_len;
- var->sync = 0;
-
- /*
- * Now adjust the parameters we found
- */
- acornfb_post_adjust_timing(var);
-
- return 0;
-}
+static struct fb_videomode __initdata
+acornfb_default_mode = {
+ name: NULL,
+ refresh: 60,
+ xres: 640,
+ yres: 480,
+ pixclock: 39722,
+ left_margin: 56,
+ right_margin: 16,
+ upper_margin: 34,
+ lower_margin: 9,
+ hsync_len: 88,
+ vsync_len: 2,
+ sync: 0,
+ vmode: FB_VMODE_NONINTERLACED
+};
static void __init
acornfb_init_fbinfo(void)
* setup initial parameters
*/
memset(&init_var, 0, sizeof(init_var));
- init_var.xres = DEFAULT_XRES;
- init_var.yres = DEFAULT_YRES;
-
-#if defined(FBCON_HAS_CFB4)
- init_var.bits_per_pixel = 4;
-#elif defined(FBCON_HAS_CFB8)
- init_var.bits_per_pixel = 8;
-#elif defined(FBCON_HAS_CFB2)
- init_var.bits_per_pixel = 2;
-#elif defined(FBCON_HAS_MFB)
- init_var.bits_per_pixel = 1;
-#else
-#error No suitable framebuffers configured
-#endif
#if defined(HAS_VIDC20)
init_var.red.length = 8;
{
unsigned long size;
u_int h_sync, v_sync;
+ int rc, i;
acornfb_init_fbinfo();
fb_info.monspecs = monspecs[current_par.montype];
fb_info.monspecs.dpms = current_par.dpms;
+ /*
+ * Try to select a suitable default mode
+ */
+ for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
+ unsigned long hs;
+
+ hs = modedb[i].refresh *
+ (modedb[i].yres + modedb[i].upper_margin +
+ modedb[i].lower_margin + modedb[i].vsync_len);
+ if (modedb[i].xres == DEFAULT_XRES &&
+ modedb[i].yres == DEFAULT_YRES &&
+ modedb[i].refresh >= fb_info.monspecs.vfmin &&
+ modedb[i].refresh <= fb_info.monspecs.vfmax &&
+ hs >= fb_info.monspecs.hfmin &&
+ hs <= fb_info.monspecs.hfmax) {
+ acornfb_default_mode = modedb[i];
+ break;
+ }
+ }
+
current_par.currcon = -1;
current_par.screen_base = SCREEN2_BASE;
current_par.screen_base_p = SCREEN_START;
if (current_par.screen_base == 0) {
printk(KERN_ERR "acornfb: unable to allocate screen "
"memory\n");
- return;
+ return -ENOMEM;
}
top = current_par.screen_base + (PAGE_SIZE * (1 << order));
/* Mark the framebuffer pages as reserved so mmap will work. */
* find it, then we can't restore it if we change
* the resolution, so we disable this feature.
*/
- if (acornfb_lookup_timing(&init_var))
- current_par.allow_modeset = 0;
+ rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
+ sizeof(modedb) / sizeof(*modedb),
+ &acornfb_default_mode, DEFAULT_BPP);
+
+ if (!rc && fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
+ &acornfb_default_mode, DEFAULT_BPP)) {
+ printk("Acornfb: no valid mode found\n");
+ }
/*
* Again, if this does not succeed, then we disallow
--- /dev/null
+/*
+ * linux/drivers/video/acornfb.h
+ *
+ * Copyright (C) 1998,1999 Russell King
+ *
+ * Frame buffer code for Acorn platforms
+ */
+#if defined(HAS_VIDC20)
+#include <asm/iomd.h>
+#define VIDC_PALETTE_SIZE 256
+#define VIDC_NAME "VIDC20"
+#elif defined(HAS_VIDC)
+#include <asm/memc.h>
+#define VIDC_PALETTE_SIZE 16
+#define VIDC_NAME "VIDC"
+#endif
+
+#define EXTEND8(x) ((x)|(x)<<8)
+#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12)
+
+struct vidc20_palette {
+ u_int red:8;
+ u_int green:8;
+ u_int blue:8;
+ u_int ext:4;
+ u_int unused:4;
+};
+
+struct vidc_palette {
+ u_int red:4;
+ u_int green:4;
+ u_int blue:4;
+ u_int trans:1;
+ u_int sbz1:13;
+ u_int reg:4;
+ u_int sbz2:2;
+};
+
+union palette {
+ struct vidc20_palette vidc20;
+ struct vidc_palette vidc;
+ u_int p;
+};
+
+struct acornfb_par {
+ unsigned long screen_base;
+ unsigned long screen_base_p;
+ unsigned long screen_end;
+ unsigned long screen_size;
+ unsigned int dram_size;
+ unsigned int vram_half_sam;
+ unsigned int palette_size;
+ signed int montype;
+ signed int currcon;
+ unsigned int allow_modeset : 1;
+ unsigned int using_vram : 1;
+ unsigned int dpms : 1;
+
+ union palette palette[VIDC_PALETTE_SIZE];
+
+ union {
+ unsigned short cfb16[16];
+ unsigned long cfb32[16];
+ } cmap;
+};
+
+struct vidc_timing {
+ u_int h_cycle;
+ u_int h_sync_width;
+ u_int h_border_start;
+ u_int h_display_start;
+ u_int h_display_end;
+ u_int h_border_end;
+ u_int h_interlace;
+
+ u_int v_cycle;
+ u_int v_sync_width;
+ u_int v_border_start;
+ u_int v_display_start;
+ u_int v_display_end;
+ u_int v_border_end;
+
+ u_int control;
+
+ /* VIDC20 only */
+ u_int pll_ctl;
+};
+
+struct modey_params {
+ u_int y_res;
+ u_int u_margin;
+ u_int b_margin;
+ u_int vsync_len;
+ u_int vf;
+};
+
+struct modex_params {
+ u_int x_res;
+ u_int l_margin;
+ u_int r_margin;
+ u_int hsync_len;
+ u_int clock;
+ u_int hf;
+ const struct modey_params *modey;
+};
+
+#ifdef HAS_VIDC
+
+#define VID_CTL_VS_NVSYNC (1 << 3)
+#define VID_CTL_HS_NHSYNC (1 << 2)
+#define VID_CTL_24MHz (0)
+#define VID_CTL_25MHz (1)
+#define VID_CTL_36MHz (2)
+
+#define VIDC_CTRL_INTERLACE (1 << 6)
+#define VIDC_CTRL_FIFO_0_4 (0 << 4)
+#define VIDC_CTRL_FIFO_1_5 (1 << 4)
+#define VIDC_CTRL_FIFO_2_6 (2 << 4)
+#define VIDC_CTRL_FIFO_3_7 (3 << 4)
+#define VIDC_CTRL_1BPP (0 << 2)
+#define VIDC_CTRL_2BPP (1 << 2)
+#define VIDC_CTRL_4BPP (2 << 2)
+#define VIDC_CTRL_8BPP (3 << 2)
+#define VIDC_CTRL_DIV3 (0 << 0)
+#define VIDC_CTRL_DIV2 (1 << 0)
+#define VIDC_CTRL_DIV1_5 (2 << 0)
+#define VIDC_CTRL_DIV1 (3 << 0)
+
+#endif
+
+#ifdef HAS_VIDC20
+/*
+ * VIDC20 registers
+ */
+#define VIDC20_CTRL 0xe0000000
+#define VIDC20_CTRL_PIX_VCLK (0 << 0)
+#define VIDC20_CTRL_PIX_HCLK (1 << 0)
+#define VIDC20_CTRL_PIX_RCLK (2 << 0)
+#define VIDC20_CTRL_PIX_CK (0 << 2)
+#define VIDC20_CTRL_PIX_CK2 (1 << 2)
+#define VIDC20_CTRL_PIX_CK3 (2 << 2)
+#define VIDC20_CTRL_PIX_CK4 (3 << 2)
+#define VIDC20_CTRL_PIX_CK5 (4 << 2)
+#define VIDC20_CTRL_PIX_CK6 (5 << 2)
+#define VIDC20_CTRL_PIX_CK7 (6 << 2)
+#define VIDC20_CTRL_PIX_CK8 (7 << 2)
+#define VIDC20_CTRL_1BPP (0 << 5)
+#define VIDC20_CTRL_2BPP (1 << 5)
+#define VIDC20_CTRL_4BPP (2 << 5)
+#define VIDC20_CTRL_8BPP (3 << 5)
+#define VIDC20_CTRL_16BPP (4 << 5)
+#define VIDC20_CTRL_32BPP (6 << 5)
+#define VIDC20_CTRL_FIFO_NS (0 << 8)
+#define VIDC20_CTRL_FIFO_4 (1 << 8)
+#define VIDC20_CTRL_FIFO_8 (2 << 8)
+#define VIDC20_CTRL_FIFO_12 (3 << 8)
+#define VIDC20_CTRL_FIFO_16 (4 << 8)
+#define VIDC20_CTRL_FIFO_20 (5 << 8)
+#define VIDC20_CTRL_FIFO_24 (6 << 8)
+#define VIDC20_CTRL_FIFO_28 (7 << 8)
+#define VIDC20_CTRL_INT (1 << 12)
+#define VIDC20_CTRL_DUP (1 << 13)
+#define VIDC20_CTRL_PDOWN (1 << 14)
+
+#define VIDC20_ECTL 0xc0000000
+#define VIDC20_ECTL_REG(x) ((x) & 0xf3)
+#define VIDC20_ECTL_ECK (1 << 2)
+#define VIDC20_ECTL_REDPED (1 << 8)
+#define VIDC20_ECTL_GREENPED (1 << 9)
+#define VIDC20_ECTL_BLUEPED (1 << 10)
+#define VIDC20_ECTL_DAC (1 << 12)
+#define VIDC20_ECTL_LCDGS (1 << 13)
+#define VIDC20_ECTL_HRM (1 << 14)
+
+#define VIDC20_ECTL_HS_MASK (3 << 16)
+#define VIDC20_ECTL_HS_HSYNC (0 << 16)
+#define VIDC20_ECTL_HS_NHSYNC (1 << 16)
+#define VIDC20_ECTL_HS_CSYNC (2 << 16)
+#define VIDC20_ECTL_HS_NCSYNC (3 << 16)
+
+#define VIDC20_ECTL_VS_MASK (3 << 18)
+#define VIDC20_ECTL_VS_VSYNC (0 << 18)
+#define VIDC20_ECTL_VS_NVSYNC (1 << 18)
+#define VIDC20_ECTL_VS_CSYNC (2 << 18)
+#define VIDC20_ECTL_VS_NCSYNC (3 << 18)
+
+#define VIDC20_DCTL 0xf0000000
+/* 0-9 = number of words in scanline */
+#define VIDC20_DCTL_SNA (1 << 12)
+#define VIDC20_DCTL_HDIS (1 << 13)
+#define VIDC20_DCTL_BUS_NS (0 << 16)
+#define VIDC20_DCTL_BUS_D31_0 (1 << 16)
+#define VIDC20_DCTL_BUS_D63_32 (2 << 16)
+#define VIDC20_DCTL_BUS_D63_0 (3 << 16)
+#define VIDC20_DCTL_VRAM_DIS (0 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK (1 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18)
+#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18)
+
+#endif
#define DEFAULT_YRES 480
#define DEFAULT_BPP 8
-static volatile unsigned char *CyberRegs;
+#define MMIO_SIZE 0x000c0000
+
+static char *CyberRegs;
#include "cyber2000fb.h"
static struct display_switch *dispsw;
static struct fb_var_screeninfo __initdata init_var = {};
-#ifdef DEBUG
+#if defined(DEBUG) && defined(CONFIG_DEBUG_LL)
static void debug_printf(char *fmt, ...)
{
char buffer[128];
#define debug_printf(x...) do { } while (0)
#endif
-/*
- * Predefined Video Modes
- */
-static const struct res cyber2000_res[] = {
- {
- 640, 480,
- {
- 0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
- 0x00, 0x40,
- 0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
- },
- 0x00,
- { 0xd2, 0xce, 0xdb, 0x54 }
- },
-
- {
- 800, 600,
- {
- 0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
- 0x00, 0x60,
- 0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
- },
- 0x00,
- { 0x52, 0x85, 0xdb, 0x54 }
- },
-
- {
- 1024, 768,
- {
- 0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
- 0x00, 0x60,
- 0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
- },
- 0x00,
- { 0xd0, 0x52, 0xdb, 0x54 }
- },
-#if 0
- {
- 1152, 886,
- {
- },
- {
- }
- },
-#endif
- {
- 1280, 1024,
- {
- 0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
- 0x00, 0x40,
- 0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
- },
- 0x1d,
- { 0xb4, 0x4b, 0xdb, 0x54 }
- },
-
- {
- 1600, 1200,
- {
- 0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
- 0x00, 0x40,
- 0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
- },
- 0x1f,
- { 0xbd, 0x10, 0xdb, 0x54 }
- }
-};
-
-#define NUM_TOTAL_MODES arraysize(cyber2000_res)
-
-static const char igs_regs[] = {
- 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
- 0x30, 0x21, 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
- 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x70, 0x0b, 0x71, 0x10, 0x72, 0x45, 0x73, 0x30,
- 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
-};
-
-static const char crtc_idx[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
-};
-
-static void cyber2000_init_hw(const struct res *res)
-{
- int i;
-
- debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
-
- cyber2000_outb(0xef, 0x3c2);
- cyber2000_crtcw(0x11, 0x0b);
- cyber2000_attrw(0x11, 0x00);
-
- cyber2000_seqw(0x00, 0x01);
- cyber2000_seqw(0x01, 0x01);
- cyber2000_seqw(0x02, 0x0f);
- cyber2000_seqw(0x03, 0x00);
- cyber2000_seqw(0x04, 0x0e);
- cyber2000_seqw(0x00, 0x03);
-
- for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(crtc_idx[i], res->crtc_regs[i]);
-
- for (i = 0x0a; i < 0x10; i++)
- cyber2000_crtcw(i, 0);
-
- cyber2000_crtcw(0x18, 0xff);
-
- cyber2000_grphw(0x00, 0x00);
- cyber2000_grphw(0x01, 0x00);
- cyber2000_grphw(0x02, 0x00);
- cyber2000_grphw(0x03, 0x00);
- cyber2000_grphw(0x04, 0x00);
- cyber2000_grphw(0x05, 0x60);
- cyber2000_grphw(0x06, 0x05);
- cyber2000_grphw(0x07, 0x0f);
- cyber2000_grphw(0x08, 0xff);
-
- for (i = 0; i < 16; i++)
- cyber2000_attrw(i, i);
-
- cyber2000_attrw(0x10, 0x01);
- cyber2000_attrw(0x11, 0x00);
- cyber2000_attrw(0x12, 0x0f);
- cyber2000_attrw(0x13, 0x00);
- cyber2000_attrw(0x14, 0x00);
-
- for (i = 0; i < sizeof(igs_regs); i += 2)
- cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
-
- cyber2000_grphw(0x11, res->crtc_ofl);
-
- for (i = 0; i < 4; i += 1)
- cyber2000_grphw(0xb0 + i, res->clk_regs[i]);
-
- cyber2000_grphw(0x90, 0x01);
- cyber2000_grphw(0xb9, 0x80);
- cyber2000_grphw(0xb9, 0x00);
-
- cyber2000_outb(0x56, 0x3ce);
- i = cyber2000_inb(0x3cf);
- cyber2000_outb(i | 4, 0x3cf);
- cyber2000_outb(0x04, 0x3c6);
- cyber2000_outb(i, 0x3cf);
-
- cyber2000_outb(0x20, 0x3c0);
- cyber2000_outb(0xff, 0x3c6);
-
- for (i = 0; i < 256; i++) {
- cyber2000_outb(i, 0x3c8);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- }
-}
-
-
-static struct fb_ops cyber2000fb_ops;
-
/* -------------------- Hardware specific routines ------------------------- */
/*
{
int count = 10000;
- while (cyber2000_inb(0xbf011) & 0x80) {
+ while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {
if (!count--) {
debug_printf("accel_wait timed out\n");
- cyber2000_outb(0, 0xbf011);
+ cyber2000_outb(0, CO_REG_CONTROL);
return;
}
udelay(10);
cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
- unsigned long src, dst, chwidth = p->var.xres_virtual * fontheight(p);
- int v = 0x8000;
+ unsigned long src, dst;
+ unsigned int fh, fw;
+ int cmd = CO_CMD_L_PATTERN_FGCOL;
+
+ fw = fontwidth(p);
+ sx *= fw;
+ dx *= fw;
+ width *= fw;
+ width -= 1;
if (sx < dx) {
- sx += width - 1;
- dx += width - 1;
- v |= 4;
+ sx += width;
+ dx += width;
+ cmd |= CO_CMD_L_INC_LEFT;
}
+ fh = fontheight(p);
+ sy *= fh;
+ dy *= fh;
+ height *= fh;
+ height -= 1;
+
if (sy < dy) {
- sy += height - 1;
- dy += height - 1;
- v |= 2;
+ sy += height;
+ dy += height;
+ cmd |= CO_CMD_L_INC_UP;
}
- sx *= fontwidth(p);
- dx *= fontwidth(p);
- src = sx + sy * chwidth;
- dst = dx + dy * chwidth;
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ src = sx + sy * p->var.xres_virtual;
+ dst = dx + dy * p->var.xres_virtual;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
if (p->var.bits_per_pixel != 24) {
- cyber2000_outl(dst, 0xbf178);
- cyber2000_outl(src, 0xbf170);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
+ cyber2000_outl(src, CO_REG_SRC_PTR);
} else {
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
- cyber2000_outl(src * 3, 0xbf170);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
+ cyber2000_outl(src * 3, CO_REG_SRC_PTR);
}
- cyber2000_outw(height, 0xbf062);
- cyber2000_outw(v, 0xbf07c);
- cyber2000_outw(0x2800, 0xbf07e);
+ cyber2000_outw(height, CO_REG_HEIGHT);
+ cyber2000_outw(cmd, CO_REG_CMD_L);
+ cyber2000_outw(0x2800, CO_REG_CMD_H);
}
static void
int height, int width)
{
unsigned long dst;
+ unsigned int fw, fh;
u32 bgx = attr_bgcol_ec(p, conp);
- dst = sx * fontwidth(p) + sy * p->var.xres_virtual * fontheight(p);
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ fw = fontwidth(p);
+ fh = fontheight(p);
+
+ dst = sx * fw + sy * p->var.xres_virtual * fh;
+ width = width * fw - 1;
+ height = height * fh - 1;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
- cyber2000_outw(height, 0xbf062);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
+ cyber2000_outw(height, CO_REG_HEIGHT);
switch (p->var.bits_per_pixel) {
case 15:
case 16:
bgx = ((u16 *)p->dispsw_data)[bgx];
case 8:
- cyber2000_outl(dst, 0xbf178);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
break;
case 24:
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
bgx = ((u32 *)p->dispsw_data)[bgx];
break;
}
- cyber2000_outl(bgx, 0xbf058);
- cyber2000_outw(0x8000, 0xbf07c);
- cyber2000_outw(0x0800, 0xbf07e);
+ cyber2000_outl(bgx, CO_REG_FOREGROUND);
+ cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);
+ cyber2000_outw(0x0800, CO_REG_CMD_H);
}
static void
return 0;
}
-static void cyber2000fb_calculate_timing(unsigned char *v, struct fb_var_screeninfo *var)
-{
- int Htotal, Hdispend, Hblankstart, Hblankend, Hsyncstart, Hsyncend;
- int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
-#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
-
- Hdispend = var->xres;
- Hsyncstart = var->xres + var->right_margin;
- Hsyncend = var->xres + var->right_margin + var->hsync_len;
- Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
-
- Hblankstart = var->xres;
- Hblankend = Htotal - 4*8;
+struct par_info {
+ /*
+ * Hardware
+ */
+ unsigned char clock_mult;
+ unsigned char clock_div;
+ unsigned char visualid;
+ unsigned char pixformat;
+ unsigned char crtc_ofl;
+ unsigned char crtc[19];
+ unsigned int width;
+ unsigned int pitch;
- Vdispend = var->yres;
- Vsyncstart = var->yres + var->lower_margin;
- Vsyncend = var->yres + var->lower_margin + var->vsync_len;
- Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
-
- Vblankstart = var->yres + 7;
- Vblankend = Vtotal - 11;
-
- Hdispend >>= 3;
- Hsyncstart >>= 3;
- Hsyncend >>= 3;
- Htotal >>= 3;
- Hblankstart >>= 3;
- Hblankend >>= 3;
-
- Htotal -= 5;
- Hdispend -= 1;
- Vtotal -= 2;
- Vdispend -= 1;
- Vblankstart -= 1;
- Vblankend -= 1;
-
- v[0] = Htotal;
- v[1] = Hdispend;
- v[2] = Hblankstart;
- v[3] = BIT(Hblankend, 0, 0x1f, 0) |
- BIT(1, 0, 0x01, 7);
- v[4] = Hsyncstart;
- v[5] = BIT(Hsyncend, 0, 0x1f, 0) |
- BIT(Hblankend, 5, 0x01, 7);
-
- v[6] = Vtotal;
- v[7] = BIT(Vtotal, 8, 0x01, 0) |
- BIT(Vdispend, 8, 0x01, 1) |
- BIT(Vsyncstart, 8, 0x01, 2) |
- BIT(Vblankstart,8, 0x01, 3) |
- BIT(1, 0, 0x01, 4) |
- BIT(Vtotal, 9, 0x01, 5) |
- BIT(Vdispend, 9, 0x01, 6) |
- BIT(Vsyncstart, 9, 0x01, 7);
- v[8] = 0;
- v[9] = BIT(0, 0, 0x1f, 0) |
- BIT(Vblankstart,9, 0x01, 5) |
- BIT(1, 0, 0x01, 6);
- v[10] = Vsyncstart;
- v[11] = BIT(Vsyncend, 0, 0x0f, 0) |
- BIT(1, 0, 0x01, 7);
- v[12] = Vdispend;
- v[14] = 0;
- v[15] = Vblankstart;
- v[16] = Vblankend;
- v[17] = 0xe3;
+ /*
+ * Other
+ */
+ unsigned int visual;
+};
- /* overflow - graphics reg 0x11 */
- v[18] = BIT(Vtotal, 10, 0x01, 0) | /* guess */
- BIT(Vdispend, 10, 0x01, 1) |
- BIT(Vsyncstart, 10, 0x01, 2) | /* guess */
- BIT(Vblankstart,10, 0x01, 3) | /* guess */
- BIT(Hblankend, 6, 0x01, 4); /* guess */
-}
+static const char crtc_idx[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
+};
-static void cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+static void cyber2000fb_set_timing(struct par_info *hw)
{
- unsigned int width = var->xres_virtual;
- unsigned int scr_pitch, fetchrow, i;
- char b, graph_r77, crtc[32];
+ unsigned int fetchrow, i;
- switch (var->bits_per_pixel) {
- case 8: /* PSEUDOCOLOUR, 256 */
- b = 0;
- graph_r77 = 1;
- scr_pitch = width;
- break;
+ /*
+ * Blank palette
+ */
+ for (i = 0; i < 256; i++) {
+ cyber2000_outb(i, 0x3c8);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
+ }
- case 15:/* DIRECTCOLOUR, 32k */
- b = 1;
- graph_r77 = 6;
- scr_pitch = width * 2;
- break;
+ cyber2000_outb(0xef, 0x3c2);
+ cyber2000_crtcw(0x11, 0x0b);
+ cyber2000_attrw(0x11, 0x00);
- case 16:/* DIRECTCOLOUR, 64k */
- b = 1;
- graph_r77 = 2;
- scr_pitch = width * 2;
- break;
+ cyber2000_seqw(0x00, 0x01);
+ cyber2000_seqw(0x01, 0x01);
+ cyber2000_seqw(0x02, 0x0f);
+ cyber2000_seqw(0x03, 0x00);
+ cyber2000_seqw(0x04, 0x0e);
+ cyber2000_seqw(0x00, 0x03);
- case 24:/* TRUECOLOUR, 16m */
- b = 2;
- graph_r77 = 4;
- width *= 3;
- scr_pitch = width;
- break;
+ for (i = 0; i < sizeof(crtc_idx); i++)
+ cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);
- default:
- return;
- }
+ for (i = 0x0a; i < 0x10; i++)
+ cyber2000_crtcw(i, 0);
- width -= 1;
- scr_pitch >>= 3;
- fetchrow = scr_pitch + 1;
+ cyber2000_grphw(0x11, hw->crtc_ofl);
+ cyber2000_grphw(0x00, 0x00);
+ cyber2000_grphw(0x01, 0x00);
+ cyber2000_grphw(0x02, 0x00);
+ cyber2000_grphw(0x03, 0x00);
+ cyber2000_grphw(0x04, 0x00);
+ cyber2000_grphw(0x05, 0x60);
+ cyber2000_grphw(0x06, 0x05);
+ cyber2000_grphw(0x07, 0x0f);
+ cyber2000_grphw(0x08, 0xff);
- cyber2000fb_calculate_timing(crtc, var);
+ /* Attribute controller registers */
+ for (i = 0; i < 16; i++)
+ cyber2000_attrw(i, i);
- for (i = 0; i < NUM_TOTAL_MODES; i++)
- if (var->xres == cyber2000_res[i].xres &&
- var->yres == cyber2000_res[i].yres)
- break;
+ cyber2000_attrw(0x10, 0x01);
+ cyber2000_attrw(0x11, 0x00);
+ cyber2000_attrw(0x12, 0x0f);
+ cyber2000_attrw(0x13, 0x00);
+ cyber2000_attrw(0x14, 0x00);
- if (i < NUM_TOTAL_MODES)
- cyber2000_init_hw(cyber2000_res + i);
+ /* PLL registers */
+ cyber2000_grphw(0xb0, hw->clock_mult);
+ cyber2000_grphw(0xb1, hw->clock_div);
+ cyber2000_grphw(0xb2, 0xdb);
+ cyber2000_grphw(0xb3, 0x54); /* MCLK: 75MHz */
+ cyber2000_grphw(0x90, 0x01);
+ cyber2000_grphw(0xb9, 0x80);
+ cyber2000_grphw(0xb9, 0x00);
- crtc[13] = scr_pitch;
+ cyber2000_outb(0x56, 0x3ce);
+ i = cyber2000_inb(0x3cf);
+ cyber2000_outb(i | 4, 0x3cf);
+ cyber2000_outb(0x04, 0x3c6);
+ cyber2000_outb(i, 0x3cf);
- /*
- * reprogram the CRTC with the values we calculated
- * above. This should be cleaned up once we're
- * confident that we're generating the correct
- * values. Disable this if you're having problems,
- * and report the values obtained from the kernel
- * messages.
- */
-#if 1
- cyber2000_crtcw(0x11, 0x0b);
- for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(crtc_idx[i], crtc[i]);
-#else
- cyber2000_crtcw(0x13, crtc[13]);
-#endif
+ cyber2000_outb(0x20, 0x3c0);
+ cyber2000_outb(0xff, 0x3c6);
+ fetchrow = hw->pitch + 1;
cyber2000_grphw(0x14, fetchrow);
- /* FIXME: is this the right way round? */
- cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f));
- cyber2000_grphw(0x77, graph_r77);
+ /* FIXME: is this the right way round? */
+ cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((hw->pitch >> 8) & 0x0f));
+ cyber2000_grphw(0x77, hw->visualid);
cyber2000_grphw(0x33, 0x1c);
- cyber2000_outw(width, 0xbf018);
- cyber2000_outw(width, 0xbf218);
- cyber2000_outb(b, 0xbf01c);
-
-#if 0
-{ int j; i = 0;
- printk(KERN_DEBUG);
- for (j = 0; j < 19; j++) printk("%2d ", j); printk("\n"KERN_DEBUG);
- for (j = 0; j < 19; j++) printk("%02X ", crtc[j]); printk("\n"KERN_DEBUG);
- for (j = 0; j < 18; j++) printk("%02X ", cyber2000_res[i].crtc_regs[j]);
- printk("%02X\n", cyber2000_res[i].crtc_ofl);
-}
-#endif
+ /*
+ * Set up accelerator registers
+ */
+ cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);
+ cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);
+ cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);
}
-static inline void
+static inline int
cyber2000fb_update_start(struct fb_var_screeninfo *var)
{
-#if 0
unsigned int base;
base = var->yoffset * var->xres_virtual + var->xoffset;
- cyber2000_crtcw(0x0c, base);
- cyber2000_crtcw(0x0d, base >> 8);
- /* FIXME: need the upper bits of the start offset */
-/* cyber2000_crtcw(0x??, base >> 16);*/
-#endif
+ base >>= 2;
+
+ if (base >= 1 << 20)
+ return -EINVAL;
+
+ /*
+ * FIXME: need the upper bits of the start offset
+ */
+ cyber2000_grphw(0x10, base >> 16 | 0x10);
+ cyber2000_crtcw(0x0c, base >> 8);
+ cyber2000_crtcw(0x0d, base);
+
+ return 0;
}
/*
return err;
}
+static int cyber2000fb_decode_crtc(struct par_info *hw, struct fb_var_screeninfo *var)
+{
+ unsigned int Htotal, Hblankend, Hsyncend;
+ unsigned int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+ hw->crtc[13] = hw->pitch;
+ hw->crtc[17] = 0xe3;
+ hw->crtc[14] = 0;
+ hw->crtc[8] = 0;
+
+ Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ if (Htotal > 2080)
+ return -EINVAL;
+
+ hw->crtc[0] = (Htotal >> 3) - 5; /* Htotal */
+ hw->crtc[1] = (var->xres >> 3) - 1; /* Hdispend */
+ hw->crtc[2] = var->xres >> 3; /* Hblankstart */
+ hw->crtc[4] = (var->xres + var->right_margin) >> 3; /* Hsyncstart */
+
+ Hblankend = (Htotal - 4*8) >> 3;
+
+ hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) | /* Hblankend */
+ BIT(1, 0, 0x01, 7);
+
+ Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
+
+ hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) | /* Hsyncend */
+ BIT(Hblankend, 5, 0x01, 7);
+
+ Vdispend = var->yres - 1;
+ Vsyncstart = var->yres + var->lower_margin;
+ Vsyncend = var->yres + var->lower_margin + var->vsync_len;
+ Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
+
+ if (Vtotal > 2047)
+ return -EINVAL;
+
+ Vblankstart = var->yres + 6;
+ Vblankend = Vtotal - 10;
+
+ hw->crtc[6] = Vtotal;
+ hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
+ BIT(Vdispend, 8, 0x01, 1) |
+ BIT(Vsyncstart, 8, 0x01, 2) |
+ BIT(Vblankstart,8, 0x01, 3) |
+ BIT(1, 0, 0x01, 4) |
+ BIT(Vtotal, 9, 0x01, 5) |
+ BIT(Vdispend, 9, 0x01, 6) |
+ BIT(Vsyncstart, 9, 0x01, 7);
+ hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
+ BIT(Vblankstart,9, 0x01, 5) |
+ BIT(1, 0, 0x01, 6);
+ hw->crtc[10] = Vsyncstart;
+ hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
+ BIT(1, 0, 0x01, 7);
+ hw->crtc[12] = Vdispend;
+ hw->crtc[15] = Vblankstart;
+ hw->crtc[16] = Vblankend;
+ hw->crtc[18] = 0xff;
+
+ /* overflow - graphics reg 0x11 */
+/* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 4=LINECOMP:10 5-IVIDEO 6=FIXCNT */
+ hw->crtc_ofl =
+ BIT(Vtotal, 10, 0x01, 0) |
+ BIT(Vdispend, 10, 0x01, 1) |
+ BIT(Vsyncstart, 10, 0x01, 2) |
+ BIT(Vblankstart,10, 0x01, 3) |
+ 1 << 4;
+
+ return 0;
+}
+
+/*
+ * The following was discovered by a good monitor,
+ * bit twiddling, theorising and but mostly luck.
+ * Strangely, it looks like everyone elses' PLL!
+ *
+ * Clock registers:
+ * fclock = fpll / div2
+ * fpll = fref * mult / div1
+ * where:
+ * fref = 14.318MHz (69842ps)
+ * mult = reg0xb0.7:0
+ * div1 = (reg0xb1.5:0 + 1)
+ * div2 = 2^(reg0xb1.7:6)
+ * fpll should be between 150 and 220 MHz
+ * (6667ps and 4545ps)
+ */
static int
-cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
{
+ unsigned long pll_ps = var->pixclock;
+ unsigned long ref_ps = 69842;
+ int div2, div1, mult;
+
+ /*
+ * Step 1:
+ * find div2 such that 150MHz < fpll < 220MHz
+ * and 0 <= div2 < 4
+ */
+ for (div2 = 0; div2 < 4; div2++, pll_ps >>= 1)
+ if (6667 > pll_ps && pll_ps > 4545)
+ break;
+
+ if (div2 == 4)
+ return -EINVAL;
+
+#if 0
+ /*
+ * Step 2:
+ * Find fpll
+ * fpll = fref * mult / div1
+ *
+ * Note! This just picks any old values at the moment,
+ * and as such I don't trust it. It certainly doesn't
+ * come out with the values below, so the PLL may become
+ * unstable under some circumstances (you don't want an
+ * FM dot clock)
+ */
+ for (div1 = 32; div1 > 1; div1 -= 1) {
+ mult = (ref_ps * div1 + pll_ps / 2) / pll_ps;
+ if (mult < 256)
+ break;
+ }
+#else
+ if (pll_ps == 4630) { /* 216.0, 108.0, 54.00, 27.000 */
+ mult = 181; /* 4630 9260 18520 37040 */
+ div1 = 12;
+ } else if (pll_ps == 4965) { /* 201.0, 100.5, 50.25, 25.125 */
+ mult = 211; /* 4965 9930 19860 39720 */
+ div1 = 15;
+ } else if (pll_ps == 5050) { /* 198.0, 99.0, 49.50, 24.750 */
+ mult = 83; /* 5050 10100 20200 40400 */
+ div1 = 6;
+ } else if (pll_ps == 6349) { /* 158.0, 79.0, 39.50, 19.750 */
+ mult = 209; /* 6349 12698 25396 50792 */
+ div1 = 19;
+ } else if (pll_ps == 6422) { /* 156.0, 78.0, 39.00, 19.500 */
+ mult = 190; /* 6422 12844 25688 51376 */
+ div1 = 17;
+ } else
+ return -EINVAL;
+#endif
+ /*
+ * Step 3:
+ * combine values
+ */
+ hw->clock_mult = mult - 1;
+ hw->clock_div = div2 << 6 | (div1 - 1);
+
+ return 0;
+}
+
+/*
+ * Decode the info required for the hardware.
+ * This involves the PLL parameters for the dot clock,
+ * CRTC registers, and accelerator settings.
+ */
+static int
+cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, struct par_info *hw)
+{
+ int err;
+
+ hw->width = var->xres_virtual;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
- case 8:
- *visual = FB_VISUAL_PSEUDOCOLOR;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ hw->visual = FB_VISUAL_PSEUDOCOLOR;
+ hw->pixformat = PIXFORMAT_8BPP;
+ hw->visualid = VISUALID_256;
+ hw->pitch = hw->width >> 3;
break;
#endif
#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- *visual = FB_VISUAL_DIRECTCOLOR;
+ case 15:/* DIRECTCOLOUR, 32k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_32K;
+ hw->pitch = hw->width >> 2;
+ break;
+
+ case 16:/* DIRECTCOLOUR, 64k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_64K;
+ hw->pitch = hw->width >> 2;
break;
#endif
#ifdef FBCON_HAS_CFB24
- case 24:
- *visual = FB_VISUAL_TRUECOLOR;
+ case 24:/* TRUECOLOUR, 16m */
+ hw->visual = FB_VISUAL_TRUECOLOR;
+ hw->pixformat = PIXFORMAT_24BPP;
+ hw->visualid = VISUALID_16M;
+ hw->width *= 3;
+ hw->pitch = hw->width >> 3;
break;
#endif
default:
return -EINVAL;
}
+ err = cyber2000fb_decode_clock(hw, var);
+ if (err)
+ return err;
+
+ err = cyber2000fb_decode_crtc(hw, var);
+ if (err)
+ return err;
+
+ debug_printf("Clock: %02X %02X\n",
+ hw->clock_mult, hw->clock_div);
+ {
+ int i;
+
+ for (i = 0; i < 19; i++)
+ debug_printf("%2d ", i);
+ debug_printf("\n");
+ for (i = 0; i < 18; i++)
+ debug_printf("%02X ", hw->crtc[i]);
+ debug_printf("%02X\n", hw->crtc_ofl);
+ }
+ hw->width -= 1;
+
return 0;
}
struct display *display;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "Cyber2000");
+ strcpy(fix->id, current_par.dev_name);
if (con >= 0)
display = fb_display + con;
fix->smem_start = current_par.screen_base_p;
fix->smem_len = current_par.screen_size;
fix->mmio_start = current_par.regs_base_p;
- fix->mmio_len = 0x000c0000;
+ fix->mmio_len = MMIO_SIZE;
fix->type = display->type;
fix->type_aux = display->type_aux;
fix->xpanstep = 0;
cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct display *display;
- int err, chgvar = 0, visual;
+ struct par_info hw;
+ int err, chgvar = 0;
if (con >= 0)
display = fb_display + con;
else
display = &global_disp;
- err = cyber2000fb_decode_var(var, con, &visual);
+ err = cyber2000fb_decode_var(var, con, &hw);
if (err)
return err;
if (var->activate & FB_ACTIVATE_ALL)
global_disp.var = display->var;
- display->screen_base = (char *)current_par.screen_base;
- display->visual = visual;
+ display->screen_base = current_par.screen_base;
+ display->visual = hw.visual;
display->type = FB_TYPE_PACKED_PIXELS;
display->type_aux = 0;
- display->ypanstep = 0;
+ display->ypanstep = 1;
display->ywrapstep = 0;
display->can_soft_blank = 1;
display->inverse = 0;
break;
#endif
default:
- printk(KERN_WARNING "cyber2000: no support for %dbpp\n",
- display->var.bits_per_pixel);
+ printk(KERN_WARNING "%s: no support for %dbpp\n",
+ current_par.dev_name, display->var.bits_per_pixel);
dispsw = &fbcon_dummy;
break;
}
struct fb_cmap *cmap;
cyber2000fb_update_start(var);
- cyber2000fb_set_timing(var);
+ cyber2000fb_set_timing(&hw);
if (display->cmap.len)
cmap = &display->cmap;
return -EINVAL;
if (y_bottom > fb_display[con].var.yres_virtual)
return -EINVAL;
-/*disabled until we can update the start address properly */
-return -EINVAL;
- cyber2000fb_update_start(var);
+ if (cyber2000fb_update_start(var))
+ return -EINVAL;
fb_display[con].var.xoffset = var->xoffset;
fb_display[con].var.yoffset = var->yoffset;
static int
cyber2000fb_updatevar(int con, struct fb_info *info)
{
+ int ret = 0;
+
if (con == current_par.currcon)
- cyber2000fb_update_start(&fb_display[con].var);
- return 0;
+ ret = cyber2000fb_update_start(&fb_display[con].var);
+
+ return ret;
}
static int
}
}
-int __init cyber2000fb_setup(char *options)
-{
- return 0;
-}
-
static struct fb_ops cyber2000fb_ops =
{
cyber2000fb_open,
cyber2000fb_ioctl
};
+/*
+ * These parameters give
+ * 640x480, hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __initdata
+cyber2000fb_default_mode = {
+ name: NULL,
+ refresh: 60,
+ xres: 640,
+ yres: 480,
+ pixclock: 39722,
+ left_margin: 56,
+ right_margin: 16,
+ upper_margin: 34,
+ lower_margin: 9,
+ hsync_len: 88,
+ vsync_len: 2,
+ sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
static void __init
cyber2000fb_init_fbinfo(void)
{
* setup initial parameters
*/
memset(&init_var, 0, sizeof(init_var));
- init_var.xres_virtual =
- init_var.xres = DEFAULT_XRES;
- init_var.yres_virtual =
- init_var.yres = DEFAULT_YRES;
- init_var.bits_per_pixel = DEFAULT_BPP;
-
- /*
- * These parameters give
- * 640x480, hsync 31.5kHz, vsync 60Hz
- */
- init_var.left_margin = 56;
- init_var.right_margin = 16;
- init_var.upper_margin = 34;
- init_var.lower_margin = 9;
- init_var.hsync_len = 88;
- init_var.vsync_len = 2;
- init_var.pixclock = 39722;
init_var.red.msb_right = 0;
init_var.green.msb_right = 0;
init_var.height = -1;
init_var.width = -1;
init_var.accel_flags = FB_ACCELF_TEXT;
- init_var.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
- init_var.vmode = FB_VMODE_NONINTERLACED;
+}
+
+/*
+ * Cyber2000 options:
+ *
+ * font:fontname
+ * Set the fontname
+ *
+ * res:XxY
+ * Set the default display resolution
+ */
+static void __init
+cyber2000fb_parse_font(char *opt)
+{
+ strcpy(fb_info.fontname, opt);
+}
+
+static struct options {
+ char *name;
+ void (*parse)(char *opt);
+} opt_table[] __initdata = {
+ { "font", cyber2000fb_parse_font },
+ { NULL, NULL }
+};
+
+int __init
+cyber2000fb_setup(char *options)
+{
+ struct options *optp;
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ cyber2000fb_init_fbinfo();
+
+ for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+ if (!*opt)
+ continue;
+
+ for (optp = opt_table; optp->name; optp++) {
+ int optlen;
+
+ optlen = strlen(optp->name);
+
+ if (strncmp(opt, optp->name, optlen) == 0 &&
+ opt[optlen] == ':') {
+ optp->parse(opt + optlen + 1);
+ break;
+ }
+ }
+
+ if (!optp->name)
+ printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n",
+ opt);
+ }
+ return 0;
+}
+
+static char igs_regs[] __initdata = {
+ 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
+/* 0x30, 0x21,*/ 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
+ 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x70, 0x0b,/* 0x71, 0x10, 0x72, 0x45,*/ 0x73, 0x30,
+ 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
+};
+
+static void __init cyber2000fb_hw_init(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(igs_regs); i += 2)
+ cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
}
/*
{
struct pci_dev *dev;
u_int h_sync, v_sync;
- u_long base_p, base_v;
+ u_long mmio_base, smem_base, smem_size;
+ int err = 0;
+
+ dev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_2000, NULL);
+
+ if (!dev)
+ dev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_2010, NULL);
- dev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, NULL);
if (!dev)
return -ENXIO;
- /* this should be done by PCI generic code */
- base_p = 0x80000000 + dev->resource[0].start;
+ sprintf(current_par.dev_name, "CyberPro%4X", dev->device);
+
+ smem_base = dev->resource[0].start;
+ mmio_base = dev->resource[0].start + 0x00800000;
/*
- * This should be ioremap'd, thus:
- *
- * base_v = ioremap(dev->resource[0].start, dev->resource[0].end - dev->resource[0].start + 1);
+ * Map in the registers
*/
- base_v = (u_long)bus_to_virt(dev->resource[0].start);
+ if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) {
+ printk("%s: memory mapped IO in use\n",
+ current_par.dev_name);
+ return -EBUSY;
+ }
- /*FIXME*/
- CyberRegs = base_v + 0x00800000;
+ CyberRegs = ioremap(mmio_base, MMIO_SIZE);
+ if (!CyberRegs) {
+ printk("%s: unable to map memory mapped IO\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_mmio_resource;
+ }
cyber2000_outb(0x18, 0x46e8);
cyber2000_outb(0x01, 0x102);
cyber2000_outb(0x08, 0x46e8);
+ /*
+ * get the video RAM size from the VGA register.
+ * This should have been already initialised by the BIOS,
+ * but if it's garbage, claim default 1MB VRAM (woody)
+ */
+ cyber2000_outb(0x72, 0x3ce);
+ switch (cyber2000_inb(0x3cf) & 3) {
+ case 2: smem_size = 0x00400000; break;
+ case 1: smem_size = 0x00200000; break;
+ default: smem_size = 0x00100000; break;
+ }
+
+ /*
+ * Map in screen memory
+ */
+ if (!request_mem_region(smem_base, smem_size, "frame buffer")) {
+ printk("%s: frame buffer in use\n",
+ current_par.dev_name);
+ err = -EBUSY;
+ goto release_mmio;
+ }
+
+ current_par.screen_base = ioremap(smem_base, smem_size);
+ if (!current_par.screen_base) {
+ printk("%s: unable to map screen memory\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_smem_resource;
+ }
+current_par.screen_base += IO_FUDGE_FACTOR;
+ current_par.screen_size = smem_size;
+ current_par.screen_base_p = smem_base + 0x80000000;
+ current_par.regs_base_p = mmio_base + 0x80000000;
+ current_par.currcon = -1;
+
cyber2000fb_init_fbinfo();
- current_par.currcon = -1;
- current_par.screen_base_p = base_p;
- current_par.screen_base = base_v;
- current_par.screen_size = 0x00200000;
- current_par.regs_base_p = base_p + 0x00800000;
+ if (!fb_find_mode(&init_var, &fb_info, NULL,
+ NULL, 0, &cyber2000fb_default_mode, 8)) {
+ printk("%s: no valid mode found\n",
+ current_par.dev_name);
+ goto release_smem_resource;
+ }
+
+ init_var.yres_virtual = smem_size * 8 /
+ (init_var.bits_per_pixel * init_var.xres_virtual);
+ if (init_var.yres_virtual < init_var.yres)
+ init_var.yres_virtual = init_var.yres;
+
+ cyber2000fb_hw_init();
cyber2000fb_set_var(&init_var, -1, &fb_info);
h_sync = 1953125000 / init_var.pixclock;
v_sync = h_sync / (init_var.yres + init_var.upper_margin +
init_var.lower_margin + init_var.vsync_len);
- printk("Cyber2000: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ current_par.dev_name,
current_par.screen_size >> 10,
init_var.xres, init_var.yres,
h_sync / 1000, h_sync % 1000, v_sync);
- if (register_framebuffer(&fb_info) < 0)
- return -EINVAL;
+ if (register_framebuffer(&fb_info) < 0) {
+ err = -EINVAL;
+ goto release_smem;
+ }
+
+ current_par.initialised = 1;
MOD_INC_USE_COUNT; /* TODO: This driver cannot be unloaded yet */
return 0;
-}
+release_smem:
+ iounmap(current_par.screen_base);
+release_smem_resource:
+ release_mem_region(smem_base, smem_size);
+release_mmio:
+ iounmap(CyberRegs);
+release_mmio_resource:
+ release_mem_region(mmio_base, MMIO_SIZE);
+ return err;
+}
#ifdef MODULE
int __init init_module(void)
{
- return cyber2000fb_init();
+ int ret;
+
+ ret = cyber2000fb_init();
+ if (ret)
+ return ret;
+
+ return 0;
}
void cleanup_module(void)
decremented to zero */
unregister_framebuffer(&fb_info);
/* TODO: clean up ... */
+
+ iounmap(current_par.screen_base);
+ iounmap(CyberRegs);
+
+ release_mem_region(smem_base, current_par.screen_size);
+ release_mem_region(mmio_base, MMIO_SIZE);
}
#endif /* MODULE */
*/
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define cyber2000_outb(dat,reg) (CyberRegs[reg] = dat)
-#define cyber2000_outw(dat,reg) (*(unsigned short *)&CyberRegs[reg] = dat)
-#define cyber2000_outl(dat,reg) (*(unsigned long *)&CyberRegs[reg] = dat)
-#define cyber2000_inb(reg) (CyberRegs[reg])
-#define cyber2000_inw(reg) (*(unsigned short *)&CyberRegs[reg])
-#define cyber2000_inl(reg) (*(unsigned long *)&CyberRegs[reg])
+#define cyber2000_outb(dat,reg) writeb(dat, CyberRegs + reg)
+#define cyber2000_outw(dat,reg) writew(dat, CyberRegs + reg)
+#define cyber2000_outl(dat,reg) writel(dat, CyberRegs + reg)
+
+#define cyber2000_inb(reg) readb(CyberRegs + reg)
+#define cyber2000_inw(reg) readw(CyberRegs + reg)
+#define cyber2000_inl(reg) readl(CyberRegs + reg)
static inline void cyber2000_crtcw(int reg, int val)
{
}
struct cyber2000fb_par {
- unsigned long screen_base;
+ char * screen_base;
unsigned long screen_base_p;
unsigned long regs_base;
unsigned long regs_base_p;
unsigned long screen_size;
unsigned int palette_size;
signed int currcon;
+ char dev_name[32];
+ unsigned int initialised;
+
/*
* palette
*/
} c_table;
};
-struct res {
- int xres;
- int yres;
- unsigned char crtc_regs[18];
- unsigned char crtc_ofl;
- unsigned char clk_regs[4];
-};
+#define PIXFORMAT_8BPP 0
+#define PIXFORMAT_16BPP 1
+#define PIXFORMAT_24BPP 2
+
+#define VISUALID_256 1
+#define VISUALID_64K 2
+#define VISUALID_16M 4
+#define VISUALID_32K 6
+
+#define CO_CMD_L_PATTERN_FGCOL 0x8000
+#define CO_CMD_L_INC_LEFT 0x0004
+#define CO_CMD_L_INC_UP 0x0002
+
+#define CO_CMD_H_SRC_PIXMAP 0x2000
+#define CO_CMD_H_BLITTER 0x0800
+
+#define CO_REG_CONTROL 0xbf011
+#define CO_REG_SRC_WIDTH 0xbf018
+#define CO_REG_PIX_FORMAT 0xbf01c
+#define CO_REG_FORE_MIX 0xbf048
+#define CO_REG_FOREGROUND 0xbf058
+#define CO_REG_WIDTH 0xbf060
+#define CO_REG_HEIGHT 0xbf062
+#define CO_REG_X_PHASE 0xbf078
+#define CO_REG_CMD_L 0xbf07c
+#define CO_REG_CMD_H 0xbf07e
+#define CO_REG_SRC_PTR 0xbf170
+#define CO_REG_DEST_PTR 0xbf178
+#define CO_REG_DEST_WIDTH 0xbf218
return 0;
}
-static struct proc_dir_entry *proc_fbmem;
-
void __init
fbmem_init(void)
{
int i;
- proc_fbmem = create_proc_entry("fb", 0, 0);
- if (proc_fbmem)
- proc_fbmem->read_proc = fbmem_read_proc;
+ create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
return (count > cnt) ? cnt : count;
}
-static struct proc_dir_entry proc_zorro_devices = {
- PROC_BUS_ZORRO_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- get_zorro_dev_info
-};
-
static struct proc_dir_entry *proc_bus_zorro_dir;
static int __init zorro_proc_attach_device(u_int slot)
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
return;
proc_bus_zorro_dir = create_proc_entry("zorro", S_IFDIR, proc_bus);
- proc_register(proc_bus_zorro_dir, &proc_zorro_devices);
+ create_proc_info_entry("devices", 0, proc_bus_zorro_dir, get_zorro_dev_info);
for (slot = 0; slot < zorro_num_autocon; slot++)
zorro_proc_attach_device(slot);
}
fi
tristate 'ROM filesystem support' CONFIG_ROMFS_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'BFS filesystem (read only) support (EXPERIMENTAL)' CONFIG_BFS_FS
+ if [ "$CONFIG_BFS_FS" != "n" ]; then
+ bool ' BFS filesystem write support (DANGEROUS)' CONFIG_BFS_FS_WRITE
+ fi
+fi
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
- nfsd nls devpts adfs partitions qnx4 udf
+ nfsd nls devpts adfs partitions qnx4 udf bfs
SUB_DIRS := partitions
endif
endif
+ifeq ($(CONFIG_BFS_FS),y)
+SUB_DIRS += bfs
+else
+ ifeq ($(CONFIG_BFS_FS),m)
+ MOD_SUB_DIRS += bfs
+ endif
+endif
+
ifeq ($(CONFIG_ISO9660_FS),y)
SUB_DIRS += isofs
else
--- /dev/null
+#
+# Makefile for BFS filesystem.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main Makefile...
+
+O_TARGET := bfs.o
+O_OBJS := inode.o file.o dir.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+#define su_lasti u.bfs_sb.si_lasti
+#define su_blocks u.bfs_sb.si_blocks
+#define su_freeb u.bfs_sb.si_freeb
+#define su_freei u.bfs_sb.si_freei
+#define su_lf_ioff u.bfs_sb.si_lf_ioff
+#define su_lf_sblk u.bfs_sb.si_lf_sblk
+#define su_lf_eblk u.bfs_sb.si_lf_eblk
+#define su_imap_len u.bfs_sb.si_imap_len
+#define su_imap u.bfs_sb.si_imap
+#define su_sbh u.bfs_sb.si_sbh
+#define su_bfs_sb u.bfs_sb.si_bfs_sb
+
+#define iu_dsk_ino u.bfs_i.i_dsk_ino
+#define iu_sblock u.bfs_i.i_sblock
+#define iu_eblock u.bfs_i.i_eblock
--- /dev/null
+/*
+ * fs/bfs/dir.c
+ * BFS directory operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bfs_fs.h>
+#include <linux/locks.h>
+
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir);
+
+static ssize_t bfs_dir_read(struct file * f, char * buf, size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
+{
+ struct inode * dir = f->f_dentry->d_inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ kdev_t dev = dir->i_dev;
+ unsigned int offset;
+ int block;
+
+ if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
+ printk(KERN_ERR "BFS-fs: %s(): Bad inode or not a directory %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), dir->i_ino);
+ return -EBADF;
+ }
+
+ if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
+ printk(KERN_ERR "BFS-fs: %s(): Bad f_pos=%08lx for %s:%08lx\n",
+ __FUNCTION__, (unsigned long)f->f_pos, bdevname(dev), dir->i_ino);
+ return -EBADF;
+ }
+
+ while (f->f_pos < dir->i_size) {
+ offset = f->f_pos & (BFS_BSIZE-1);
+ block = dir->iu_sblock + f->f_pos/BFS_BSIZE;
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ f->f_pos += BFS_BSIZE - offset;
+ continue;
+ }
+ do {
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ if (de->ino) {
+ int size = strnlen(de->name, BFS_NAMELEN);
+ if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) {
+ brelse(bh);
+ return 0;
+ }
+ }
+ offset += BFS_DIRENT_SIZE;
+ f->f_pos += BFS_DIRENT_SIZE;
+ } while (offset < BFS_BSIZE && f->f_pos < dir->i_size);
+ brelse(bh);
+ }
+
+ UPDATE_ATIME(dir);
+ return 0;
+}
+
+static struct file_operations bfs_dir_operations = {
+ llseek: NULL,
+ read: bfs_dir_read,
+ write: NULL,
+ readdir: bfs_readdir,
+ poll: NULL,
+ ioctl: NULL,
+ mmap: NULL,
+ open: NULL,
+ flush: NULL,
+ release: NULL,
+ fsync: file_fsync,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+extern void dump_imap(const char *, struct super_block *);
+
+static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
+{
+ int err;
+ struct inode * inode;
+ struct super_block * s = dir->i_sb;
+ unsigned long ino;
+
+ inode = get_empty_inode();
+ if (!inode)
+ return -ENOSPC;
+ inode->i_sb = s;
+ ino = find_first_zero_bit(s->su_imap, s->su_imap_len);
+ if (ino >= s->su_lasti) {
+ iput(inode);
+ return -ENOSPC;
+ }
+ set_bit(ino, s->su_imap);
+ s->su_freei--;
+ inode->i_dev = s->s_dev;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = inode->i_blksize = 0;
+ inode->i_op = &bfs_file_inops;
+ inode->i_mode = mode;
+ inode->i_ino = inode->iu_dsk_ino = ino;
+ inode->iu_sblock = inode->iu_eblock = 0;
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+ dump_imap("create",s);
+
+ err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
+ if (err) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ return err;
+ }
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct inode * inode = NULL;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ if (dentry->d_name.len > BFS_NAMELEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->ino);
+ brelse(bh);
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new)
+{
+ struct inode * inode = old->d_inode;
+ int err;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino);
+ if (err)
+ return err;
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ inode->i_count++;
+ d_instantiate(new, inode);
+ return 0;
+}
+
+
+static int bfs_unlink(struct inode * dir, struct dentry * dentry)
+{
+ int error = -ENOENT;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ inode = dentry->d_inode;
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!bh || de->ino != inode->i_ino)
+ goto out_brelse;
+
+ if (!inode->i_nlink) {
+ printk(KERN_WARNING
+ "BFS-fs: %s(): unlinking non-existent file %s:%lu (nlink=%d)\n",
+ __FUNCTION__, bdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ de->ino = 0;
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+ mark_inode_dirty(inode);
+ d_delete(dentry);
+ error = 0;
+
+out_brelse:
+ brelse(bh);
+ return error;
+}
+
+static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh;
+ struct bfs_dirent * old_de, * new_de;
+ int error = -ENOENT;
+
+ old_bh = new_bh = NULL;
+ old_inode = old_dentry->d_inode;
+ if (S_ISDIR(old_inode->i_mode))
+ return -EINVAL;
+
+ old_bh = bfs_find_entry(old_dir,
+ old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de);
+
+ if (!old_bh || old_de->ino != old_inode->i_ino)
+ goto end_rename;
+
+ error = -EPERM;
+ new_inode = new_dentry->d_inode;
+ new_bh = bfs_find_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de);
+
+ if (new_bh && !new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ if (!new_bh) {
+ error = bfs_add_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, old_inode->i_ino);
+ if (error)
+ goto end_rename;
+ }
+ old_de->ino = 0;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_version = ++event;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
+ mark_buffer_dirty(old_bh, 1);
+ error = 0;
+
+end_rename:
+ brelse(old_bh);
+ brelse(new_bh);
+ return error;
+}
+
+struct inode_operations bfs_dir_inops = {
+ default_file_ops: &bfs_dir_operations,
+ create: bfs_create,
+ lookup: bfs_lookup,
+ link: bfs_link,
+ unlink: bfs_unlink,
+ symlink: NULL,
+ mkdir: NULL,
+ rmdir: NULL,
+ mknod: NULL,
+ rename: bfs_rename,
+ readlink: NULL,
+ follow_link: NULL,
+ get_block: NULL,
+ readpage: NULL,
+ writepage: NULL,
+ flushpage: NULL,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
+{
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ int block, sblock, eblock, off;
+ kdev_t dev;
+ int i;
+
+ DBG(KERN_ERR "BFS-fs: %s(%s,%d)\n", __FUNCTION__, name, namelen);
+
+ if (!namelen)
+ return -ENOENT;
+ if (namelen > BFS_NAMELEN)
+ return -ENAMETOOLONG;
+
+ dev = dir->i_dev;
+ sblock = dir->iu_sblock;
+ eblock = dir->iu_eblock;
+ for (block=sblock; block<=eblock; block++) {
+ bh = bread(dev, block, BFS_BSIZE);
+ if(!bh)
+ return -ENOSPC;
+ for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
+ de = (struct bfs_dirent *)(bh->b_data + off);
+ if (!de->ino) {
+ if ((block-sblock)*BFS_BSIZE + off >= dir->i_size) {
+ dir->i_size += BFS_DIRENT_SIZE;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ de->ino = ino;
+ for (i=0; i<BFS_NAMELEN; i++)
+ de->name[i] = (i < namelen) ? name[i] : 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return 0;
+ }
+ }
+ brelse(bh);
+ }
+ return -ENOSPC;
+}
+
+static inline int bfs_namecmp(int len, const char * name, const char * buffer)
+{
+ if (len < BFS_NAMELEN && buffer[len])
+ return 0;
+ return !memcmp(name, buffer, len);
+}
+
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir)
+{
+ unsigned long block, offset;
+ struct buffer_head * bh;
+ struct bfs_sb_info * info;
+ struct bfs_dirent * de;
+
+ *res_dir = NULL;
+ info = &dir->i_sb->u.bfs_sb;
+ if (namelen > BFS_NAMELEN)
+ return NULL;
+ bh = NULL;
+ block = offset = 0;
+ while (block * BFS_BSIZE + offset < dir->i_size) {
+ if (!bh) {
+ bh = bread(dir->i_dev, dir->iu_sblock + block, BFS_BSIZE);
+ if (!bh) {
+ block++;
+ continue;
+ }
+ }
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ offset += BFS_DIRENT_SIZE;
+ if (de->ino && bfs_namecmp(namelen, name, de->name)) {
+ *res_dir = de;
+ return bh;
+ }
+ if (offset < bh->b_size)
+ continue;
+ brelse(bh);
+ bh = NULL;
+ offset = 0;
+ block++;
+ }
+ brelse(bh);
+ return NULL;
+}
--- /dev/null
+/*
+ * fs/bfs/file.c
+ * BFS file operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/fs.h>
+#include <linux/bfs_fs.h>
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static ssize_t bfs_file_write(struct file * f, const char * buf, size_t count, loff_t *ppos)
+{
+ return generic_file_write(f, buf, count, ppos, block_write_partial_page);
+}
+
+static struct file_operations bfs_file_operations = {
+ llseek: NULL,
+ read: generic_file_read,
+ write: bfs_file_write,
+ readdir: NULL,
+ poll: NULL,
+ ioctl: NULL,
+ mmap: generic_file_mmap,
+ open: NULL,
+ flush: NULL,
+ release: NULL,
+ fsync: NULL,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+static int bfs_get_block(struct inode * inode, long block,
+ struct buffer_head * bh_result, int create)
+{
+ if (!create) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = inode->iu_sblock + block;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ return 0;
+ } else
+ DBG(KERN_ERR "BFS-fs: %s(create=%d) impossible!\n",
+ __FUNCTION__, create);
+ return -EIO;
+}
+
+struct inode_operations bfs_file_inops = {
+ default_file_ops: &bfs_file_operations,
+ create: NULL,
+ lookup: NULL,
+ link: NULL,
+ unlink: NULL,
+ symlink: NULL,
+ mkdir: NULL,
+ rmdir: NULL,
+ mknod: NULL,
+ rename: NULL,
+ readlink: NULL,
+ follow_link: NULL,
+ get_block: bfs_get_block,
+ readpage: block_read_full_page,
+ writepage: block_write_full_page,
+ flushpage: block_flushpage,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
--- /dev/null
+/*
+ * fs/bfs/inode.c
+ * BFS superblock and inode operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/locks.h>
+#include <linux/bfs_fs.h>
+
+#include <asm/uaccess.h>
+
+#include "bfs_defs.h"
+
+MODULE_AUTHOR("Tigran A. Aivazian");
+MODULE_DESCRIPTION("UnixWare BFS filesystem for Linux");
+EXPORT_NO_SYMBOLS;
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void dump_imap(const char *prefix, struct super_block * s);
+
+static void bfs_read_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ int block, off;
+
+ if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
+ printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), ino);
+ make_bad_inode(inode);
+ return;
+ }
+
+ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), ino);
+ make_bad_inode(inode);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ inode->i_mode = 0x0000FFFF & di->i_mode;
+ if (di->i_vtype == BFS_VDIR) {
+ inode->i_mode |= S_IFDIR;
+ inode->i_op = &bfs_dir_inops;
+ } else if (di->i_vtype == BFS_VREG) {
+ inode->i_mode |= S_IFREG;
+ inode->i_op = &bfs_file_inops;
+ } else
+ inode->i_op = NULL;
+
+ inode->i_uid = di->i_uid;
+ inode->i_gid = di->i_gid;
+ inode->i_nlink = di->i_nlink;
+ inode->i_size = BFS_FILESIZE(di);
+ inode->i_blocks = BFS_FILEBLOCKS(di);
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_atime = di->i_atime;
+ inode->i_mtime = di->i_mtime;
+ inode->i_ctime = di->i_ctime;
+ inode->i_rdev = 0; /* BFS doesn't have special nodes */
+ inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
+ inode->iu_sblock = di->i_sblock;
+ inode->iu_eblock = di->i_eblock;
+
+ brelse(bh);
+}
+
+static void bfs_write_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ int block, off;
+
+ if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
+ printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), ino);
+ return;
+ }
+
+ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), ino);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ if (inode->i_ino == BFS_ROOT_INO)
+ di->i_vtype = BFS_VDIR;
+ else
+ di->i_vtype = BFS_VREG;
+
+ di->i_ino = inode->i_ino;
+ di->i_mode = inode->i_mode;
+ di->i_uid = inode->i_uid;
+ di->i_gid = inode->i_gid;
+ di->i_nlink = inode->i_nlink;
+ di->i_atime = inode->i_atime;
+ di->i_mtime = inode->i_mtime;
+ di->i_ctime = inode->i_ctime;
+ di->i_sblock = inode->iu_sblock;
+ di->i_eblock = inode->iu_eblock;
+ di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
+
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+}
+
+static void bfs_delete_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ int block, off;
+ struct super_block * s = inode->i_sb;
+
+ DBG(KERN_ERR "%s(ino=%08lx)\n", __FUNCTION__, inode->i_ino);
+
+ if (!inode)
+ return;
+ if (!inode->i_dev) {
+ printk(KERN_ERR "BFS-fs: free_inode(%08lx) !dev\n", inode->i_ino);
+ return;
+ }
+ if (inode->i_count > 1) {
+ printk(KERN_ERR "BFS-fs: free_inode(%08lx) count=%d\n",
+ inode->i_ino, inode->i_count);
+ return;
+ }
+ if (inode->i_nlink) {
+ printk(KERN_ERR "BFS-fs: free_inode(%08lx) nlink=%d\n",
+ inode->i_ino, inode->i_nlink);
+ return;
+ }
+ if (!inode->i_sb) {
+ printk(KERN_ERR "BFS-fs: free_inode(%08lx) !sb\n", inode->i_ino);
+ return;
+ }
+ if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > inode->i_sb->su_lasti) {
+ printk(KERN_ERR "BFS-fs: free_inode(%08lx) invalid ino\n", inode->i_ino);
+ return;
+ }
+
+ inode->i_size = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
+ __FUNCTION__, bdevname(dev), ino);
+ return;
+ }
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+ if (di->i_ino) {
+ s->su_freeb += BFS_FILEBLOCKS(di);
+ s->su_freei++;
+ clear_bit(di->i_ino, s->su_imap);
+ dump_imap("delete_inode", s);
+ }
+ di->i_ino = 0;
+ di->i_sblock = 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ clear_inode(inode);
+}
+
+static void bfs_put_super(struct super_block *s)
+{
+ brelse(s->su_sbh);
+ kfree(s->su_imap);
+ MOD_DEC_USE_COUNT;
+}
+
+static int bfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = BFS_MAGIC;
+ tmp.f_bsize = s->s_blocksize;
+ tmp.f_blocks = s->su_blocks;
+ tmp.f_bfree = tmp.f_bavail = s->su_freeb;
+ tmp.f_files = s->su_lasti + 1 - BFS_ROOT_INO;
+ tmp.f_ffree = s->su_freei;
+ tmp.f_fsid.val[0] = s->s_dev;
+ tmp.f_namelen = BFS_NAMELEN;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void bfs_write_super(struct super_block *s)
+{
+ if (!(s->s_flags & MS_RDONLY))
+ mark_buffer_dirty(s->su_sbh, 1);
+ s->s_dirt = 0;
+}
+
+static struct super_operations bfs_sops = {
+ read_inode: bfs_read_inode,
+ write_inode: bfs_write_inode,
+ put_inode: NULL,
+ delete_inode: bfs_delete_inode,
+ notify_change: NULL,
+ put_super: bfs_put_super,
+ write_super: bfs_write_super,
+ statfs: bfs_statfs,
+ remount_fs: NULL,
+ clear_inode: NULL,
+ umount_begin: NULL
+};
+
+void dump_imap(const char *prefix, struct super_block * s)
+{
+#if 0
+ int i, hibit = 8 * (s->su_imap_len) - 1;
+ char tmpbuf[400];
+
+ memset(tmpbuf, 0, 400);
+ for (i=hibit; i>=0; i--) {
+ if (i>390) break;
+ if (test_bit(i, s->su_imap))
+ strcat(tmpbuf, "1");
+ else
+ strcat(tmpbuf, "0");
+ }
+ printk(KERN_ERR "BFS-fs: %s: lasti=%d <%s> (%d*8 bits)\n",
+ prefix, s->su_lasti, tmpbuf, s->su_imap_len);
+#endif
+}
+
+static struct super_block * bfs_read_super(struct super_block * s,
+ void * data, int silent)
+{
+ kdev_t dev;
+ struct buffer_head * bh;
+ struct bfs_super_block * bfs_sb;
+ struct inode * inode;
+ unsigned long i;
+
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+ dev = s->s_dev;
+ set_blocksize(dev, BFS_BSIZE);
+ s->s_blocksize = BFS_BSIZE;
+ s->s_blocksize_bits = BFS_BSIZE_BITS;
+
+ /* read ahead 8K to get inodes as we'll need them in a tick */
+ bh = breada(dev, 0, BFS_BSIZE, 0, 8192);
+ if(!bh)
+ goto out;
+ bfs_sb = (struct bfs_super_block *)bh->b_data;
+ if (bfs_sb->s_magic != BFS_MAGIC) {
+ if (!silent)
+ printk(KERN_ERR "BFS-fs: No BFS filesystem on %s (magic=%08x)\n",
+ bdevname(dev), bfs_sb->s_magic);
+ goto out;
+ }
+ if (BFS_UNCLEAN(bfs_sb, s) && !silent)
+ printk(KERN_WARNING "BFS-fs: %s is unclean\n", bdevname(dev));
+
+#ifndef CONFIG_BFS_FS_WRITE
+ s->s_flags |= MS_RDONLY;
+#endif
+ s->s_magic = BFS_MAGIC;
+ s->su_bfs_sb = bfs_sb;
+ s->su_sbh = bh;
+ s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode)
+ + BFS_ROOT_INO - 1;
+
+ s->su_imap_len = s->su_lasti/8 + 1; /* 1 byte is 8 bit */
+ s->su_imap = kmalloc(s->su_imap_len, GFP_KERNEL);
+ if (!s->su_imap)
+ goto out;
+ memset(s->su_imap, 0, s->su_imap_len);
+ for (i=0; i<BFS_ROOT_INO; i++)
+ set_bit(i, s->su_imap);
+
+ s->s_op = &bfs_sops;
+ inode = iget(s, BFS_ROOT_INO);
+ if (!inode) {
+ kfree(s->su_imap);
+ goto out;
+ }
+ s->s_root = d_alloc_root(inode);
+ if (!s->s_root) {
+ iput(inode);
+ kfree(s->su_imap);
+ goto out;
+ }
+
+ s->su_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */
+ s->su_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS;
+ s->su_freei = 0;
+ s->su_lf_eblk = 0;
+ s->su_lf_sblk = 0;
+ s->su_lf_ioff = 0;
+ for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
+ inode = iget(s,i);
+ if (inode->iu_dsk_ino == 0)
+ s->su_freei++;
+ else {
+ set_bit(i, s->su_imap);
+ s->su_freeb -= inode->i_blocks;
+ if (inode->iu_eblock > s->su_lf_eblk) {
+ s->su_lf_eblk = inode->iu_eblock;
+ s->su_lf_sblk = inode->iu_sblock;
+ s->su_lf_ioff = BFS_INO2OFF(i);
+ }
+ }
+ iput(inode);
+ }
+ if (!(s->s_flags & MS_RDONLY)) {
+ mark_buffer_dirty(bh, 1);
+ s->s_dirt = 1;
+ }
+ dump_imap("read_super", s);
+ unlock_super(s);
+ return s;
+
+out:
+ brelse(bh);
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static struct file_system_type bfs_fs_type = {
+ name: "bfs",
+ fs_flags: FS_REQUIRES_DEV,
+ read_super: bfs_read_super,
+ next: NULL
+};
+
+#ifdef MODULE
+#define init_bfs_fs init_module
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&bfs_fs_type);
+}
+#endif
+
+int __init init_bfs_fs(void)
+{
+ return register_filesystem(&bfs_fs_type);
+}
6};
#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
-#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
#define NR_RESERVED (2*MAX_BUF_PER_PAGE)
#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this
number of unused buffer heads */
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
int err, i;
- unsigned long block, offset;
+ unsigned long block;
struct buffer_head *bh, *head;
if (!PageLocked(page))
create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
head = page->buffers;
- offset = page->offset;
- block = offset >> inode->i_sb->s_blocksize_bits;
-
- // FIXME: currently we assume page alignment.
- if (offset & (PAGE_SIZE-1))
- BUG();
+ /* The page cache is now PAGE_CACHE_SIZE aligned, period. We handle old a.out
+ * and others via unaligned private mappings.
+ */
+ block = page->pg_offset << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
bh = head;
i = 0;
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
- block = page->offset >> bbits;
- blocks = PAGE_SIZE >> bbits;
+ block = page->pg_offset << (PAGE_CACHE_SHIFT - bbits);
+ blocks = PAGE_CACHE_SIZE >> bbits;
start_block = offset >> bbits;
end_block = (offset + bytes - 1) >> bbits;
start_offset = offset & (blocksize - 1);
BUG();
if (end_block < 0 || end_block >= blocks)
BUG();
- // FIXME: currently we assume page alignment.
- if (page->offset & (PAGE_SIZE-1))
- BUG();
i = 0;
bh = head;
unsigned long data_offset = offset;
int need_balance_dirty;
- offset = inode->i_size - page->offset;
- if (page->offset>inode->i_size)
+ offset = inode->i_size - (page->pg_offset << PAGE_CACHE_SHIFT);
+ if (page->pg_offset > (inode->i_size >> PAGE_CACHE_SHIFT))
offset = 0;
else if (offset >= data_offset)
offset = data_offset;
- bytes += data_offset-offset;
+ bytes += data_offset - offset;
target_buf = (char *)page_address(page) + offset;
target_data = (char *)page_address(page) + data_offset;
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
- block = page->offset >> bbits;
- blocks = PAGE_SIZE >> bbits;
+ block = page->pg_offset << (PAGE_CACHE_SHIFT - bbits);
+ blocks = PAGE_CACHE_SIZE >> bbits;
start_block = offset >> bbits;
end_block = (offset + bytes - 1) >> bbits;
start_offset = offset & (blocksize - 1);
BUG();
if (end_block < 0 || end_block >= blocks)
BUG();
- // FIXME: currently we assume page alignment.
- if (page->offset & (PAGE_SIZE-1))
- BUG();
i = 0;
bh = head;
create_empty_buffers(page, inode, blocksize);
head = page->buffers;
- blocks = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
- iblock = page->offset >> inode->i_sb->s_blocksize_bits;
+ blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
+ iblock = page->pg_offset << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
bh = head;
nr = 0;
*/
-struct proc_dir_entry proc_fs_coda = {
- PROC_FS_CODA, 4, "coda",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-
-struct proc_dir_entry proc_coda_vfs = {
- PROC_VFS_STATS , 9, "vfs_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_vfs_stats_get_info
- };
-
-struct proc_dir_entry proc_coda_upcall = {
- PROC_UPCALL_STATS , 12, "upcall_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_upcall_stats_get_info
- };
-
-struct proc_dir_entry proc_coda_permission = {
- PROC_PERMISSION_STATS , 16, "permission_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_permission_stats_get_info
- };
-
-
-struct proc_dir_entry proc_coda_cache_inv = {
- PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_cache_inv_stats_get_info
- };
+struct proc_dir_entry* proc_fs_coda;
static void coda_proc_modcount(struct inode *inode, int fill)
{
#endif
+#define coda_proc_create(name,get_info) \
+ create_proc_info_entry(name, 0, proc_fs_coda, get_info)
void coda_sysctl_init()
{
reset_coda_cache_inv_stats();
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root_fs,&proc_fs_coda);
- proc_fs_coda.fill_inode = &coda_proc_modcount;
- proc_register(&proc_fs_coda,&proc_coda_vfs);
- proc_register(&proc_fs_coda,&proc_coda_upcall);
- proc_register(&proc_fs_coda,&proc_coda_permission);
- proc_register(&proc_fs_coda,&proc_coda_cache_inv);
+ proc_fs_coda = create_proc_entry("coda", S_IFDIR, proc_root_fs);
+ proc_fs_coda->fill_inode = &coda_proc_modcount;
+ coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
+ coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
+ coda_proc_create("permission_stats", coda_permission_stats_get_info);
+ coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
#endif
#ifdef CONFIG_SYSCTL
#endif
#if CONFIG_PROC_FS
- proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
- proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
+ remove_proc_entry("cache_inv_stats", proc_fs_coda);
+ remove_proc_entry("permission_stats", proc_fs_coda);
+ remove_proc_entry("upcall_stats", proc_fs_coda);
+ remove_proc_entry("vfs_stats", proc_fs_coda);
+ remove_proc_entry("coda", proc_root_fs);
#endif
}
*--end = '\0';
buflen--;
- if (dentry->d_parent != dentry && list_empty(&dentry->d_hash)) {
+ if (!IS_ROOT(dentry) && list_empty(&dentry->d_hash)) {
buflen -= 10;
end -= 10;
memcpy(end, " (deleted)", 10);
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL;
- mpnt->vm_offset = 0;
+ mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL;
mpnt->vm_private_data = (void *) 0;
vmlist_modify_lock(current->mm);
* Universite Pierre et Marie Curie (Paris VI)
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+
/*
* This file will contain the Access Control Lists management for the
* second extended file system.
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
/*
* ext2_permission ()
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#include <asm/bitops.h>
-#include <asm/byteorder.h>
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
* Universite Pierre et Marie Curie (Paris VI)
*/
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+
+
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+
+
static ssize_t ext2_dir_read (struct file * filp, char * buf,
size_t count, loff_t *ppos)
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
+
+
#define NBUF 32
* we can depend on generic_block_fdatasync() to sync the data blocks.
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
+
+
#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* ialloc.c contains the inodes allocation and deallocation routines
*/
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#include <asm/bitops.h>
-#include <asm/byteorder.h>
/*
* Read the inode allocation bitmap for a given block_group, reading
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
#include <linux/locks.h>
-#include <linux/mm.h>
#include <linux/smp_lock.h>
+#include <linux/sched.h>
+
+
static int ext2_update_inode(struct inode * inode, int do_sync);
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/ioctl.h>
#include <linux/sched.h>
-#include <linux/mm.h>
+#include <asm/uaccess.h>
+
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
* for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
+
/*
* define how far ahead to read directories while searching them.
*/
*/
#include <linux/module.h>
-
-#include <stdarg.h>
-
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/blkdev.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/locks.h>
+#include <asm/uaccess.h>
+
+
static char error_buf[1024];
* ext2 symlink handling code
*/
+#include <linux/module.h>
+#include <linux/fs.h>
#include <asm/uaccess.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/stat.h>
+
static int ext2_readlink (struct dentry *, char *, int);
static struct dentry *ext2_follow_link(struct dentry *, struct dentry *, unsigned int);
* General cleanup and race fixes, wsh, 1998
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+
+
/*
* Real random numbers for secure rm added 94/02/18
* Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/string.h>
-
#if 0
/*
#include <linux/ntfs_fs.h>
#include <linux/hfs_fs.h>
#include <linux/devpts_fs.h>
+#include <linux/bfs_fs.h>
#include <linux/major.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_UDF_FS
init_udf_fs();
#endif
+
+#ifdef CONFIG_BFS_FS
+ init_bfs_fs();
+#endif
#ifdef CONFIG_NLS
init_nls();
static struct proc_dir_entry proc_nfsclnt = {
0, 3, "nfs",
S_IFREG | S_IRUGO, 1, 0, 0,
- 6, &proc_net_inode_operations,
+ 6, NULL,
nfs_get_info
};
nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
{
struct nfs_rreq rqst;
- unsigned long offset = page->offset;
+ unsigned long offset = page->pg_offset << PAGE_CACHE_SHIFT;
char *buffer = (char *) page_address(page);
int rsize = NFS_SERVER(inode)->rsize;
int result, refresh = 0;
/* Initialize request */
/* N.B. Will the dentry remain valid for life of request? */
- nfs_readreq_setup(req, NFS_FH(dentry), page->offset,
+ nfs_readreq_setup(req, NFS_FH(dentry), page->pg_offset << PAGE_CACHE_SHIFT,
(void *) address, PAGE_SIZE);
req->ra_inode = inode;
req->ra_page = page; /* count has been incremented by caller */
int error;
lock_kernel();
- dprintk("NFS: nfs_readpage (%p %ld@%ld)\n",
- page, PAGE_SIZE, page->offset);
+ dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
+ page, PAGE_SIZE, page->pg_offset);
get_page(page);
/*
struct nfs_fattr fattr;
lock_kernel();
- dprintk("NFS: nfs_writepage_sync(%s/%s %d@%ld)\n",
+ dprintk("NFS: nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset + offset);
+ count, page->pg_offset, offset);
buffer = (u8 *) page_address(page) + offset;
- offset += page->offset;
+ offset += page->pg_offset << PAGE_CACHE_SHIFT;
do {
if (count < wsize && !IS_SWAPFILE(inode))
dprintk("NFS: create_write_request(%s/%s, %ld+%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- page->offset + offset, bytes);
+ (page->pg_offset << PAGE_CACHE_SHIFT) + offset, bytes);
/* FIXME: Enforce hard limit on number of concurrent writes? */
wreq = kmem_cache_alloc(nfs_wreq_cachep, SLAB_KERNEL);
dprintk("NFS: nfs_updatepage(%s/%s %d@%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset+offset);
+ count, (page->pg_offset << PAGE_CACHE_SHIFT) +offset);
/*
* Try to find a corresponding request on the writeback queue.
/* Setup the task struct for a writeback call */
req->wb_flags |= NFS_WRITE_INPROGRESS;
req->wb_args.fh = NFS_FH(dentry);
- req->wb_args.offset = page->offset + req->wb_offset;
+ req->wb_args.offset = (page->pg_offset << PAGE_CACHE_SHIFT) + req->wb_offset;
req->wb_args.count = req->wb_bytes;
req->wb_args.buffer = (void *) (page_address(page) + req->wb_offset);
void proc_export_init(void)
{
- struct proc_dir_entry *nfs_export_ent = NULL;
-
- if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
- return;
- if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+ if (!create_proc_entry("fs/nfs", S_IFDIR, 0))
return;
- nfs_export_ent->read_proc = exp_procfs_exports;
+ create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL);
}
O_TARGET := proc.o
O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
- kmsg.o scsi.o proc_tty.o sysvipc.o
+ kmsg.o scsi.o proc_tty.o sysvipc.o proc_misc.o
ifdef CONFIG_OMIRR
O_OBJS := $(O_OBJS) omirr.o
endif
#include <asm/pgtable.h>
#include <asm/io.h>
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-#ifdef CONFIG_DEBUG_MALLOC
-int get_malloc(char * buffer);
-#endif
-
static int open_kcore(struct inode * inode, struct file * filp)
{
&proc_profile_operations,
};
-
-static int get_loadavg(char * buffer)
-{
- int a, b, c;
-
- a = avenrun[0] + (FIXED_1/200);
- b = avenrun[1] + (FIXED_1/200);
- c = avenrun[2] + (FIXED_1/200);
- return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
- LOAD_INT(a), LOAD_FRAC(a),
- LOAD_INT(b), LOAD_FRAC(b),
- LOAD_INT(c), LOAD_FRAC(c),
- nr_running, nr_threads, last_pid);
-}
-
-static int get_kstat(char * buffer)
-{
- int i, len;
- unsigned sum = 0;
- extern unsigned long total_forks;
- unsigned long jif = jiffies;
-
- for (i = 0 ; i < NR_IRQS ; i++)
- sum += kstat_irqs(i);
-
-#ifdef __SMP__
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n",
- kstat.cpu_user,
- kstat.cpu_nice,
- kstat.cpu_system,
- jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system));
- for (i = 0 ; i < smp_num_cpus; i++)
- len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n",
- i,
- kstat.per_cpu_user[cpu_logical_map(i)],
- kstat.per_cpu_nice[cpu_logical_map(i)],
- kstat.per_cpu_system[cpu_logical_map(i)],
- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
- + kstat.per_cpu_nice[cpu_logical_map(i)] \
- + kstat.per_cpu_system[cpu_logical_map(i)]));
- len += sprintf(buffer + len,
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
-#else
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n"
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
- kstat.cpu_user,
- kstat.cpu_nice,
- kstat.cpu_system,
- jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
-#endif
- kstat.dk_drive[0], kstat.dk_drive[1],
- kstat.dk_drive[2], kstat.dk_drive[3],
- kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
- kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
- kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
- kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
- kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
- kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
- kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
- kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
- kstat.pgpgin,
- kstat.pgpgout,
- kstat.pswpin,
- kstat.pswpout,
- sum);
- for (i = 0 ; i < NR_IRQS ; i++)
- len += sprintf(buffer + len, " %u", kstat_irqs(i));
- len += sprintf(buffer + len,
- "\nctxt %u\n"
- "btime %lu\n"
- "processes %lu\n",
- kstat.context_swtch,
- xtime.tv_sec - jif / HZ,
- total_forks);
- return len;
-}
-
-
-static int get_uptime(char * buffer)
-{
- unsigned long uptime;
- unsigned long idle;
-
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
-
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
-#if HZ!=100
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
-#else
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
-#endif
-}
-
-static int get_meminfo(char * buffer)
-{
- struct sysinfo i;
- int len;
-
-/*
- * display in kilobytes.
- */
-#define K(x) ((x) << (PAGE_SHIFT - 10))
-
- si_meminfo(&i);
- si_swapinfo(&i);
- len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
- "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
- "Swap: %8lu %8lu %8lu\n",
- K(i.totalram), K(i.totalram-i.freeram), K(i.freeram),
- K(i.sharedram), K(i.bufferram),
- K(atomic_read(&page_cache_size)), K(i.totalswap),
- K(i.totalswap-i.freeswap), K(i.freeswap));
- /*
- * Tagged format, for easy grepping and expansion.
- * The above will go away eventually, once the tools
- * have been updated.
- */
- return len + sprintf(buffer+len,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemShared: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8u kB\n"
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n",
- K(i.totalram),
- K(i.freeram),
- K(i.sharedram),
- K(i.bufferram),
- K(atomic_read(&page_cache_size)),
- K(i.totalhigh),
- K(i.freehigh),
- K(i.totalswap),
- K(i.freeswap));
-#undef K
-}
-
-static int get_version(char * buffer)
-{
- extern char *linux_banner;
-
- strcpy(buffer, linux_banner);
- return strlen(buffer);
-}
-
-static int get_cmdline(char * buffer)
-{
- extern char saved_command_line[];
-
- return sprintf(buffer, "%s\n", saved_command_line);
-}
-
static struct page * get_phys_addr(struct mm_struct * mm, unsigned long ptr)
{
pgd_t *pgd;
int count = 0;
stack_page = 4096 + (unsigned long)p;
- fp = get_css_fp (&p->tss);
+ fp = get_css_fp(&p->thread);
do {
if (fp < stack_page || fp > 4092+stack_page)
return 0;
(*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
#elif defined(__arm__)
-# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
-# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
+# ifdef CONFIG_CPU_26
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
+# else
+# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1021])
+# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
+# endif
#elif defined(__mc68000__)
#define KSTK_EIP(tsk) \
({ \
len = sprintf(line,
sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
- map->vm_start, map->vm_end, str, map->vm_offset,
+ map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
if(map->vm_file) {
}
#endif
-#ifdef CONFIG_MODULES
-extern int get_module_list(char *);
-extern int get_ksyms_list(char *, char **, off_t, int);
-#endif
-extern int get_device_list(char *);
-extern int get_partition_list(char *);
-extern int get_filesystem_list(char *);
-extern int get_filesystem_info( char * );
-extern int get_irq_list(char *);
-extern int get_dma_list(char *);
-extern int get_cpuinfo(char *);
-extern int get_pci_list(char *);
-extern int get_md_status (char *);
-extern int get_rtc_status (char *);
-extern int get_locks_status (char *, char **, off_t, int);
-extern int get_swaparea_info (char *);
-extern int get_hardware_list(char *);
-extern int get_stram_list(char *);
-
-static long get_root_array(char * page, int type, char **start,
- off_t offset, unsigned long length)
-{
- switch (type) {
- case PROC_LOADAVG:
- return get_loadavg(page);
-
- case PROC_UPTIME:
- return get_uptime(page);
-
- case PROC_MEMINFO:
- return get_meminfo(page);
-
-#ifdef CONFIG_PCI
- case PROC_PCI:
- return get_pci_list(page);
-#endif
-
-#ifdef CONFIG_NUBUS
- case PROC_NUBUS:
- return get_nubus_list(page);
-#endif
-
- case PROC_CPUINFO:
- return get_cpuinfo(page);
-
- case PROC_VERSION:
- return get_version(page);
-
-#ifdef CONFIG_DEBUG_MALLOC
- case PROC_MALLOC:
- return get_malloc(page);
-#endif
-
-#ifdef CONFIG_MODULES
- case PROC_MODULES:
- return get_module_list(page);
-
- case PROC_KSYMS:
- return get_ksyms_list(page, start, offset, length);
-#endif
-
- case PROC_STAT:
- return get_kstat(page);
-
- case PROC_SLABINFO:
- return get_slabinfo(page);
-
- case PROC_DEVICES:
- return get_device_list(page);
-
- case PROC_PARTITIONS:
- return get_partition_list(page);
-
- case PROC_INTERRUPTS:
- return get_irq_list(page);
-
- case PROC_FILESYSTEMS:
- return get_filesystem_list(page);
-
- case PROC_DMA:
- return get_dma_list(page);
-
- case PROC_IOPORTS:
- return get_ioport_list(page);
-
- case PROC_MEMORY:
- return get_mem_list(page);
-#ifdef CONFIG_BLK_DEV_MD
- case PROC_MD:
- return get_md_status(page);
-#endif
- case PROC_CMDLINE:
- return get_cmdline(page);
-
- case PROC_MTAB:
- return get_filesystem_info( page );
-
- case PROC_SWAP:
- return get_swaparea_info(page);
-#ifdef CONFIG_RTC
- case PROC_RTC:
- return get_rtc_status(page);
-#endif
-#ifdef CONFIG_SGI_DS1286
- case PROC_RTC:
- return get_ds1286_status(page);
-#endif
-#ifdef CONFIG_SGI_DS1286
- case PROC_RTC:
- return get_ds1286_status(page);
-#endif
- case PROC_LOCKS:
- return get_locks_status(page, start, offset, length);
-#ifdef CONFIG_PROC_HARDWARE
- case PROC_HARDWARE:
- return get_hardware_list(page);
-#endif
-#ifdef CONFIG_STRAM_PROC
- case PROC_STRAM:
- return get_stram_list(page);
-#endif
- }
- return -EBADF;
-}
-
static int process_unauthorized(int type, int pid)
{
struct task_struct *p;
}
-static int get_process_array(char * page, int pid, int type)
+static inline int get_process_array(char * page, int pid, int type)
{
switch (type) {
case PROC_PID_STATUS:
return -EBADF;
}
-
-static inline int fill_array(char * page, int pid, int type, char **start, off_t offset, int length)
-{
- if (pid)
- return get_process_array(page, pid, type);
- return get_root_array(page, type, start, offset, length);
-}
-
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
static ssize_t array_read(struct file * file, char * buf,
type &= 0x0000ffff;
start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
+
+ if (!pid) { /* can't happen */
+ free_page(page);
+ return -EBADF;
+ }
- if (pid && process_unauthorized(type, pid)) {
+ if (process_unauthorized(type, pid)) {
free_page(page);
return -EIO;
}
- if (dp->get_info)
- length = dp->get_info((char *)page, &start, *ppos,
- count, 0);
- else
- length = fill_array((char *) page, pid, type,
- &start, *ppos, count);
+ length = get_process_array((char *) page, pid, type);
if (length < 0) {
free_page(page);
return length;
}
- if (start != NULL) {
- /* We have had block-adjusting processing! */
- copy_to_user(buf, start, length);
- *ppos += length;
- count = length;
- } else {
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- copy_to_user(buf, (char *) page + *ppos, count);
- *ppos = end;
+ /* Static 4kB (or whatever) block capacity */
+ if (*ppos >= length) {
+ free_page(page);
+ return 0;
}
+ if (count + *ppos > length)
+ count = length - *ppos;
+ end = count + *ppos;
+ copy_to_user(buf, (char *) page + *ppos, count);
+ *ppos = end;
free_page(page);
return count;
}
NULL /* revalidate */
};
-/*
- * compatibility to replace fs/proc/net.c
- */
-struct inode_operations proc_net_inode_operations = {
- &proc_file_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
pgd_t *src_dir, *dest_dir;
pmd_t *src_middle, *dest_middle;
pte_t *src_table, *dest_table;
- unsigned long stmp, dtmp, mapnr;
+ unsigned long stmp, etmp, dtmp, mapnr;
struct vm_area_struct *src_vma = NULL;
struct inode *inode = file->f_dentry->d_inode;
worth it. */
src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
- while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
+ stmp = vma->vm_pgoff << PAGE_SHIFT;
+ etmp = stmp + vma->vm_end - vma->vm_start;
+ while (stmp < etmp) {
while (src_vma && stmp > src_vma->vm_end)
src_vma = src_vma->vm_next;
if (!src_vma || (src_vma->vm_flags & VM_SHM))
}
src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
+ stmp = vma->vm_pgoff << PAGE_SHIFT;
dtmp = vma->vm_start;
flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
--- /dev/null
+/*
+ * linux/fs/proc/proc_misc.c
+ *
+ * linux/fs/proc/array.c
+ * Copyright (C) 1992 by Linus Torvalds
+ * based on ideas by Darren Senn
+ *
+ * This used to be the part of array.c. See the rest of history and credits
+ * there. I took this into a separate file and switched the thing to generic
+ * proc_file_inode_operations, leaving in array.c only per-process stuff.
+ * Inumbers allocation made dynamic (via create_proc_entry()). AV, May 1999.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/tty.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+/*
+ * Warning: stuff below (imported functions) assumes that its output will fit
+ * into one page. For some of those functions it may be wrong. Moreover, we
+ * have a way to deal with that gracefully. Right now I used straightforward
+ * wrappers, but this needs further analysis wrt potential overflows.
+ */
+extern int get_cpuinfo(char *);
+extern int get_hardware_list(char *);
+extern int get_stram_list(char *);
+#ifdef CONFIG_DEBUG_MALLOC
+extern int get_malloc(char * buffer);
+#endif
+#ifdef CONFIG_MODULES
+extern int get_module_list(char *);
+extern int get_ksyms_list(char *, char **, off_t, int);
+#endif
+extern int get_device_list(char *);
+extern int get_partition_list(char *);
+extern int get_filesystem_list(char *);
+extern int get_filesystem_info( char * );
+extern int get_irq_list(char *);
+extern int get_dma_list(char *);
+extern int get_rtc_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
+extern int get_swaparea_info (char *);
+#ifdef CONFIG_SGI_DS1286
+extern int get_ds1286_status(char *);
+#endif
+
+static int loadavg_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int a, b, c;
+ int len;
+
+ a = avenrun[0] + (FIXED_1/200);
+ b = avenrun[1] + (FIXED_1/200);
+ c = avenrun[2] + (FIXED_1/200);
+ len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+ LOAD_INT(a), LOAD_FRAC(a),
+ LOAD_INT(b), LOAD_FRAC(b),
+ LOAD_INT(c), LOAD_FRAC(c),
+ nr_running, nr_threads, last_pid);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int uptime_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long uptime;
+ unsigned long idle;
+ int len;
+
+ uptime = jiffies;
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+
+ /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
+ that would overflow about every five days at HZ == 100.
+ Therefore the identity a = (a / b) * b + a % b is used so that it is
+ calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
+ The part in front of the '+' always evaluates as 0 (mod 100). All divisions
+ in the above formulas are truncating. For HZ being a power of 10, the
+ calculations simplify to the version in the #else part (if the printf
+ format is adapted to the same number of digits as zeroes in HZ.
+ */
+#if HZ!=100
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ (((uptime % HZ) * 100) / HZ) % 100,
+ idle / HZ,
+ (((idle % HZ) * 100) / HZ) % 100);
+#else
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ uptime % HZ,
+ idle / HZ,
+ idle % HZ);
+#endif
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int meminfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct sysinfo i;
+ int len;
+
+/*
+ * display in kilobytes.
+ */
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+
+ si_meminfo(&i);
+ si_swapinfo(&i);
+ len = sprintf(page, " total: used: free: shared: buffers: cached:\n"
+ "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
+ "Swap: %8lu %8lu %8lu\n",
+ K(i.totalram), K(i.totalram-i.freeram), K(i.freeram),
+ K(i.sharedram), K(i.bufferram),
+ K(atomic_read(&page_cache_size)), K(i.totalswap),
+ K(i.totalswap-i.freeswap), K(i.freeswap));
+ /*
+ * Tagged format, for easy grepping and expansion.
+ * The above will go away eventually, once the tools
+ * have been updated.
+ */
+ len += sprintf(page+len,
+ "MemTotal: %8lu kB\n"
+ "MemFree: %8lu kB\n"
+ "MemShared: %8lu kB\n"
+ "Buffers: %8lu kB\n"
+ "Cached: %8u kB\n"
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n",
+ K(i.totalram),
+ K(i.freeram),
+ K(i.sharedram),
+ K(i.bufferram),
+ K(atomic_read(&page_cache_size)),
+ K(i.totalhigh),
+ K(i.freehigh),
+ K(i.totalswap),
+ K(i.freeswap));
+
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+
+#undef K
+}
+
+static int version_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char *linux_banner;
+ int len;
+
+ strcpy(page, linux_banner);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cpuinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_cpuinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_PROC_HARDWARE
+static int hardware_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_hardware_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_STRAM_PROC
+static int stram_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_stram_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_MALLOC
+static int malloc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_malloc(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_MODULES
+static int modules_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_module_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ksyms_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ksyms_list(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+#endif
+
+static int kstat_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, len;
+ unsigned sum = 0;
+ extern unsigned long total_forks;
+ unsigned long jif = jiffies;
+
+ for (i = 0 ; i < NR_IRQS ; i++)
+ sum += kstat_irqs(i);
+
+#ifdef __SMP__
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system));
+ for (i = 0 ; i < smp_num_cpus; i++)
+ len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
+ i,
+ kstat.per_cpu_user[cpu_logical_map(i)],
+ kstat.per_cpu_nice[cpu_logical_map(i)],
+ kstat.per_cpu_system[cpu_logical_map(i)],
+ jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
+ + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ + kstat.per_cpu_system[cpu_logical_map(i)]));
+ len += sprintf(page + len,
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+#else
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n"
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
+#endif
+ kstat.dk_drive[0], kstat.dk_drive[1],
+ kstat.dk_drive[2], kstat.dk_drive[3],
+ kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
+ kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
+ kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
+ kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
+ kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
+ kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
+ kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
+ kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
+ kstat.pgpgin,
+ kstat.pgpgout,
+ kstat.pswpin,
+ kstat.pswpout,
+ sum);
+ for (i = 0 ; i < NR_IRQS ; i++)
+ len += sprintf(page + len, " %u", kstat_irqs(i));
+ len += sprintf(page + len,
+ "\nctxt %u\n"
+ "btime %lu\n"
+ "processes %lu\n",
+ kstat.context_swtch,
+ xtime.tv_sec - jif / HZ,
+ total_forks);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int devices_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_device_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int partitions_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_partition_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int interrupts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_irq_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int filesystems_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int dma_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_dma_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ioports_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ioport_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cmdline_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char saved_command_line[];
+ int len;
+
+ len = sprintf(page, "%s\n", saved_command_line);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_RTC
+static int rtc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_rtc_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_SGI_DS1286
+static int ds1286_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ds1286_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+static int locks_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_locks_status(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+
+static int mounts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int swaps_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_swaparea_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int slabinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_slabinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int memory_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_mem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static struct proc_dir_entry proc_root_kmsg = {
+ 0, 4, "kmsg",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kmsg_inode_operations
+};
+static struct proc_dir_entry proc_root_kcore = {
+ 0, 5, "kcore",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kcore_inode_operations
+};
+static struct proc_dir_entry proc_root_profile = {
+ 0, 7, "profile",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_profile_inode_operations
+};
+
+void proc_misc_init(void)
+{
+ static struct {
+ char *name;
+ int (*read_proc)(char*,char**,off_t,int,int*,void*);
+ } *p, simple_ones[] = {
+ {"loadavg", loadavg_read_proc},
+ {"uptime", uptime_read_proc},
+ {"meminfo", meminfo_read_proc},
+ {"version", version_read_proc},
+ {"cpuinfo", cpuinfo_read_proc},
+#ifdef CONFIG_PROC_HARDWARE
+ {"hardware", hardware_read_proc},
+#endif
+#ifdef CONFIG_STRAM_PROC
+ {"stram", stram_read_proc},
+#endif
+#ifdef CONFIG_DEBUG_MALLOC
+ {"malloc", malloc_read_proc},
+#endif
+#ifdef CONFIG_MODULES
+ {"modules", modules_read_proc},
+ {"ksyms", ksyms_read_proc},
+#endif
+ {"stat", kstat_read_proc},
+ {"devices", devices_read_proc},
+ {"partitions", partitions_read_proc},
+ {"interrupts", interrupts_read_proc},
+ {"filesystems", filesystems_read_proc},
+ {"dma", dma_read_proc},
+ {"ioports", ioports_read_proc},
+ {"cmdline", cmdline_read_proc},
+#ifdef CONFIG_RTC
+ {"rtc", rtc_read_proc},
+#endif
+#ifdef CONFIG_SGI_DS1286
+ {"rtc", ds1286_read_proc},
+#endif
+ {"locks", locks_read_proc},
+ {"mounts", mounts_read_proc},
+ {"swaps", swaps_read_proc},
+ {"slabinfo", slabinfo_read_proc},
+ {"iomem", memory_read_proc},
+ {NULL,NULL}
+ };
+ for(p=simple_ones;p->name;p++)
+ create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
+
+ /* And now for trickier ones */
+ proc_register(&proc_root, &proc_root_kmsg);
+ proc_register(&proc_root, &proc_root_kcore);
+ proc_root_kcore.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
+ if (prof_shift) {
+ proc_register(&proc_root, &proc_root_profile);
+ proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
+ }
+}
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
extern struct inode_operations proc_scsi_inode_operations;
-extern struct proc_dir_entry proc_sys_root;
+extern struct proc_dir_entry *proc_sys_root;
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(proc_sys_root);
EXPORT_SYMBOL(proc_root_fs);
EXPORT_SYMBOL(proc_get_inode);
EXPORT_SYMBOL(proc_dir_inode_operations);
-EXPORT_SYMBOL(proc_net_inode_operations);
EXPORT_SYMBOL(proc_net);
EXPORT_SYMBOL(proc_bus);
&proc_root, NULL
};
-struct proc_dir_entry *proc_net, *proc_scsi, *proc_bus, *proc_sysvipc;
+struct proc_dir_entry *proc_net, *proc_scsi, *proc_bus, *proc_sysvipc,
+ *proc_root_fs, *proc_root_driver;
#ifdef CONFIG_MCA
-struct proc_dir_entry proc_mca = {
- PROC_MCA, 3, "mca",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL, &proc_root, NULL
-};
+struct proc_dir_entry *proc_mca;
#endif
#ifdef CONFIG_SYSCTL
-struct proc_dir_entry proc_sys_root = {
- PROC_SYS, 3, "sys", /* inode, name */
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
- 0, &proc_dir_inode_operations, /* size, ops */
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
-};
+struct proc_dir_entry *proc_sys_root;
#endif
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
NULL /* revalidate */
};
-static struct proc_dir_entry proc_root_loadavg = {
- PROC_LOADAVG, 7, "loadavg",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_uptime = {
- PROC_UPTIME, 6, "uptime",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_meminfo = {
- PROC_MEMINFO, 7, "meminfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_kmsg = {
- PROC_KMSG, 4, "kmsg",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kmsg_inode_operations
-};
-static struct proc_dir_entry proc_root_version = {
- PROC_VERSION, 7, "version",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cpuinfo = {
- PROC_CPUINFO, 7, "cpuinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#if defined (CONFIG_PROC_HARDWARE)
-static struct proc_dir_entry proc_root_hardware = {
- PROC_HARDWARE, 8, "hardware",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-#ifdef CONFIG_STRAM_PROC
-static struct proc_dir_entry proc_root_stram = {
- PROC_STRAM, 5, "stram",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
static struct proc_dir_entry proc_root_self = {
- PROC_SELF, 4, "self",
+ 0, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
64, &proc_self_inode_operations,
};
-#ifdef CONFIG_DEBUG_MALLOC
-static struct proc_dir_entry proc_root_malloc = {
- PROC_MALLOC, 6, "malloc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_kcore = {
- PROC_KCORE, 5, "kcore",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kcore_inode_operations
-};
-#ifdef CONFIG_MODULES
-static struct proc_dir_entry proc_root_modules = {
- PROC_MODULES, 7, "modules",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ksyms = {
- PROC_KSYMS, 5, "ksyms",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_stat = {
- PROC_STAT, 4, "stat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_devices = {
- PROC_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_partitions = {
- PROC_PARTITIONS, 10, "partitions",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_interrupts = {
- PROC_INTERRUPTS, 10,"interrupts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_filesystems = {
- PROC_FILESYSTEMS, 11,"filesystems",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-struct proc_dir_entry proc_root_fs = {
- PROC_FS, 2, "fs",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-struct proc_dir_entry proc_root_driver = {
- PROC_DRIVER, 6, "driver",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-static struct proc_dir_entry proc_root_dma = {
- PROC_DMA, 3, "dma",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ioports = {
- PROC_IOPORTS, 7, "ioports",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_iomem = {
- PROC_MEMORY, 5, "iomem",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cmdline = {
- PROC_CMDLINE, 7, "cmdline",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#ifdef CONFIG_RTC
-static struct proc_dir_entry proc_root_rtc = {
- PROC_RTC, 3, "rtc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_locks = {
- PROC_LOCKS, 5, "locks",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_mounts = {
- PROC_MTAB, 6, "mounts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_swaps = {
- PROC_SWAP, 5, "swaps",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_profile = {
- PROC_PROFILE, 7, "profile",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_profile_inode_operations
-};
-static struct proc_dir_entry proc_root_slab = {
- PROC_SLABINFO, 8, "slabinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
#ifdef __powerpc__
static struct proc_dir_entry proc_root_ppc_htab = {
- PROC_PPC_HTAB, 8, "ppc_htab",
+ 0, 8, "ppc_htab",
S_IFREG | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 1, 0, 0,
0, &proc_ppc_htab_inode_operations,
NULL, NULL, /* get_info, fill_inode */
void __init proc_root_init(void)
{
proc_base_init();
- proc_register(&proc_root, &proc_root_loadavg);
- proc_register(&proc_root, &proc_root_uptime);
- proc_register(&proc_root, &proc_root_meminfo);
- proc_register(&proc_root, &proc_root_kmsg);
- proc_register(&proc_root, &proc_root_version);
- proc_register(&proc_root, &proc_root_cpuinfo);
+ proc_misc_init();
proc_register(&proc_root, &proc_root_self);
proc_net = create_proc_entry("net", S_IFDIR, 0);
proc_scsi = create_proc_entry("scsi", S_IFDIR, 0);
proc_sysvipc = create_proc_entry("sysvipc", S_IFDIR, 0);
#endif
#ifdef CONFIG_SYSCTL
- proc_register(&proc_root, &proc_sys_root);
+ proc_sys_root = create_proc_entry("sys", S_IFDIR, 0);
#endif
#ifdef CONFIG_MCA
- proc_register(&proc_root, &proc_mca);
-#endif
-
-#ifdef CONFIG_DEBUG_MALLOC
- proc_register(&proc_root, &proc_root_malloc);
+ proc_mca = create_proc_entry("mca", S_IFDIR, 0);
#endif
- proc_register(&proc_root, &proc_root_kcore);
- proc_root_kcore.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
-
-#ifdef CONFIG_MODULES
- proc_register(&proc_root, &proc_root_modules);
- proc_register(&proc_root, &proc_root_ksyms);
-#endif
- proc_register(&proc_root, &proc_root_stat);
- proc_register(&proc_root, &proc_root_devices);
- proc_register(&proc_root, &proc_root_driver);
- proc_register(&proc_root, &proc_root_partitions);
- proc_register(&proc_root, &proc_root_interrupts);
- proc_register(&proc_root, &proc_root_filesystems);
- proc_register(&proc_root, &proc_root_fs);
- proc_register(&proc_root, &proc_root_dma);
- proc_register(&proc_root, &proc_root_ioports);
- proc_register(&proc_root, &proc_root_iomem);
- proc_register(&proc_root, &proc_root_cmdline);
-#ifdef CONFIG_RTC
- proc_register(&proc_root, &proc_root_rtc);
-#endif
- proc_register(&proc_root, &proc_root_locks);
-
- proc_register(&proc_root, &proc_root_mounts);
- proc_register(&proc_root, &proc_root_swaps);
-
+ proc_root_fs = create_proc_entry("fs", S_IFDIR, 0);
+ proc_root_driver = create_proc_entry("driver", S_IFDIR, 0);
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
#ifdef CONFIG_SUN_OPENPROMFS
openpromfs_init ();
#endif
proc_register(&proc_root, &proc_openprom);
#endif
-#ifdef CONFIG_PROC_HARDWARE
- proc_register(&proc_root, &proc_root_hardware);
-#endif
-#ifdef CONFIG_STRAM_PROC
- proc_register(&proc_root, &proc_root_stram);
-#endif
- proc_register(&proc_root, &proc_root_slab);
-
- if (prof_shift) {
- proc_register(&proc_root, &proc_root_profile);
- proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
- }
-
proc_tty_init();
#ifdef __powerpc__
proc_register(&proc_root, &proc_root_ppc_htab);
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
-
proc_bus = create_proc_entry("bus", S_IFDIR, 0);
}
{
struct page * page;
struct page ** hash;
- unsigned long new_page;
+ struct page *cached_page = NULL;
again:
hash = page_hash(mapping, offset);
page = __find_lock_page(mapping, offset, hash);
if(!page && new) {
- /* not in cache, alloc a new page */
- new_page = page_cache_alloc();
- if (!new_page)
- return 0;
- clear_page(new_page); /* smb code assumes pages are zeroed */
- page = page_cache_entry(new_page);
- if (add_to_page_cache_unique(page, mapping, offset, hash)) {
+ /* not in cache, alloc a new page if we didn't do it yet */
+ if (!cached_page) {
+ cached_page = page_cache_alloc();
+ if (!cached_page)
+ return 0;
+ /* smb code assumes pages are zeroed */
+ clear_page(page_address(cached_page));
+ goto again;
+ }
+ page = cached_page;
+ if (page->buffers)
+ BUG();
+ printk(KERN_DEBUG "smbfs: get_cached_page\n");
+ if (add_to_page_cache_unique(page, mapping, offset, hash))
/* Hmm, a page has materialized in the
cache. Fine. Go back and get that page
- instead ... throwing away this one first. */
- put_cached_page((unsigned long) page);
+ instead... */
goto again;
- }
+ cached_page = NULL;
}
+ printk(KERN_DEBUG "smbfs: get_cached_page done\n");
+ if (cached_page)
+ page_cache_free(cached_page);
if(!page)
return 0;
if(!PageLocked(page))
- printk(KERN_ERR "smbfs/cache.c: page isn't locked! This could be fun ...\n");
+ BUG();
return page_address(page);
}
smb_readpage_sync(struct dentry *dentry, struct page *page)
{
char *buffer = (char *) page_address(page);
- unsigned long offset = page->offset;
+ unsigned long offset = page->pg_offset << PAGE_CACHE_SHIFT;
int rsize = smb_get_rsize(server_from_dentry(dentry));
int count = PAGE_SIZE;
int result;
int wsize = smb_get_wsize(server_from_dentry(dentry));
int result, written = 0;
- offset += page->offset;
+ offset += page->pg_offset << PAGE_CACHE_SHIFT;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize);
pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset+offset);
+ count, (page->pg_offset << PAGE_CACHE_SHIFT)+offset);
return smb_writepage_sync(dentry, page, offset, count);
}
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
/* eof=^D eol=\0 eol2=\0 erase=del
* Page offset: 32MB
*/
#define PAGE_OFFSET (0x02000000UL)
+#define PHYS_OFFSET (0x02000000UL)
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) vpage
* Page offset: 3GB
*/
#define PAGE_OFFSET (0xc0000000UL)
+#define PHYS_OFFSET (0x00000000UL)
#define __virt_to_phys__is_a_macro
#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
* Page offset: 3GB
*/
#define PAGE_OFFSET (0xc0000000UL)
+#define PHYS_OFFSET (0x00000000UL)
#define __virt_to_bus__is_a_macro
#define __virt_to_bus(x) ((x) - 0xe0000000)
* Page offset: 1.5GB
*/
#define PAGE_OFFSET (0x60000000UL)
+#define PHYS_OFFSET (0x00000000UL)
#else
* Page offset: 3GB
*/
#define PAGE_OFFSET (0xc0000000UL)
+#define PHYS_OFFSET (0x40000000UL)
/*
* On NexusPCI, the DRAM is contiguous
*/
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x40000000)
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x40000000)
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET)
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET)
#define __virt_to_phys__is_a_macro
#define __phys_to_virt__is_a_macro
* Page offset: 3GB
*/
#define PAGE_OFFSET (0xc0000000UL)
+#define PHYS_OFFSET (0x10000000UL)
#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x10000000)
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x10000000)
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET)
/*
* These are exactly the same on the RiscPC as the
outb(0, IOMD_ROMCR0);
__asm__ __volatile__(
- "mcr p15, 0, %0, c1, c0, 0\n\t"
- "movs pc, #0"
+ "mcr p15, 0, %0, c1, c0, 0\n\t"
+ "mov pc, #0"
: : "r" (cpu_reset()));
}
/*
* Task size: 3GB
*/
-#define TASK_SIZE (0xc0000000UL)
+#define TASK_SIZE (0xc0000000UL)
/*
* Page offset: 3GB
*/
-#define PAGE_OFFSET (0xc0000000UL)
+#define PAGE_OFFSET (0xc0000000UL)
+#define PHYS_OFFSET (0x00000000UL)
#define __virt_to_phys__is_a_macro
#define __phys_to_virt__is_a_macro
#endif
-#ifndef ARCH_READWRITE
+extern void __readwrite_bug(const char *fn);
-/* for panic */
-#include <linux/kernel.h>
+#ifndef ARCH_READWRITE
-#define readb(p) (panic("readb called, but not implemented"),0)
-#define readw(p) (panic("readw called, but not implemented"),0)
-#define readl(p) (panic("readl called, but not implemented"),0)
-#define writeb(v,p) panic("writeb called, but not implemented")
-#define writew(v,p) panic("writew called, but not implemented")
-#define writel(v,p) panic("writel called, but not implemented")
+#define readb(p) (__readwrite_bug("readb"),0)
+#define readw(p) (__readwrite_bug("readw"),0)
+#define readl(p) (__readwrite_bug("readl"),0)
+#define writeb(v,p) __readwrite_bug("writeb")
+#define writew(v,p) __readwrite_bug("writew")
+#define writel(v,p) __readwrite_bug("writel")
#endif
#define STRICT_MM_TYPECHECKS
#define clear_page(page) memzero((void *)(page), PAGE_SIZE)
-extern void copy_page(unsigned long to, unsigned long from);
+extern void copy_page(void *to, void *from);
#ifdef STRICT_MM_TYPECHECKS
/*
#ifndef __ASSEMBLY__
-#define BUG() do { \
- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
- *(int *)0 = 0; \
-} while (0)
+extern void __bug(const char *file, int line, void *data);
-#define PAGE_BUG(page) do { \
- BUG(); \
-} while (0)
+#define BUG() __bug(__FILE__, __LINE__, NULL)
+#define PAGE_BUG(page) __bug(__FILE__, __LINE__, page)
#endif /* !__ASSEMBLY__ */
#include <asm/arch/memory.h>
-#define __pa(x) __virt_to_phys((unsigned long)(x))
-#define __va(x) ((void *)(__phys_to_virt((unsigned long)(x))))
-#define MAP_NR(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
+#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
#endif
+/*
+ * linux/include/asm-arm/pgtable.h
+ */
#ifndef _ASMARM_PGTABLE_H
#define _ASMARM_PGTABLE_H
#include <linux/config.h>
-#include <asm/arch/memory.h> /* For TASK_SIZE */
+#include <asm/arch/memory.h>
#include <asm/proc-fns.h>
#include <asm/system.h>
-#include <asm/proc/cache.h>
+
+/*
+ * PMD_SHIFT determines the size of the area a second-level page table can map
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
+#define PMD_SHIFT 20
+#define PGDIR_SHIFT 20
#define LIBRARY_TEXT_START 0x0c000000
-#undef TEST_VERIFY_AREA
+#ifndef __ASSEMBLY__
+extern void __pte_error(const char *file, int line, unsigned long val);
+extern void __pmd_error(const char *file, int line, unsigned long val);
+extern void __pgd_error(const char *file, int line, unsigned long val);
+
+#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
+#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
+#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
+#endif /* !__ASSEMBLY__ */
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
+
+/*
+ * The table below defines the page protection levels that we insert into our
+ * Linux page table version. These get translated into the best that the
+ * architecture can perform. Note that on most ARM hardware:
+ * 1) We cannot do execute protection
+ * 2) If we could do execute protection, then read is implied
+ * 3) write implies read permissions
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED
+
+#ifndef __ASSEMBLY__
/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-extern unsigned long *empty_zero_page;
+struct page *empty_zero_page;
+#define ZERO_PAGE(vaddr) (empty_zero_page)
+
+/*
+ * Handling allocation failures during page table setup.
+ */
+extern void __handle_bad_pmd(pmd_t *pmd);
+extern void __handle_bad_pmd_kernel(pmd_t *pmd);
+
+#define pte_none(pte) (!pte_val(pte))
+#define pte_clear(ptep) set_pte((ptep), __pte(0))
+#define pte_pagenr(pte) ((unsigned long)(((pte_val(pte) - PHYS_OFFSET) >> PAGE_SHIFT)))
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
+
+/*
+ * Permanent address of a page.
+ */
+#define page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT))
+#define pte_page(x) (mem_map + pte_pagenr(x))
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+#define pgd_none(pgd) (0)
+#define pgd_bad(pgd) (0)
+#define pgd_present(pgd) (1)
+#define pgd_clear(pgdp)
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+{
+ pte_t pte;
+ pte_val(pte) = physpage | pgprot_val(pgprot);
+ return pte;
+}
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
+extern __inline__ pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+ pte_t pte;
+ pte_val(pte) = (PHYS_OFFSET + ((page - mem_map) << PAGE_SHIFT)) | pgprot_val(pgprot);
+ return pte;
+}
-/* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR (sizeof(unsigned long))
-#define BITS_PER_PTR (8*BYTES_PER_PTR)
+#define page_pte_prot(page,prot) mk_pte(page, prot)
+#define page_pte(page) mk_pte(page, __pgprot(0))
-/* to align the pointer to a pointer address */
-#define PTR_MASK (~(sizeof(void*)-1))
+/* to find an entry in a page-table-directory */
+#define __pgd_offset(addr) ((addr) >> PGDIR_SHIFT)
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2 2
+#define pgd_offset(mm, addr) ((mm)->pgd+__pgd_offset(addr))
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
- ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
-extern void __bad_pmd(pmd_t *pmd);
-extern void __bad_pmd_kernel(pmd_t *pmd);
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, addr) ((pmd_t *)(dir))
+
+/* Find an entry in the third-level page table.. */
+#define __pte_offset(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset(dir, addr) ((pte_t *)pmd_page(*(dir)) + __pte_offset(addr))
+
+/*
+ * Get the cache handling stuff now.
+ */
+#include <asm/proc/cache.h>
/*
* Page table cache stuff
*/
#ifndef CONFIG_NO_PGT_CACHE
-#ifndef __SMP__
+#ifdef __SMP__
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif /* __SMP__ */
+
extern struct pgtable_cache_struct {
unsigned long *pgd_cache;
unsigned long *pte_cache;
#define pte_quicklist (quicklists.pte_cache)
#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-#else /* __SMP__ */
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif /* __SMP__ */
-
/* used for quicklists */
#define __pgd_next(pgd) (((unsigned long *)pgd)[1])
#define __pte_next(pte) (((unsigned long *)pte)[0])
{
unsigned long *ret;
- if((ret = pgd_quicklist) != NULL) {
+ if ((ret = pgd_quicklist) != NULL) {
pgd_quicklist = (unsigned long *)__pgd_next(ret);
ret[1] = ret[2];
clean_cache_area(ret + 1, 4);
return (pgd_t *)ret;
}
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+ __pgd_next(pgd) = (unsigned long) pgd_quicklist;
+ pgd_quicklist = (unsigned long *) pgd;
+ pgtable_cache_size++;
+}
+
/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
+#define get_pmd_fast() ((pmd_t *)0)
+
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
{
- return (pmd_t *)0;
}
extern __inline__ pte_t *get_pte_fast(void)
return (pte_t *)ret;
}
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
- __pgd_next(pgd) = (unsigned long) pgd_quicklist;
- pgd_quicklist = (unsigned long *) pgd;
- pgtable_cache_size++;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
-{
-}
-
extern __inline__ void free_pte_fast(pte_t *pte)
{
__pte_next(pte) = (unsigned long) pte_quicklist;
#else /* CONFIG_NO_PGT_CACHE */
-#define get_pgd_fast() (NULL)
-#define get_pmd_fast() (NULL)
-#define get_pte_fast() (NULL)
+#define pgd_quicklist ((unsigned long *)0)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist ((unsigned long *)0)
+
+#define get_pgd_fast() ((pgd_t *)0)
+#define get_pmd_fast() ((pmd_t *)0)
+#define get_pte_fast() ((pte_t *)0)
#define free_pgd_fast(pgd) free_pgd_slow(pgd)
#define free_pmd_fast(pmd) free_pmd_slow(pmd)
#endif /* CONFIG_NO_PGT_CACHE */
+extern pgd_t *get_pgd_slow(void);
+extern void free_pgd_slow(pgd_t *pgd);
+
+#define free_pmd_slow(pmd) do { } while (0)
+
+extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long addr_preadjusted);
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long addr_preadjusted);
+extern void free_pte_slow(pte_t *pte);
+
#include <asm/proc/pgtable.h>
+extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+ return pte;
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
+#define pte_free_kernel(pte) free_pte_fast(pte)
+#define pte_free(pte) free_pte_fast(pte)
+
+#ifndef pte_alloc_kernel
+extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ pte_t *page = (pte_t *) get_pte_fast();
+
+ if (!page)
+ return get_pte_kernel_slow(pmd, address);
+ set_pmd(pmd, mk_kernel_pmd(page));
+ return page + address;
+ }
+ if (pmd_bad(*pmd)) {
+ __handle_bad_pmd_kernel(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + address;
+}
+#endif
+
+extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ pte_t *page = (pte_t *) get_pte_fast();
+
+ if (!page)
+ return get_pte_slow(pmd, address);
+ set_pmd(pmd, mk_user_pmd(page));
+ return page + address;
+ }
+ if (pmd_bad(*pmd)) {
+ __handle_bad_pmd(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + address;
+}
+
+#define pmd_free_kernel pmd_free
+#define pmd_free(pmd) do { } while (0)
+
+#define pmd_alloc_kernel pmd_alloc
+extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+#define pgd_free(pgd) free_pgd_fast(pgd)
+
+extern __inline__ pgd_t *pgd_alloc(void)
+{
+ pgd_t *pgd;
+
+ pgd = get_pgd_fast();
+ if (!pgd)
+ pgd = get_pgd_slow();
+
+ return pgd;
+}
+
+extern int do_check_pgt_cache(int, int);
+
extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
{
struct task_struct * p;
#define update_mmu_cache(vma,address,pte)
-#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 9)
-#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+/*
+ * We support up to 32GB of swap on 4k machines
+ */
+#define SWP_TYPE(entry) (((pte_val(entry)) >> 2) & 0x7f)
+#define SWP_OFFSET(entry) ((pte_val(entry)) >> 9)
+#define SWP_ENTRY(type,offset) __pte((((type) << 2) | ((offset) << 9)))
#define module_map vmalloc
#define module_unmap vfree
-extern int do_check_pgt_cache(int, int);
-
/*
* We rely on GCC optimising this code away for
* architectures which it doesn't apply to. Note
#define io_remap_page_range remap_page_range
+#endif /* !__ASSEMBLY__ */
+
#endif /* _ASMARM_PGTABLE_H */
}
extern __inline__ void
-memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long addr)
+memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr)
{
- cpu_memc_update_entry(mm->pgd, pte_val(pte), addr);
+ cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr);
if (mm == current->active_mm)
processor._set_pgd(mm->pgd);
}
extern __inline__ void
-memc_clear(struct mm_struct *mm, unsigned long phys_addr)
+memc_clear(struct mm_struct *mm, struct page *page)
{
- cpu_memc_update_entry(mm->pgd, phys_addr, 0);
+ cpu_memc_update_entry(mm->pgd, page_address(page), 0);
if (mm == current->active_mm)
processor._set_pgd(mm->pgd);
#define __ASM_PROC_PGTABLE_H
/*
- * PMD_SHIFT determines the size of the area a second-level page table can map
+ * entries per page directory level: they are two-level, so
+ * we don't really have any PMD directory.
*/
-#define PMD_SHIFT 20
-#define PMD_SIZE (1UL << PMD_SHIFT)
-#define PMD_MASK (~(PMD_SIZE-1))
+#define PTRS_PER_PTE 32
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 32
/*
- * PGDIR_SHIFT determines what a third-level page table entry can map
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
*/
-#define PGDIR_SHIFT 20
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#define VMALLOC_START 0x01a00000
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END 0x01c00000
-/*
- * entries per page directory level: the arm3 is one-level, so
- * we don't really have any PMD or PTE directory physically.
- */
-#define PTRS_PER_PTE 32
-#define PTRS_PER_PMD 1
-#define PTRS_PER_PGD 32
-#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
+#define _PAGE_TABLE (0x01)
-#define VMALLOC_START 0x01a00000
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END 0x01c00000
+#define pmd_bad(pmd) ((pmd_val(pmd) & 0xfc000002))
+#define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd))
+
+extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
+{
+ unsigned long pte_ptr = (unsigned long)ptep;
+ pmd_t pmd;
+
+ pmd_val(pmd) = __virt_to_phys(pte_ptr) | prot;
+
+ return pmd;
+}
+
+/* these are aliases for the above function */
+#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE)
+#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_TABLE)
+
+extern __inline__ unsigned long pmd_page(pmd_t pmd)
+{
+ return __phys_to_virt(pmd_val(pmd) & ~_PAGE_TABLE);
+}
+
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
#define _PAGE_PRESENT 0x01
#define _PAGE_READONLY 0x02
#define _PAGE_OLD 0x08
#define _PAGE_CLEAN 0x10
-#define _PAGE_TABLE (_PAGE_PRESENT)
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_OLD | _PAGE_CLEAN)
-
/* -- present -- -- !dirty -- --- !write --- ---- !user --- */
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_CLEAN | _PAGE_READONLY | _PAGE_NOT_USER)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_CLEAN )
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_CLEAN | _PAGE_READONLY )
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_NOT_USER)
-/*
- * The arm can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
-
-extern unsigned long physical_start;
-extern unsigned long physical_end;
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_OLD | _PAGE_CLEAN)
-#define pte_none(pte) (!pte_val(pte))
-#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
-#define pte_clear(ptep) set_pte((ptep), __pte(0))
-
-#define pmd_none(pmd) (!pmd_val(pmd))
-#define pmd_bad(pmd) ((pmd_val(pmd) & 0xfc000002))
-#define pmd_present(pmd) (pmd_val(pmd) & _PAGE_PRESENT)
-#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-#define pgd_none(pgd) (0)
-#define pgd_bad(pgd) (0)
-#define pgd_present(pgd) (1)
-#define pgd_clear(pgdp)
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-extern inline int pte_read(pte_t pte) { return !(pte_val(pte) & _PAGE_NOT_USER); }
-extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_READONLY); }
-extern inline int pte_exec(pte_t pte) { return !(pte_val(pte) & _PAGE_NOT_USER); }
-extern inline int pte_dirty(pte_t pte) { return !(pte_val(pte) & _PAGE_CLEAN); }
-extern inline int pte_young(pte_t pte) { return !(pte_val(pte) & _PAGE_OLD); }
+#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
+#define pte_read(pte) (!(pte_val(pte) & _PAGE_NOT_USER))
+#define pte_write(pte) (!(pte_val(pte) & _PAGE_READONLY))
+#define pte_exec(pte) (!(pte_val(pte) & _PAGE_NOT_USER))
+#define pte_dirty(pte) (!(pte_val(pte) & _PAGE_CLEAN))
+#define pte_young(pte) (!(pte_val(pte) & _PAGE_OLD))
extern inline pte_t pte_nocache(pte_t pte) { return pte; }
extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_READONLY; return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) &= ~_PAGE_CLEAN; return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) &= ~_PAGE_OLD; return pte; }
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{
- pte_t pte;
- pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
- return pte;
-}
-
-/* This takes a physical page address that is used by the remapping functions */
-extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{
- pte_t pte;
- pte_val(pte) = physpage + pgprot_val(pgprot);
- return pte;
-}
-
-extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
- pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
- return pte;
-}
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified. Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-extern __inline__ unsigned long pte_page(pte_t pte)
-{
- return __phys_to_virt(pte_val(pte) & PAGE_MASK);
-}
-
-extern __inline__ pmd_t mk_pmd(pte_t *ptep)
-{
- pmd_t pmd;
- pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_TABLE;
- return pmd;
-}
-
-/* these are aliases for the above function */
-#define mk_user_pmd(ptep) mk_pmd(ptep)
-#define mk_kernel_pmd(ptep) mk_pmd(ptep)
-
-#define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd))
-
-extern __inline__ unsigned long pmd_page(pmd_t pmd)
-{
- return __phys_to_virt(pmd_val(pmd) & ~_PAGE_TABLE);
-}
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-/* to find an entry in a page-table-directory */
-extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
- return mm->pgd + (address >> PGDIR_SHIFT);
-}
-
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
-
-/* Find an entry in the third-level page table.. */
-extern __inline__ pte_t * pte_offset(pmd_t *dir, unsigned long address)
-{
- return (pte_t *)pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-extern void free_table(void *table);
-
-/* keep this as an inline so we get type checking */
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
-{
- free_table(pgd);
-}
-
-/* keep this as an inline so we get type checking */
-extern __inline__ void free_pte_slow(pte_t *pte)
-{
- free_table(pte);
-}
-
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
-{
-}
-
-#define pgd_free(pgd) free_pgd_fast(pgd)
-
-extern __inline__ pgd_t *pgd_alloc(void)
-{
- extern pgd_t *get_pgd_slow(void);
- pgd_t *pgd;
-
- pgd = get_pgd_fast();
- if (!pgd)
- pgd = get_pgd_slow();
-
- return pgd;
-}
-
-#define pte_free_kernel(pte) free_pte_fast(pte)
-#define pte_free(pte) free_pte_fast(pte)
-
-extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
-{
- extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
- if (pmd_none (*pmd)) {
- pte_t *page = (pte_t *) get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- set_pmd(pmd, mk_pmd(page));
- return page + address;
- }
- if (pmd_bad (*pmd)) {
- __bad_pmd(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern __inline__ void pmd_free(pmd_t *pmd)
-{
-}
-
-extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
- return (pmd_t *) pgd;
-}
-
-#define pmd_free_kernel pmd_free
-#define pmd_alloc_kernel pmd_alloc
#define pte_alloc_kernel pte_alloc
#endif /* __ASM_PROC_PGTABLE_H */
* This flushes back any buffered write data. We have to clean the entries
* in the cache for this page. This does not invalidate either I or D caches.
*/
-#define flush_page_to_ram(_page) \
- cpu_flush_ram_page((_page) & PAGE_MASK);
+static __inline__ void flush_page_to_ram(struct page *page)
+{
+ unsigned long virt = page_address(page);
+ cpu_flush_ram_page(virt);
+}
/*
* TLB flushing:
#include <asm/proc/domain.h>
/*
- * PMD_SHIFT determines the size of the area a second-level page table can map
+ * entries per page directory level: they are two-level, so
+ * we don't really have any PMD directory.
*/
-#define PMD_SHIFT 20
-#define PMD_SIZE (1UL << PMD_SHIFT)
-#define PMD_MASK (~(PMD_SIZE-1))
-
-/*
- * PGDIR_SHIFT determines what a third-level page table entry can map
- */
-#define PGDIR_SHIFT 20
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
-
-/*
- * entries per page directory level: the sa110 is two-level, so
- * we don't really have any PMD directory physically.
- */
-#define PTRS_PER_PTE 256
-#define PTRS_PER_PMD 1
-#define PTRS_PER_PGD 4096
-#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
+#define PTRS_PER_PTE 256
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 4096
/*
* Just any arbitrary offset to the start of the vmalloc VM area: the
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
-extern unsigned long get_page_2k(int priority);
-extern void free_page_2k(unsigned long page);
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
/****************
* PMD functions *
****************/
#define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
#define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
-#define pmd_none(pmd) (!pmd_val(pmd))
-#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
#define pmd_bad(pmd) (pmd_val(pmd) & 2)
-#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_USER_TABLE)
-#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_KERNEL_TABLE)
#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd)
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
-
-extern __inline__ int pmd_present(pmd_t pmd)
-{
- return ((pmd_val(pmd) + 1) & 2);
-}
-
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
-{
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern __inline__ void pmd_free(pmd_t *pmd)
-{
-}
-
-extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
- return (pmd_t *) pgd;
-}
-
-#define pmd_free_kernel pmd_free
-#define pmd_alloc_kernel pmd_alloc
-
extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
{
unsigned long pte_ptr = (unsigned long)ptep;
pmd_t pmd;
- pte_ptr -= PTRS_PER_PTE * BYTES_PER_PTR;
+ pte_ptr -= PTRS_PER_PTE * sizeof(void *);
/*
* The pmd must be loaded with the physical
return pmd;
}
+/* these are aliases for the above function */
+#define mk_user_pmd(ptep) __mk_pmd(ptep, _PAGE_USER_TABLE)
+#define mk_kernel_pmd(ptep) __mk_pmd(ptep, _PAGE_KERNEL_TABLE)
+
extern __inline__ unsigned long pmd_page(pmd_t pmd)
{
unsigned long ptr;
- ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * BYTES_PER_PTR - 1);
+ ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * sizeof(void *) - 1);
- ptr += PTRS_PER_PTE * BYTES_PER_PTR;
+ ptr += PTRS_PER_PTE * sizeof(void *);
return __phys_to_virt(ptr);
}
#define PTE_CACHEABLE 0x0008
#define PTE_BUFFERABLE 0x0004
-#define pte_none(pte) (!pte_val(pte))
-#define pte_clear(ptep) set_pte(ptep, __pte(0))
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{
- pte_t pte;
- pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
- return pte;
-}
-
-/* This takes a physical page address that is used by the remapping functions */
-extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{
- pte_t pte;
- pte_val(pte) = physpage + pgprot_val(pgprot);
- return pte;
-}
-
#define set_pte(ptep, pte) cpu_set_pte(ptep,pte)
-extern __inline__ unsigned long pte_page(pte_t pte)
-{
- return __phys_to_virt(pte_val(pte) & PAGE_MASK);
-}
-
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
-extern __inline__ void free_pte_slow(pte_t *pte)
-{
- free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
-}
-
-#define pte_free_kernel(pte) free_pte_fast(pte)
-#define pte_free(pte) free_pte_fast(pte)
-
-/*###############################################################################
- * New PageTableEntry stuff...
- */
/* We now keep two sets of ptes - the physical and the linux version.
* This gives us many advantages, and allows us greater flexibility.
*
*/
#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG
#define _L_PTE_READ L_PTE_USER | L_PTE_CACHEABLE
-#define _L_PTE_EXEC _L_PTE_READ | L_PTE_EXEC
#define PAGE_NONE __pgprot(_L_PTE_DEFAULT)
#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_BUFFERABLE)
#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
#define PAGE_KERNEL __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
-#define _PAGE_CHG_MASK (PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
+#define _PAGE_CHG_MASK (PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
-/*
- * The table below defines the page protection levels that we insert into our
- * Linux page table version. These get translated into the best that the
- * architecture can perform. Note that on most ARM hardware:
- * 1) We cannot do execute protection
- * 2) If we could do execute protection, then read is implied
- * 3) write implies read permissions
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
-
-#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
+#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
#define pte_read(pte) (pte_val(pte) & L_PTE_USER)
#define pte_write(pte) (pte_val(pte) & L_PTE_WRITE)
#define pte_exec(pte) (pte_val(pte) & L_PTE_EXEC)
#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
#define PTE_BIT_FUNC(fn,op) \
-extern inline pte_t fn##(pte_t pte) { pte_val(pte) op##; return pte; }
-
-/*PTE_BIT_FUNC(pte_rdprotect, &= ~L_PTE_USER);*/
-PTE_BIT_FUNC(pte_wrprotect, &= ~L_PTE_WRITE);
-PTE_BIT_FUNC(pte_exprotect, &= ~L_PTE_EXEC);
-PTE_BIT_FUNC(pte_mkclean, &= ~L_PTE_DIRTY);
-PTE_BIT_FUNC(pte_mkold, &= ~L_PTE_YOUNG);
-/*PTE_BIT_FUNC(pte_mkread, |= L_PTE_USER);*/
-PTE_BIT_FUNC(pte_mkwrite, |= L_PTE_WRITE);
-PTE_BIT_FUNC(pte_mkexec, |= L_PTE_EXEC);
-PTE_BIT_FUNC(pte_mkdirty, |= L_PTE_DIRTY);
-PTE_BIT_FUNC(pte_mkyoung, |= L_PTE_YOUNG);
-PTE_BIT_FUNC(pte_nocache, &= ~L_PTE_CACHEABLE);
-
-extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
- pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
- return pte;
-}
-
-/* Find an entry in the third-level page table.. */
-extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
- return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-}
-
-extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
- if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_pte_fast();
-
- if (!page)
- return get_pte_kernel_slow(pmd, address);
- set_pmd(pmd, mk_kernel_pmd(page));
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pmd_kernel(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
- extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
- address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
- if (pmd_none(*pmd)) {
- pte_t *page = (pte_t *) get_pte_fast();
-
- if (!page)
- return get_pte_slow(pmd, address);
- set_pmd(pmd, mk_user_pmd(page));
- return page + address;
- }
- if (pmd_bad(*pmd)) {
- __bad_pmd(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + address;
-}
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-#define pgd_none(pgd) (0)
-#define pgd_bad(pgd) (0)
-#define pgd_present(pgd) (1)
-#define pgd_clear(pgdp)
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-/* to find an entry in a page-table-directory */
-extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
- return mm->pgd + (address >> PGDIR_SHIFT);
-}
-
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
-{
- do {
- if (pgd) { /* can pgd be NULL? */
- pmd_t *pmd;
- pte_t *pte;
-
- /* pgd is never none and bad - it is
- * detected in the pmd macros.
- */
- pmd = pmd_offset(pgd, 0);
- if (pmd_none(*pmd))
- break;
- if (pmd_bad(*pmd)) {
- printk("free_pgd_slow: bad directory entry %08lx\n", pmd_val(*pmd));
- pmd_clear(pmd);
- break;
- }
-
- pte = pte_offset(pmd, 0);
- pmd_clear(pmd);
- pte_free(pte);
- pmd_free(pmd);
- }
- } while (0);
- free_pages((unsigned long) pgd, 2);
-}
-
-#define pgd_free(pgd) free_pgd_fast(pgd)
-
-extern __inline__ pgd_t *pgd_alloc(void)
-{
- extern pgd_t *get_pgd_slow(void);
- pgd_t *pgd;
-
- pgd = get_pgd_fast();
- if (!pgd)
- pgd = get_pgd_slow();
-
- return pgd;
-}
+extern inline pte_t pte_##fn##(pte_t pte) { pte_val(pte) op##; return pte; }
+
+/*PTE_BIT_FUNC(rdprotect, &= ~L_PTE_USER);*/
+/*PTE_BIT_FUNC(mkread, |= L_PTE_USER);*/
+PTE_BIT_FUNC(wrprotect, &= ~L_PTE_WRITE);
+PTE_BIT_FUNC(mkwrite, |= L_PTE_WRITE);
+PTE_BIT_FUNC(exprotect, &= ~L_PTE_EXEC);
+PTE_BIT_FUNC(mkexec, |= L_PTE_EXEC);
+PTE_BIT_FUNC(mkclean, &= ~L_PTE_DIRTY);
+PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY);
+PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG);
+PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
+PTE_BIT_FUNC(nocache, &= ~L_PTE_CACHEABLE);
#endif /* __ASM_PROC_PGTABLE_H */
* - when adding fields, don't rely on the address until
* a patch from me has been released
* - unused fields should be zero (for future expansion)
+ * - this structure is relatively short-lived - only
+ * guaranteed to contain useful data in setup_arch()
*/
#define COMMAND_LINE_SIZE 1024
char commandline[COMMAND_LINE_SIZE];
};
+/*
+ * Memory map description
+ */
+#define NR_BANKS 4
+
+struct meminfo {
+ int nr_banks;
+ unsigned long end;
+ struct {
+ unsigned long start;
+ unsigned long size;
+ } bank[NR_BANKS];
+};
+
+extern struct meminfo meminfo;
+
#endif
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ISA_IO_base + (b),(c))
#define isa_memcpy_toio(a,b,c) memcpy_toio(__ISA_IO_base + (a),(b),(c))
+
/*
* Again, i386 does not require mem IO specific function.
*/
-#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
+#define isa_eth_io_copy_and_csum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
static inline int check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
-#define __pte(x) ((pte_t) { (x) } )
-#define __pmd(x) ((pmd_t) { (x) } )
-#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
#endif /* !__ASSEMBLY__ */
return (pmd_t *) pgd;
}
-#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8)))
-
#endif /* _I386_PGTABLE_2LEVEL_H */
return (pmd_t *)pgd_page(*pgd) + address;
}
-/*
- * Subtle. offset can overflow 32 bits and that's a feature - we can do
- * up to 16 TB swap on PAE. (Not that anyone should need that much
- * swapspace, but who knows?)
- */
-#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8ULL)))
-
#endif /* _I386_PGTABLE_3LEVEL_H */
{
}
-#define SWP_TYPE(entry) (((pte_val(entry)) >> 1) & 0x3f)
-#define SWP_OFFSET(entry) ((pte_val(entry)) >> 8)
+/* Encode and de-code a swap entry */
+#define SWP_TYPE(x) (((x).val >> 1) & 0x3f)
+#define SWP_OFFSET(x) ((x).val >> 8)
+#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
+#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define swp_entry_to_pte(x) ((pte_t) { (x).val })
#define module_map vmalloc
#define module_unmap vfree
#include <asm/system.h>
#include <asm/ptrace.h>
#include <linux/smp.h>
+#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/mmx.h>
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
#ifdef __KERNEL__
/*
* Include file for the interface to an APM BIOS
- * Copyright 1994-1998 Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
+ * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
--- /dev/null
+/*
+ * include/linux/bfs_fs.h - BFS data structures on disk.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#ifndef _LINUX_BFS_FS_H
+#define _LINUX_BFS_FS_H
+
+#define BFS_BSIZE_BITS 9
+#define BFS_BSIZE (1<<BFS_BSIZE_BITS)
+
+#define BFS_MAGIC 0x1BADFACE
+#define BFS_ROOT_INO 2
+#define BFS_INODES_PER_BLOCK 8
+
+/* SVR4 vnode type values (bfs_inode->i_vtype) */
+#define BFS_VDIR 2
+#define BFS_VREG 1
+
+/* BFS inode layout on disk */
+struct bfs_inode {
+ __u16 i_ino;
+ __u16 i_unused;
+ __u32 i_sblock;
+ __u32 i_eblock;
+ __u32 i_eoffset;
+ __u32 i_vtype;
+ __u32 i_mode;
+ __s32 i_uid;
+ __s32 i_gid;
+ __u32 i_nlink;
+ __u32 i_atime;
+ __u32 i_mtime;
+ __u32 i_ctime;
+ __u8 i_padding[16];
+};
+
+#define BFS_NAMELEN 14
+#define BFS_DIRENT_SIZE 16
+#define BFS_DIRS_PER_BLOCK 32
+
+struct bfs_dirent {
+ __u16 ino;
+ char name[BFS_NAMELEN];
+};
+
+/* BFS superblock layout on disk */
+struct bfs_super_block {
+ __u32 s_magic;
+ __u32 s_start;
+ __u32 s_end;
+ __s32 s_from;
+ __s32 s_to;
+ __s32 s_bfrom;
+ __s32 s_bto;
+ char s_fsname[6];
+ char s_volume[6];
+ __u8 s_padding[472];
+};
+
+#define BFS_NZFILESIZE(ip) \
+ (((ip)->i_eoffset + 1) - (ip)->i_sblock * BFS_BSIZE)
+
+#define BFS_FILESIZE(ip) \
+ ((ip)->i_sblock == 0 ? 0 : BFS_NZFILESIZE(ip))
+
+#define BFS_FILEBLOCKS(ip) \
+ ((ip)->i_sblock == 0 ? 0 : ((ip)->i_eblock + 1) - (ip)->i_sblock)
+
+#define BFS_OFF2INO(offset) \
+ ((((offset) - BFS_BSIZE) / sizeof(struct bfs_inode)) + BFS_ROOT_INO)
+
+#define BFS_INO2OFF(ino) \
+ ((__u32)(((ino) - BFS_ROOT_INO) * sizeof(struct bfs_inode)) + BFS_BSIZE)
+
+#define BFS_UNCLEAN(bfs_sb, sb) \
+ ((bfs_sb->s_from != -1) && (bfs_sb->s_to != -1) && !(sb->s_flags & MS_RDONLY))
+
+#ifdef __KERNEL__
+
+/* inode.c */
+extern int init_bfs_fs(void);
+
+/* file.c */
+extern struct inode_operations bfs_file_inops;
+
+/* dir.c */
+extern struct inode_operations bfs_dir_inops;
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_BFS_FS_H */
--- /dev/null
+/*
+ * include/linux/bfs_fs_i.h
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#ifndef _LINUX_BFS_FS_I
+#define _LINUX_BFS_FS_I
+
+/*
+ * BFS file system in-core inode info
+ */
+struct bfs_inode_info {
+ __u32 i_dsk_ino; /* inode number from the disk, can be 0 */
+ __u32 i_sblock;
+ __u32 i_eblock;
+};
+
+#endif /* _LINUX_BFS_FS_I */
--- /dev/null
+/*
+ * include/linux/bfs_fs_sb.h
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#ifndef _LINUX_BFS_FS_SB
+#define _LINUX_BFS_FS_SB
+
+/*
+ * BFS file system in-core superblock info
+ */
+struct bfs_sb_info {
+ __u32 si_blocks;
+ __u32 si_freeb;
+ __u32 si_freei;
+ __u32 si_lf_ioff;
+ __u32 si_lf_sblk;
+ __u32 si_lf_eblk;
+ __u32 si_lasti;
+ __u32 si_imap_len;
+ __u8 *si_imap;
+ struct buffer_head * si_sbh; /* buffer header w/superblock */
+ struct bfs_super_block * si_bfs_sb; /* superblock in si_sbh->b_data */
+};
+
+#endif /* _LINUX_BFS_FS_SB */
#include <linux/hfs_fs_i.h>
#include <linux/adfs_fs_i.h>
#include <linux/qnx4_fs_i.h>
+#include <linux/bfs_fs_i.h>
#include <linux/udf_fs_i.h>
#include <linux/ncp_fs_i.h>
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
struct qnx4_inode_info qnx4_i;
+ struct bfs_inode_info bfs_i;
struct udf_inode_info udf_i;
struct ncp_inode_info ncpfs_i;
struct socket socket_i;
#include <linux/hfs_fs_sb.h>
#include <linux/adfs_fs_sb.h>
#include <linux/qnx4_fs_sb.h>
+#include <linux/bfs_fs_sb.h>
#include <linux/udf_fs_sb.h>
#include <linux/ncp_fs_sb.h>
struct hfs_sb_info hfs_sb;
struct adfs_sb_info adfs_sb;
struct qnx4_sb_info qnx4_sb;
+ struct bfs_sb_info bfs_sb;
struct udf_sb_info udf_sb;
struct ncp_sb_info ncpfs_sb;
void *generic_sbp;
#ifdef __KERNEL__
-/* special shmsegs[id], msgque[id] or semary[id] values */
+/* special shmsegs[id] values */
#define IPC_UNUSED ((void *) -1)
#define IPC_NOID ((void *) -2) /* being allocated/destroyed */
struct vm_area_struct **vm_pprev_share;
struct vm_operations_struct * vm_ops;
- unsigned long vm_offset;
+ unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
struct file * vm_file;
void * vm_private_data; /* was vm_pte (shared mem) */
};
int (*swapout)(struct page *, struct file *);
};
+/*
+ * A swap entry has to fit into a "unsigned long", as
+ * the entry is hidden in the "pg_offset" field of the
+ * swapper address space.
+ */
+typedef struct {
+ unsigned long val;
+} swp_entry_t;
+
/*
* Try to keep the most commonly accessed fields in single cache lines
* here (16 bytes or greater). This ordering should be particularly
/* these must be first (free area handling) */
struct list_head list;
struct address_space *mapping;
- unsigned long offset;
+ unsigned long pg_offset;
struct page *next_hash;
atomic_t count;
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
extern void show_mem(void);
extern void oom(struct task_struct * tsk);
extern void si_meminfo(struct sysinfo * val);
-extern void swapin_readahead(pte_t);
+extern void swapin_readahead(swp_entry_t);
/* mmap.c */
extern void vma_init(void);
unsigned long grow;
address &= PAGE_MASK;
- grow = vma->vm_start - address;
+ grow = (vma->vm_start - address) >> PAGE_SHIFT;
if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
- (vma->vm_mm->total_vm << PAGE_SHIFT) + grow > current->rlim[RLIMIT_AS].rlim_cur)
+ ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
return -ENOMEM;
vma->vm_start = address;
- vma->vm_offset -= grow;
- vma->vm_mm->total_vm += grow >> PAGE_SHIFT;
+ vma->vm_pgoff -= grow;
+ vma->vm_mm->total_vm += grow;
if (vma->vm_flags & VM_LOCKED)
- vma->vm_mm->locked_vm += grow >> PAGE_SHIFT;
+ vma->vm_mm->locked_vm += grow;
return 0;
}
#include <linux/highmem.h>
#include <linux/list.h>
-extern inline pte_t get_pagecache_pte(struct page *page)
-{
- /*
- * the pagecache is still machineword sized. The rest of the VM
- * can deal with arbitrary sized ptes.
- */
- return __pte(page->offset);
-}
-
/*
* The page cache can done in larger chunks than
* one page, because it allows for more efficient
extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long offset)
{
#define i (((unsigned long) mapping)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
-#define o (offset >> PAGE_SHIFT)
#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
- return s(i+o) & (PAGE_HASH_SIZE-1);
+ return s(i+offset) & (PAGE_HASH_SIZE-1);
#undef i
#undef o
#undef s
void pci_init(void);
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
-int get_pci_list(char *buf);
int pci_proc_attach_device(struct pci_dev *dev);
int pci_proc_detach_device(struct pci_dev *dev);
void pci_name_device(struct pci_dev *dev);
#define PCI_DEVICE_ID_INTERG_1680 0x1680
#define PCI_DEVICE_ID_INTERG_1682 0x1682
#define PCI_DEVICE_ID_INTERG_2000 0x2000
+#define PCI_DEVICE_ID_INTERG_2010 0x2010
#define PCI_VENDOR_ID_REALTEK 0x10ec
#define PCI_DEVICE_ID_REALTEK_8029 0x8029
* We always define these enumerators
*/
-enum root_directory_inos {
+enum {
PROC_ROOT_INO = 1,
- PROC_LOADAVG,
- PROC_UPTIME,
- PROC_MEMINFO,
- PROC_KMSG,
- PROC_VERSION,
- PROC_CPUINFO,
- PROC_PCI,
- PROC_MCA,
- PROC_NUBUS,
- PROC_MAC_VIA,
- PROC_SELF, /* will change inode # */
- PROC_NET,
- PROC_SCSI,
- PROC_MALLOC,
- PROC_KCORE,
- PROC_MODULES,
- PROC_STAT,
- PROC_DEVICES,
- PROC_PARTITIONS,
- PROC_INTERRUPTS,
- PROC_FILESYSTEMS,
- PROC_KSYMS,
- PROC_DMA,
- PROC_IOPORTS,
- PROC_MEMORY,
- PROC_PROFILE, /* whether enabled or not */
- PROC_CMDLINE,
- PROC_SYS,
- PROC_MTAB,
- PROC_SWAP,
- PROC_MD,
- PROC_RTC,
- PROC_LOCKS,
- PROC_HARDWARE,
- PROC_SLABINFO,
- PROC_PARPORT,
- PROC_PPC_HTAB,
- PROC_STRAM,
- PROC_SOUND,
- PROC_MTRR, /* whether enabled or not */
- PROC_FS,
- PROC_SYSVIPC,
- PROC_DRIVER,
};
enum pid_directory_inos {
};
enum net_directory_inos {
- PROC_NET_UNIX = 128,
- PROC_NET_ARP,
- PROC_NET_ROUTE,
- PROC_NET_DEV,
- PROC_NET_RAW,
- PROC_NET_RAW6,
- PROC_NET_TCP,
- PROC_NET_TCP6,
- PROC_NET_UDP,
- PROC_NET_UDP6,
- PROC_NET_SNMP,
- PROC_NET_RARP,
- PROC_NET_IGMP,
- PROC_NET_IPMR_VIF,
- PROC_NET_IPMR_MFC,
- PROC_NET_IPFWFWD,
- PROC_NET_IPFWIN,
- PROC_NET_IPFWOUT,
- PROC_NET_IPACCT,
- PROC_NET_IPMSQHST,
- PROC_NET_WIRELESS,
- PROC_NET_IPX_INTERFACE,
- PROC_NET_IPX_ROUTE,
- PROC_NET_IPX,
- PROC_NET_ATALK,
- PROC_NET_AT_ROUTE,
- PROC_NET_ATIF,
- PROC_NET_AX25_ROUTE,
- PROC_NET_AX25,
- PROC_NET_AX25_CALLS,
- PROC_NET_BMAC,
- PROC_NET_NR_NODES,
- PROC_NET_NR_NEIGH,
- PROC_NET_NR,
- PROC_NET_SOCKSTAT,
- PROC_NET_SOCKSTAT6,
- PROC_NET_RTCACHE,
- PROC_NET_AX25_BPQETHER,
- PROC_NET_IP_MASQ_APP,
- PROC_NET_RT6,
- PROC_NET_SNMP6,
- PROC_NET_RT6_STATS,
- PROC_NET_NDISC,
- PROC_NET_STRIP_STATUS,
- PROC_NET_STRIP_TRACE,
- PROC_NET_Z8530,
- PROC_NET_RS_NODES,
- PROC_NET_RS_NEIGH,
- PROC_NET_RS_ROUTES,
- PROC_NET_RS,
- PROC_NET_CL2LLC,
- PROC_NET_X25_ROUTES,
- PROC_NET_X25,
- PROC_NET_TR_RIF,
- PROC_NET_DN_DEV,
- PROC_NET_DN_ADJ,
- PROC_NET_DN_ROUTE,
- PROC_NET_DN_CACHE,
- PROC_NET_DN_SKT,
- PROC_NET_DN_FW_CHAINS,
- PROC_NET_DN_FW_CHAIN_NAMES,
- PROC_NET_DN_RAW,
- PROC_NET_NETSTAT,
- PROC_NET_IPFW_CHAINS,
- PROC_NET_IPFW_CHAIN_NAMES,
- PROC_NET_AT_AARP,
- PROC_NET_BRIDGE,
PROC_NET_LAST
};
PROC_MCA_LAST = (PROC_MCA_SLOT + 8)
};
-enum bus_directory_inos {
- PROC_BUS_PCI = PROC_MCA_LAST,
- PROC_BUS_PCI_DEVICES,
- PROC_BUS_ZORRO,
- PROC_BUS_ZORRO_DEVICES,
- PROC_BUS_ECARD_DEVICES,
- PROC_BUS_NUBUS,
- PROC_BUS_NUBUS_DEVICES,
- PROC_BUS_LAST
-};
-
-enum fs_directory_inos {
- PROC_FS_CODA = PROC_BUS_LAST,
- PROC_FS_LAST
-};
-
-enum fs_coda_directory_inos {
- PROC_VFS_STATS = PROC_FS_LAST,
- PROC_UPCALL_STATS,
- PROC_PERMISSION_STATS,
- PROC_CACHE_INV_STATS,
- PROC_CODA_FS_LAST
-};
-
-enum sysvipc_directory_inos {
- PROC_SYSVIPC_SHM = PROC_CODA_FS_LAST,
- PROC_SYSVIPC_SEM,
- PROC_SYSVIPC_MSG
-};
-
/* Finally, the dynamically allocatable proc entries are reserved: */
#define PROC_DYNAMIC_FIRST 4096
* fill in file type/protection/owner information specific to the
* particular /proc file.
*/
+
+typedef int (read_proc_t)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+typedef int (write_proc_t)(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+typedef int (get_info_t)(char *, char **, off_t, int, int);
+
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
gid_t gid;
unsigned long size;
struct inode_operations * ops;
- int (*get_info)(char *, char **, off_t, int, int);
+ get_info_t *get_info;
void (*fill_inode)(struct inode *, int);
struct proc_dir_entry *next, *parent, *subdir;
void *data;
- int (*read_proc)(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- int (*write_proc)(struct file *file, const char *buffer,
- unsigned long count, void *data);
+ read_proc_t *read_proc;
+ write_proc_t *write_proc;
int (*readlink_proc)(struct proc_dir_entry *de, char *page);
unsigned int count; /* use count */
int deleted; /* delete flag */
};
-typedef int (read_proc_t)(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-typedef int (write_proc_t)(struct file *file, const char *buffer,
- unsigned long count, void *data);
-
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry proc_root;
-extern struct proc_dir_entry proc_root_fs;
+extern struct proc_dir_entry *proc_root_fs;
extern struct proc_dir_entry *proc_net;
extern struct proc_dir_entry *proc_scsi;
extern struct proc_dir_entry proc_sys;
extern struct proc_dir_entry proc_openprom;
extern struct proc_dir_entry proc_pid;
extern struct proc_dir_entry proc_pid_fd;
-extern struct proc_dir_entry proc_mca;
+extern struct proc_dir_entry *proc_mca;
extern struct proc_dir_entry *proc_bus;
extern struct proc_dir_entry *proc_sysvipc;
-extern struct proc_dir_entry proc_root_driver;
+extern struct proc_dir_entry *proc_root_driver;
extern struct inode_operations proc_scsi_inode_operations;
extern void proc_root_init(void);
extern void proc_base_init(void);
+extern void proc_misc_init(void);
extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
extern int proc_unregister(struct proc_dir_entry *, int);
-/*
- * generic.c
- */
extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
- struct proc_dir_entry *parent);
+ struct proc_dir_entry *parent);
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
-
-/*
- * inlined /proc helper functions
- */
-
-static inline int proc_net_register(struct proc_dir_entry * x)
-{
- return proc_register(proc_net, x);
-}
-
-static inline int proc_net_unregister(int x)
-{
- return proc_unregister(proc_net, x);
-}
-
-static inline int proc_scsi_register(struct proc_dir_entry *driver,
+extern inline int proc_scsi_register(struct proc_dir_entry *driver,
struct proc_dir_entry *x)
{
x->ops = &proc_scsi_inode_operations;
}
}
-static inline int proc_scsi_unregister(struct proc_dir_entry *driver, int x)
+extern inline int proc_scsi_unregister(struct proc_dir_entry *driver, int x)
{
extern void scsi_init_free(char *ptr, unsigned int size);
{
struct proc_dir_entry *p;
- p = proc_root_driver.subdir;
+ p = proc_root_driver->subdir;
while (p != NULL) {
if (strcmp (p->name, module_name) == 0)
return p;
*/
extern inline int proc_driver_unregister(const char *module_name)
{
- remove_proc_entry (module_name, &proc_root_driver);
+ remove_proc_entry (module_name, proc_root_driver);
return 0;
}
{
struct proc_dir_entry *p;
- p = create_proc_entry (module_name, S_IFDIR, &proc_root_driver);
+ p = create_proc_entry (module_name, S_IFDIR, proc_root_driver);
return (p == NULL) ? -1 : 0;
}
extern struct inode_operations proc_dir_inode_operations;
extern struct inode_operations proc_file_inode_operations;
-extern struct inode_operations proc_net_inode_operations;
extern struct inode_operations proc_netdir_inode_operations;
extern struct inode_operations proc_openprom_inode_operations;
extern struct inode_operations proc_mem_inode_operations;
*/
extern void proc_device_tree_init(void);
+extern inline struct proc_dir_entry *create_proc_read_entry(const char *name,
+ mode_t mode, struct proc_dir_entry *base,
+ read_proc_t *read_proc, void * data)
+{
+ struct proc_dir_entry *res=create_proc_entry(name,mode,base);
+ if (res) {
+ res->read_proc=read_proc;
+ res->data=data;
+ }
+ return res;
+}
+
+extern inline struct proc_dir_entry *create_proc_info_entry(const char *name,
+ mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
+{
+ struct proc_dir_entry *res=create_proc_entry(name,mode,base);
+ if (res) res->get_info=get_info;
+ return res;
+}
+
+extern inline struct proc_dir_entry *proc_net_create(const char *name,
+ mode_t mode, get_info_t *get_info)
+{
+ return create_proc_info_entry(name,mode,proc_net,get_info);
+}
+
+extern inline void proc_net_remove(const char *name)
+{
+ remove_proc_entry(name,proc_net);
+}
+
+extern inline int proc_net_register(struct proc_dir_entry * x)
+{
+ return proc_register(proc_net, x);
+}
+
+extern inline int proc_net_unregister(int x)
+{
+ return proc_unregister(proc_net, x);
+}
+
#else
extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; }
extern inline int proc_unregister(struct proc_dir_entry *a, int b) { return 0; }
-extern inline int proc_net_register(struct proc_dir_entry *a) { return 0; }
+extern inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode,
+ get_info_t *get_info) {return NULL;}
+extern inline void proc_net_remove(const char *name) {}
+extern inline int proc_net_register(struct proc_dir_entry * x) { return 0; }
extern inline int proc_net_unregister(int x) { return 0; }
extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) { return 0; }
extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x) { return 0; }
-extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
- struct proc_dir_entry *parent)
-{
- return NULL;
-}
+extern inline struct proc_dir_entry *create_proc_entry(const char *name,
+ mode_t mode, struct proc_dir_entry *parent) { return NULL; }
extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
+extern inline struct proc_dir_entry *create_proc_read_entry(const char *name,
+ mode_t mode, struct proc_dir_entry *base,
+ int (*read_proc)(char *, char **, off_t, int, int *, void *),
+ void * data) { return NULL; }
+extern inline struct proc_dir_entry *create_proc_info_entry(const char *name,
+ mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
+ { return NULL; }
+
extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
int semaem;
};
-#define SEMMNI 128 /* ? max # of semaphore identifiers */
-#define SEMMSL 32 /* <= 512 max num of semaphores per id */
-#define SEMMNS (SEMMNI*SEMMSL) /* ? max # of semaphores in system */
-#define SEMOPM 32 /* ~ 100 max num of ops per semop call */
-#define SEMVMX 32767 /* semaphore maximum value */
+#define SEMMNI 128 /* <= 32767 max # of semaphore identifiers */
+#define SEMMSL 250 /* <= 512 max num of semaphores per id */
+#define SEMMNS (SEMMNI*SEMMSL) /* <= MAX_INT max # of semaphores in system */
+#define SEMOPM 32 /* <= 160 max num of ops per semop call */
+#define SEMVMX 32767 /* <= 32767 semaphore maximum value */
/* unused */
#define SEMUME SEMOPM /* max num of undo entries per process */
int sempid; /* pid of last operation */
};
-/* One queue for each semaphore set in the system. */
+/* One queue for each sleeping process in the system. */
struct sem_queue {
struct sem_queue * next; /* next entry in the queue */
struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */
- wait_queue_head_t sleeper; /* sleeping process */
+ struct task_struct* sleeper; /* this process */
struct sem_undo * undo; /* undo structure */
int pid; /* process id of requesting process */
int status; /* completion status of operation */
struct semid_ds * sma; /* semaphore array for operations */
+ int id; /* internal sem id */
struct sembuf * sops; /* array of pending operations */
int nsops; /* number of operations */
int alter; /* operation will alter semaphore */
#define ASYNC_CLOSING_WAIT_INF 0
#define ASYNC_CLOSING_WAIT_NONE 65535
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+ __u32 cts, dsr, rng, dcd, tx, rx;
+ __u32 frame, parity, overrun, brk;
+ __u32 buf_overrun;
+};
+
/*
* These are the supported serial types.
*/
#include <linux/tqueue.h>
#include <linux/wait.h>
-/*
- * Counters of the input lines (CTS, DSR, RI, CD) interrupts
- */
-struct async_icount {
- __u32 cts, dsr, rng, dcd, tx, rx;
- __u32 frame, parity, overrun, brk;
- __u32 buf_overrun;
-};
struct serial_state {
int magic;
#define SERIAL_MAGIC 0x5301
#define SSTATE_MAGIC 0x5302
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
/*
* Events are used to schedule things to happen at timer-interrupt
asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr);
asmlinkage long sys_shmdt (char *shmaddr);
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
-extern void shm_unuse(pte_t entry, struct page *page);
+extern void shm_unuse(swp_entry_t entry, struct page *page);
#endif /* __KERNEL__ */
/* linux/mm/page_io.c */
extern void rw_swap_page(int, struct page *, int);
-extern void rw_swap_page_nolock(int, pte_t, char *, int);
+extern void rw_swap_page_nolock(int, swp_entry_t, char *, int);
/* linux/mm/page_alloc.c */
/* linux/mm/swap_state.c */
extern void show_swap_cache_info(void);
-extern void add_to_swap_cache(struct page *, pte_t);
-extern int swap_duplicate(pte_t);
+extern void add_to_swap_cache(struct page *, swp_entry_t);
+extern int swap_duplicate(swp_entry_t);
extern int swap_check_entry(unsigned long);
-struct page * lookup_swap_cache(pte_t);
-extern struct page * read_swap_cache_async(pte_t, int);
+extern struct page * lookup_swap_cache(swp_entry_t);
+extern struct page * read_swap_cache_async(swp_entry_t, int);
#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
extern int swap_count(struct page *);
-extern pte_t acquire_swap_entry(struct page *page);
+extern swp_entry_t acquire_swap_entry(struct page *page);
/*
* Make these inline later once they are working properly.
extern unsigned int nr_swapfiles;
extern struct swap_info_struct swap_info[];
extern int is_swap_partition(kdev_t);
-void si_swapinfo(struct sysinfo *);
-pte_t get_swap_page(void);
-extern void swap_free(pte_t);
+extern void si_swapinfo(struct sysinfo *);
+extern swp_entry_t get_swap_page(void);
+extern void swap_free(swp_entry_t);
struct swap_list_t {
int head; /* head of priority-ordered swapfile list */
int next; /* swapfile to be used next */
#define vma_set_inode(v,i) v->vm_inode = i
#define vma_get_flags(v) v->vm_flags
-#define vma_get_offset(v) v->vm_offset
+#define vma_get_pgoff(v) v->vm_pgoff
#define vma_get_start(v) v->vm_start
#define vma_get_end(v) v->vm_end
#define vma_get_page_prot(v) v->vm_page_prot
void __init msg_init (void)
{
int id;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
for (id = 0; id < MSGMNI; id++) {
msg_que[id].lock = SPIN_LOCK_UNLOCKED;
msg_que[id].q = NULL;
}
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("sysvipc/msg", 0, 0);
- ent->read_proc = sysvipc_msg_read_proc;
+ create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);
#endif
}
* array we do the same as before.
*
* /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
+ *
+ * SMP-threaded (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
*/
#include <linux/config.h>
#include <linux/malloc.h>
-#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
#endif
-static struct semid_ds *semary[SEMMNI];
-static int used_sems = 0, used_semids = 0;
-static DECLARE_WAIT_QUEUE_HEAD(sem_lock);
+struct semid_ary
+{
+ spinlock_t lock;
+ struct semid_ds* s;
+};
+
+static struct semid_ary semary[SEMMNI];
+
+static DECLARE_MUTEX(sem_lock);
static int max_semid = 0;
+static int used_sems = 0;
+static int used_semids = 0;
static unsigned short sem_seq = 0;
+/* anti-deadlock ordering:
+ * sem_lock < semary[].lock
+ * linked list protection:
+ * sem_undo.id_next,
+ * semid_ds.sem_pending{,last},
+ * semid_ds.sem_undo: semary[].lock for read/write
+ * sem_undo.proc_next: only "current" is allowed to read/write that field.
+ *
+ */
+
void __init sem_init (void)
{
int i;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
- init_waitqueue_head(&sem_lock);
used_sems = used_semids = max_semid = sem_seq = 0;
- for (i = 0; i < SEMMNI; i++)
- semary[i] = (struct semid_ds *) IPC_UNUSED;
+ for (i = 0; i < SEMMNI; i++) {
+ semary[i].lock = SPIN_LOCK_UNLOCKED;
+ semary[i].s = NULL;
+ }
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("sysvipc/sem", 0, 0);
- ent->read_proc = sysvipc_sem_read_proc;
+ create_proc_read_entry("sysvipc/sem", 0, 0, sysvipc_sem_read_proc, NULL);
#endif
return;
}
struct semid_ds *sma;
for (id = 0; id <= max_semid; id++) {
- while ((sma = semary[id]) == IPC_NOID)
- interruptible_sleep_on (&sem_lock);
- if (sma == IPC_UNUSED)
+ sma = semary[id].s;
+ if(sma==NULL)
continue;
+
if (key == sma->sem_perm.key)
return id;
}
return -EINVAL;
if (used_sems + nsems > SEMMNS)
return -ENOSPC;
- for (id = 0; id < SEMMNI; id++)
- if (semary[id] == IPC_UNUSED) {
- semary[id] = (struct semid_ds *) IPC_NOID;
+ for (id = 0; id < SEMMNI; id++) {
+ if(semary[id].s == NULL)
goto found;
- }
+ }
return -ENOSPC;
found:
size = sizeof (*sma) + nsems * sizeof (struct sem);
used_sems += nsems;
sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);
if (!sma) {
- semary[id] = (struct semid_ds *) IPC_UNUSED;
used_sems -= nsems;
- wake_up (&sem_lock);
return -ENOMEM;
}
memset (sma, 0, size);
ipcp->key = key;
ipcp->cuid = ipcp->uid = current->euid;
ipcp->gid = ipcp->cgid = current->egid;
- sma->sem_perm.seq = sem_seq;
+ /* sma->sem_perm.seq*MSGMNI must be a positive integer.
+ * this limits MSGMNI to 32768
+ */
+ sma->sem_perm.seq = sem_seq++;
/* sma->sem_pending = NULL; */
sma->sem_pending_last = &sma->sem_pending;
/* sma->undo = NULL; */
if (id > max_semid)
max_semid = id;
used_semids++;
- semary[id] = sma;
- wake_up (&sem_lock);
+ spin_lock(&semary[id].lock);
+ semary[id].s = sma;
+ spin_unlock(&semary[id].lock);
return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
}
int id, err = -EINVAL;
struct semid_ds *sma;
- lock_kernel();
if (nsems < 0 || nsems > SEMMSL)
- goto out;
+ return -EINVAL;
+ down(&sem_lock);
+
if (key == IPC_PRIVATE) {
err = newary(key, nsems, semflg);
} else if ((id = findkey (key)) == -1) { /* key not used */
} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
err = -EEXIST;
} else {
- sma = semary[id];
+ sma = semary[id].s;
if (nsems > sma->sem_nsems)
err = -EINVAL;
else if (ipcperms(&sma->sem_perm, semflg))
else
err = (int) sma->sem_perm.seq * SEMMNI + id;
}
-out:
- unlock_kernel();
+
+ up(&sem_lock);
return err;
}
* insert new queue elements at the tail sma->sem_pending_last.
*/
static inline void append_to_queue (struct semid_ds * sma,
- struct sem_queue * q)
+ struct sem_queue * q)
{
*(q->prev = sma->sem_pending_last) = q;
*(sma->sem_pending_last = &q->next) = NULL;
}
static inline void prepend_to_queue (struct semid_ds * sma,
- struct sem_queue * q)
+ struct sem_queue * q)
{
- q->next = sma->sem_pending;
- *(q->prev = &sma->sem_pending) = q;
- if (q->next)
- q->next->prev = &q->next;
- else /* sma->sem_pending_last == &sma->sem_pending */
- sma->sem_pending_last = &q->next;
+ q->next = sma->sem_pending;
+ *(q->prev = &sma->sem_pending) = q;
+ if (q->next)
+ q->next->prev = &q->next;
+ else /* sma->sem_pending_last == &sma->sem_pending */
+ sma->sem_pending_last = &q->next;
}
static inline void remove_from_queue (struct semid_ds * sma,
- struct sem_queue * q)
+ struct sem_queue * q)
{
*(q->prev) = q->next;
if (q->next)
*/
static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,
- int nsops, struct sem_undo *un, int pid,
- int do_undo)
+ int nsops, struct sem_undo *un, int pid,
+ int do_undo)
{
int result, sem_op;
struct sembuf *sop;
goto out_of_range;
}
- if (do_undo)
- {
- sop--;
- result = 0;
- goto undo;
- }
+ if (do_undo)
+ {
+ sop--;
+ result = 0;
+ goto undo;
+ }
sma->sem_otime = CURRENT_TIME;
return 0;
result = 1;
undo:
- while (sop >= sops) {
+ while (sop >= sops) {
curr = sma->sem_base + sop->sem_num;
curr->semval -= sop->sem_op;
curr->sempid >>= 16;
int error;
struct sem_queue * q;
- for (q = sma->sem_pending; q; q = q->next) {
-
- if (q->status == 1)
- return; /* wait for other process */
-
- error = try_atomic_semop(sma, q->sops, q->nsops,
- q->undo, q->pid, q->alter);
-
- /* Does q->sleeper still need to sleep? */
- if (error <= 0) {
- /* Found one, wake it up */
- wake_up_interruptible(&q->sleeper);
- if (error == 0 && q->alter) {
- /* if q-> alter let it self try */
- q->status = 1;
- return;
- }
- q->status = error;
- remove_from_queue(sma,q);
- }
- }
+ for (q = sma->sem_pending; q; q = q->next) {
+
+ if (q->status == 1)
+ return; /* wait for other process */
+
+ error = try_atomic_semop(sma, q->sops, q->nsops,
+ q->undo, q->pid, q->alter);
+
+ /* Does q->sleeper still need to sleep? */
+ if (error <= 0) {
+ /* Found one, wake it up */
+ wake_up_process(q->sleeper);
+ if (error == 0 && q->alter) {
+ /* if q-> alter let it self try */
+ q->status = 1;
+ return;
+ }
+ q->status = error;
+ remove_from_queue(sma,q);
+ }
+ }
}
/* The following counts are associated to each semaphore:
/* Free a semaphore set. */
static void freeary (int id)
{
- struct semid_ds *sma = semary[id];
+ struct semid_ds *sma;
struct sem_undo *un;
struct sem_queue *q;
- /* Invalidate this semaphore set */
- sma->sem_perm.seq++;
- sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
+ /* we own both locks, noone can get in */
+ sma = semary[id].s;
+ semary[id].s = NULL;
+
used_sems -= sma->sem_nsems;
if (id == max_semid)
- while (max_semid && (semary[--max_semid] == IPC_UNUSED));
- semary[id] = (struct semid_ds *) IPC_UNUSED;
+ while (max_semid && (semary[--max_semid].s == NULL));
used_semids--;
/* Invalidate the existing undo structures for this semaphore set.
- * (They will be freed without any further action in sem_exit().)
+ * (They will be freed without any further action in sem_exit()
+ * or during the next semop.)
*/
for (un = sma->undo; un; un = un->id_next)
un->semid = -1;
for (q = sma->sem_pending; q; q = q->next) {
q->status = -EIDRM;
q->prev = NULL;
- wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
+ wake_up_process(q->sleeper); /* doesn't sleep */
}
kfree(sma);
}
-asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
+int semctl_nolock(int semid, int semnum, int cmd, union semun arg)
{
- struct semid_ds *buf = NULL;
- struct semid_ds tbuf;
- int i, id, val = 0;
- struct semid_ds *sma;
- struct ipc_perm *ipcp;
- struct sem *curr = NULL;
- struct sem_undo *un;
- unsigned int nsems;
- ushort *array = NULL;
- ushort sem_io[SEMMSL];
int err = -EINVAL;
+ int lid = semid % SEMMNI;
- lock_kernel();
- if (semid < 0 || semnum < 0 || cmd < 0)
- goto out;
-
- switch (cmd) {
+ switch(cmd) {
case IPC_INFO:
case SEM_INFO:
{
- struct seminfo seminfo, *tmp = arg.__buf;
+ struct seminfo seminfo;
+
seminfo.semmni = SEMMNI;
seminfo.semmns = SEMMNS;
seminfo.semmsl = SEMMSL;
seminfo.semusz = SEMUSZ;
seminfo.semaem = SEMAEM;
if (cmd == SEM_INFO) {
+ down(&sem_lock);
seminfo.semusz = used_semids;
seminfo.semaem = used_sems;
+ up(&sem_lock);
}
- err = -EFAULT;
- if (copy_to_user (tmp, &seminfo, sizeof(struct seminfo)))
- goto out;
- err = max_semid;
- goto out;
+ if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
+ return -EFAULT;
+ return max_semid;
}
-
case SEM_STAT:
- buf = arg.buf;
- err = -EINVAL;
+ {
+ struct semid_ds *sma;
+ struct semid_ds tbuf;
+ int id;
+
if (semid > max_semid)
- goto out;
- sma = semary[semid];
- if (sma == IPC_UNUSED || sma == IPC_NOID)
- goto out;
+ return -EINVAL;
+
+ spin_lock(&semary[lid].lock);
+ err = -EINVAL;
+ sma = semary[semid].s;
+ if (sma == NULL)
+ goto out_unlock;
err = -EACCES;
if (ipcperms (&sma->sem_perm, S_IRUGO))
- goto out;
+ goto out_unlock;
id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
+ memset(&tbuf,0,sizeof(tbuf));
tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
- err = -EFAULT;
- if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0)
- err = id;
- goto out;
+ spin_unlock(&semary[lid].lock);
+ if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
+ return -EFAULT;
+ return id;
}
+ default:
+ return -EINVAL;
+ }
+ return err;
+out_unlock:
+ spin_unlock(&semary[lid].lock);
+ return err;
+}
- id = (unsigned int) semid % SEMMNI;
- sma = semary [id];
- err = -EINVAL;
- if (sma == IPC_UNUSED || sma == IPC_NOID)
- goto out;
- ipcp = &sma->sem_perm;
- nsems = sma->sem_nsems;
- err = -EIDRM;
+int semctl_locked_unlock(int semid, int semnum, int cmd, union semun arg)
+{
+ struct semid_ds *sma;
+ struct semid_ds tbuf;
+ int err;
+ int lid = semid % SEMMNI;
+
+ sma = semary[lid].s;
+ err=-EINVAL;
+ if (sma == NULL)
+ goto out_unlock;
+ err=-EIDRM;
if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- goto out;
+ goto out_unlock;
+ err = -EACCES;
+ if (ipcperms(&sma->sem_perm, S_IRUGO))
+ goto out_unlock;
+
switch (cmd) {
- case GETVAL:
- case GETPID:
- case GETNCNT:
- case GETZCNT:
- case SETVAL:
+ case GETALL:
+ {
+ ushort *array = arg.array;
+ ushort sem_io[SEMMSL];
+ int i;
+ int nsems = sma->sem_nsems;
+
+ for (i = 0; i < sma->sem_nsems; i++)
+ sem_io[i] = sma->sem_base[i].semval;
+ spin_unlock(&semary[lid].lock);
+ if (copy_to_user (array, sem_io, nsems*sizeof(ushort)))
+ return -EFAULT;
+ return 0;
+ }
+ case IPC_STAT:
+ memset(&tbuf,0,sizeof(tbuf));
+ tbuf.sem_perm = sma->sem_perm;
+ tbuf.sem_otime = sma->sem_otime;
+ tbuf.sem_ctime = sma->sem_ctime;
+ tbuf.sem_nsems = sma->sem_nsems;
+ spin_unlock(&semary[lid].lock);
+ if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
+ return -EFAULT;
+ return 0;
+default:
err = -EINVAL;
- if (semnum >= nsems)
- goto out;
- curr = &sma->sem_base[semnum];
- break;
}
+out_unlock:
+ spin_unlock(&semary[lid].lock);
+ return err;
+
+}
+
+int semctl_locked(int semid, int semnum, int cmd, union semun arg)
+{
+ struct semid_ds *sma;
+ int lid = semid % SEMMNI;
+ struct sem *curr;
+
+ sma = semary[lid].s;
+ if (sma == NULL)
+ return -EINVAL;
+
+ if (ipcperms (&sma->sem_perm, (cmd==SETVAL)?S_IWUGO:S_IRUGO))
+ return -EACCES;
+
+ if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
+ return -EIDRM;
+
+ if (semnum >= sma->sem_nsems)
+ return -EINVAL;
+
+ curr = &sma->sem_base[semnum];
switch (cmd) {
case GETVAL:
+ return curr->semval;
case GETPID:
+ return curr->sempid & 0xffff;
case GETNCNT:
+ return count_semncnt(sma,semnum);
case GETZCNT:
- case GETALL:
- err = -EACCES;
- if (ipcperms (ipcp, S_IRUGO))
- goto out;
- switch (cmd) {
- case GETVAL : err = curr->semval; goto out;
- case GETPID : err = curr->sempid & 0xffff; goto out;
- case GETNCNT: err = count_semncnt(sma,semnum); goto out;
- case GETZCNT: err = count_semzcnt(sma,semnum); goto out;
- case GETALL:
- array = arg.array;
- break;
- }
- break;
+ return count_semzcnt(sma,semnum);
case SETVAL:
- val = arg.val;
- err = -ERANGE;
+ {
+ int val = arg.val;
+ struct sem_undo *un;
if (val > SEMVMX || val < 0)
- goto out;
- break;
- case IPC_RMID:
- if (current->euid == ipcp->cuid ||
- current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {
- freeary (id);
- err = 0;
- goto out;
- }
- err = -EPERM;
- goto out;
- case SETALL: /* arg is a pointer to an array of ushort */
- array = arg.array;
- err = -EFAULT;
- if (copy_from_user (sem_io, array, nsems*sizeof(ushort)))
- goto out;
- err = 0;
- for (i = 0; i < nsems; i++)
- if (sem_io[i] > SEMVMX) {
- err = -ERANGE;
- goto out;
- }
- break;
- case IPC_STAT:
- buf = arg.buf;
- break;
- case IPC_SET:
- buf = arg.buf;
- err = copy_from_user (&tbuf, buf, sizeof (*buf));
- if (err)
- err = -EFAULT;
- break;
- }
-
- err = -EIDRM;
- if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
- goto out;
- if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
- goto out;
+ return -ERANGE;
- switch (cmd) {
- case GETALL:
- err = -EACCES;
- if (ipcperms (ipcp, S_IRUGO))
- goto out;
- for (i = 0; i < sma->sem_nsems; i++)
- sem_io[i] = sma->sem_base[i].semval;
- if (copy_to_user (array, sem_io, nsems*sizeof(ushort)))
- err = -EFAULT;
- break;
- case SETVAL:
- err = -EACCES;
- if (ipcperms (ipcp, S_IWUGO))
- goto out;
for (un = sma->undo; un; un = un->id_next)
un->semadj[semnum] = 0;
curr->semval = val;
sma->sem_ctime = CURRENT_TIME;
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
- break;
- case IPC_SET:
- if (current->euid == ipcp->cuid ||
- current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) {
- ipcp->uid = tbuf.sem_perm.uid;
- ipcp->gid = tbuf.sem_perm.gid;
- ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
- | (tbuf.sem_perm.mode & S_IRWXUGO);
- sma->sem_ctime = CURRENT_TIME;
- err = 0;
- goto out;
- }
- err = -EPERM;
- goto out;
- case IPC_STAT:
- err = -EACCES;
- if (ipcperms (ipcp, S_IRUGO))
- goto out;
- tbuf.sem_perm = sma->sem_perm;
- tbuf.sem_otime = sma->sem_otime;
- tbuf.sem_ctime = sma->sem_ctime;
- tbuf.sem_nsems = sma->sem_nsems;
- if (copy_to_user (buf, &tbuf, sizeof(*buf)))
- err = -EFAULT;
- break;
- case SETALL:
- err = -EACCES;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+int semctl_down(int semid, int semnum, int cmd, union semun arg)
+{
+ struct semid_ds *sma;
+ int err;
+ int lid = semid % SEMMNI;
+ struct semid_ds tbuf;
+ struct ipc_perm *ipcp;
+
+ if(cmd == IPC_SET) {
+ if(copy_from_user (&tbuf, arg.buf, sizeof (tbuf)))
+ return -EFAULT;
+ }
+ spin_lock(&semary[lid].lock);
+ sma = semary[lid].s;
+ err=-EINVAL;
+ if (sma == NULL)
+ goto out_unlock;
+ ipcp = &sma->sem_perm;
+
+ if(cmd == SETALL) {
+ int i;
+ struct sem_undo *un;
+ unsigned int nsems;
+ ushort sem_io[SEMMSL];
+ /* SETALL doesn't belong into this
+ * group, but I need the semaphore
+ * for atomically reading nsems
+ * and changing the semaphore values
+ */
+ err=-EACCES;
if (ipcperms (ipcp, S_IWUGO))
- goto out;
+ goto out_unlock;
+ nsems=sma->sem_nsems;
+ spin_unlock(&semary[lid].lock);
+
+ if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort)))
+ return -EFAULT;
+ for (i = 0; i < nsems; i++) {
+ if (sem_io[i] > SEMVMX) {
+ return -ERANGE;
+ }
+ }
+ /* we still own sem_lock, ie neither ownership
+ * nor permissions of the sem array could
+ * have changed. Just continue.
+ */
+ spin_lock(&semary[lid].lock);
for (i = 0; i < nsems; i++)
sma->sem_base[i].semval = sem_io[i];
for (un = sma->undo; un; un = un->id_next)
sma->sem_ctime = CURRENT_TIME;
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
+ err = 0;
+ goto out_unlock;
+ }
+
+ if (current->euid != ipcp->cuid &&
+ current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
+ err=-EPERM;
+ goto out_unlock;
+ }
+
+ if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) {
+ err=-EIDRM;
+ goto out_unlock;
+ }
+ switch(cmd){
+ case IPC_RMID:
+ freeary(lid);
+ err = 0;
+ break;
+ case IPC_SET:
+ ipcp->uid = tbuf.sem_perm.uid;
+ ipcp->gid = tbuf.sem_perm.gid;
+ ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
+ | (tbuf.sem_perm.mode & S_IRWXUGO);
+ sma->sem_ctime = CURRENT_TIME;
+ err = 0;
break;
default:
err = -EINVAL;
- goto out;
}
- err = 0;
-out:
- unlock_kernel();
+
+out_unlock:
+ spin_unlock(&semary[lid].lock);
return err;
}
+asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
+{
+ int lid; /* lock id */
+ int err = -EINVAL;
+
+ if (semid < 0 || semnum < 0 || cmd < 0)
+ return -EINVAL;
+
+ lid = semid % SEMMNI;
+
+ switch(cmd) {
+ case IPC_INFO:
+ case SEM_INFO:
+ case SEM_STAT:
+ err = semctl_nolock(semid,semnum,cmd,arg);
+ return err;
+ case GETALL:
+ case IPC_STAT:
+ spin_lock(&semary[lid].lock);
+ err = semctl_locked_unlock(semid,semnum,cmd,arg);
+ return err;
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case SETVAL:
+ spin_lock(&semary[lid].lock);
+ err= semctl_locked(semid,semnum,cmd,arg);
+ spin_unlock(&semary[lid].lock);
+ return err;
+ case SETALL:
+ case IPC_RMID:
+ case IPC_SET:
+ down(&sem_lock);
+ err= semctl_down(semid,semnum,cmd,arg);
+ up(&sem_lock);
+ return err;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct sem_undo* freeundos(struct semid_ds *sma, struct sem_undo* un)
+{
+ struct sem_undo* u;
+ struct sem_undo** up;
+
+ for(up = ¤t->semundo;(u=*up);up=&u->proc_next) {
+ if(un==u) {
+ un=u->proc_next;
+ *up=un;
+ kfree(u);
+ return un;
+ }
+ }
+ printk ("freeundos undo list error id=%d\n", un->semid);
+ return un->proc_next;
+}
+
+static int alloc_undo(struct semid_ds *sma, struct sem_undo** unp, int semid, int alter)
+{
+ int size;
+ struct sem_undo *un;
+ int error,id;
+ id = (unsigned int) semid % SEMMNI;
+ size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
+ spin_unlock(&semary[id].lock);
+
+ un = (struct sem_undo *) kmalloc(size, GFP_KERNEL);
+ spin_lock(&semary[id].lock);
+ if (!un) {
+ return -ENOMEM;
+ }
+ sma = semary[id].s;
+ error = -EIDRM;
+ if (sma == NULL)
+ goto out;
+ if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
+ goto out;
+ if (size != sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems)
+ goto out;
+
+ error = -EACCES;
+ if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
+ goto out;
+ memset(un, 0, size);
+ un->semadj = (short *) &un[1];
+ un->semid = semid;
+ un->proc_next = current->semundo;
+ current->semundo = un;
+ un->id_next = sma->undo;
+ sma->undo = un;
+ *unp = un;
+ return 0;
+out:
+ kfree(un);
+ return error;
+}
+
asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
{
- int id, size, error = -EINVAL;
+ int id, error = -EINVAL;
struct semid_ds *sma;
struct sembuf sops[SEMOPM], *sop;
struct sem_undo *un;
int undos = 0, decrease = 0, alter = 0;
struct sem_queue queue;
- lock_kernel();
if (nsops < 1 || semid < 0)
- goto out;
- error = -E2BIG;
+ return -EINVAL;
+
if (nsops > SEMOPM)
- goto out;
- error = -EFAULT;
+ return -E2BIG;
if (copy_from_user (sops, tsops, nsops * sizeof(*tsops)))
- goto out;
+ return -EFAULT;
+
id = (unsigned int) semid % SEMMNI;
+ spin_lock(&semary[id].lock);
+ sma = semary[id].s;
error = -EINVAL;
- if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
+ if (sma == NULL)
goto out;
error = -EIDRM;
if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
goto out;
- error = -EFBIG;
+ error = -EFBIG;
for (sop = sops; sop < sops + nsops; sop++) {
if (sop->sem_num >= sma->sem_nsems)
goto out;
undos++;
if (sop->sem_op < 0)
decrease = 1;
- if (sop->sem_op > 0)
- alter = 1;
+ if (sop->sem_op > 0)
+ alter = 1;
}
- alter |= decrease;
+ alter |= decrease;
error = -EACCES;
if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
/* Make sure we have an undo structure
* for this process and this semaphore set.
*/
- for (un = current->semundo; un; un = un->proc_next)
- if (un->semid == semid)
+ un=current->semundo;
+ while(un != NULL) {
+ if(un->semid==semid)
break;
+ if(un->semid==-1)
+ un=freeundos(sma,un);
+ else
+ un=un->proc_next;
+ }
if (!un) {
- size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
- un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);
- if (!un) {
- error = -ENOMEM;
+ error = alloc_undo(sma,&un,semid,alter);
+ if(error<0)
goto out;
- }
- memset(un, 0, size);
- un->semadj = (short *) &un[1];
- un->semid = semid;
- un->proc_next = current->semundo;
- current->semundo = un;
- un->id_next = sma->undo;
- sma->undo = un;
}
} else
un = NULL;
error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0);
if (error <= 0)
- goto update;
-
- /* We need to sleep on this operation, so we put the current
- * task into the pending queue and go to sleep.
- */
-
- queue.sma = sma;
- queue.sops = sops;
- queue.nsops = nsops;
- queue.undo = un;
- queue.pid = current->pid;
- queue.alter = decrease;
- current->semsleeping = &queue;
- if (alter)
- append_to_queue(sma ,&queue);
- else
- prepend_to_queue(sma ,&queue);
-
- for (;;) {
- queue.status = -EINTR;
- init_waitqueue_head(&queue.sleeper);
- interruptible_sleep_on(&queue.sleeper);
-
- /*
- * If queue.status == 1 we where woken up and
- * have to retry else we simply return.
- * If an interrupt occurred we have to clean up the
- * queue
- *
- */
- if (queue.status == 1)
- {
- error = try_atomic_semop (sma, sops, nsops, un,
- current->pid,0);
- if (error <= 0)
- break;
- } else {
- error = queue.status;;
- if (queue.prev) /* got Interrupt */
- break;
- /* Everything done by update_queue */
- current->semsleeping = NULL;
- goto out;
- }
- }
- current->semsleeping = NULL;
- remove_from_queue(sma,&queue);
+ goto update;
+
+ /* We need to sleep on this operation, so we put the current
+ * task into the pending queue and go to sleep.
+ */
+
+ queue.sma = sma;
+ queue.sops = sops;
+ queue.nsops = nsops;
+ queue.undo = un;
+ queue.pid = current->pid;
+ queue.alter = decrease;
+ queue.id = id;
+ current->semsleeping = &queue;
+ if (alter)
+ append_to_queue(sma ,&queue);
+ else
+ prepend_to_queue(sma ,&queue);
+
+ for (;;) {
+ queue.status = -EINTR;
+ queue.sleeper = current;
+ current->state = TASK_INTERRUPTIBLE;
+ spin_unlock(&semary[id].lock);
+
+ schedule();
+
+ /* we can lock the semary even if it was
+ * deleted.
+ */
+ spin_lock(&semary[id].lock);
+ /*
+ * If queue.status == 1 we where woken up and
+ * have to retry else we simply return.
+ * If an interrupt occurred we have to clean up the
+ * queue
+ *
+ */
+ if (queue.status == 1)
+ {
+ error = try_atomic_semop (sma, sops, nsops, un,
+ current->pid,0);
+ if (error <= 0)
+ break;
+ } else {
+ error = queue.status;
+ if (queue.prev) /* got Interrupt */
+ break;
+ /* Everything done by update_queue */
+ current->semsleeping = NULL;
+ goto out;
+ }
+ }
+ current->semsleeping = NULL;
+ remove_from_queue(sma,&queue);
update:
- if (alter)
- update_queue (sma);
+ if (alter)
+ update_queue (sma);
out:
- unlock_kernel();
+ spin_unlock(&semary[id].lock);
return error;
}
/* If the current process was sleeping for a semaphore,
* remove it from the queue.
*/
+ /* semsleeping is part of "current", and it
+ * is never modified by another thread.
+ * No synchronization required.
+ */
if ((q = current->semsleeping)) {
+ spin_lock(&semary[current->semsleeping->id].lock);
+
if (q->prev)
remove_from_queue(q->sma,q);
current->semsleeping = NULL;
+ spin_unlock(&semary[current->semsleeping->id].lock);
}
for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
- if (u->semid == -1)
- continue;
- sma = semary[(unsigned int) u->semid % SEMMNI];
- if (sma == IPC_UNUSED || sma == IPC_NOID)
+ int semid = u->semid;
+ int lid;
+ if(semid == -1)
continue;
+ lid = semid % SEMMNI;
+ spin_lock(&semary[lid].lock);
+
+ if (u->semid == -1)
+ goto next_entry;
+
+ sma = semary[lid].s;
+ if (sma == NULL)
+ goto next_entry;
if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
- continue;
+ goto next_entry;
+
/* remove u from the sma->undo list */
for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
if (u == un)
goto found;
}
printk ("sem_exit undo list error id=%d\n", u->semid);
- break;
+ goto next_entry;
found:
*unp = un->id_next;
/* perform adjustments registered in u */
sma->sem_otime = CURRENT_TIME;
/* maybe some queued-up processes were waiting for this */
update_queue(sma);
+next_entry:
+ spin_unlock(&semary[lid].lock);
}
current->semundo = NULL;
}
int i, len = 0;
len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n");
+ down(&sem_lock);
for(i = 0; i < SEMMNI; i++)
- if(semary[i] != IPC_UNUSED) {
+ if(semary[i].s != NULL) {
+ spin_lock(&semary[i].lock);
len += sprintf(buffer + len, "%10d %10d %4o %5u %5u %5u %5u %5u %10lu %10lu\n",
- semary[i]->sem_perm.key,
- semary[i]->sem_perm.seq * SEMMNI + i,
- semary[i]->sem_perm.mode,
- semary[i]->sem_nsems,
- semary[i]->sem_perm.uid,
- semary[i]->sem_perm.gid,
- semary[i]->sem_perm.cuid,
- semary[i]->sem_perm.cgid,
- semary[i]->sem_otime,
- semary[i]->sem_ctime);
+ semary[i].s->sem_perm.key,
+ semary[i].s->sem_perm.seq * SEMMNI + i,
+ semary[i].s->sem_perm.mode,
+ semary[i].s->sem_nsems,
+ semary[i].s->sem_perm.uid,
+ semary[i].s->sem_perm.gid,
+ semary[i].s->sem_perm.cuid,
+ semary[i].s->sem_perm.cgid,
+ semary[i].s->sem_otime,
+ semary[i].s->sem_ctime);
+ spin_unlock(&semary[i].lock);
pos += len;
if(pos < offset) {
}
*eof = 1;
done:
+ up(&sem_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if(len > length)
void __init shm_init (void)
{
int id;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
for (id = 0; id < SHMMNI; id++)
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
init_waitqueue_head(&shm_wait);
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("sysvipc/shm", 0, 0);
- ent->read_proc = sysvipc_shm_read_proc;
+ create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
#endif
return;
}
rss++;
} else {
lock_kernel();
- swap_free(pte);
+ swap_free(pte_to_swp_entry(pte));
unlock_kernel();
swp++;
}
* shmd->vm_end multiple of SHMLBA
* shmd->vm_next next attach for task
* shmd->vm_next_share next attach for segment
- * shmd->vm_offset offset into segment
+ * shmd->vm_pgoff offset into segment (in pages)
* shmd->vm_private_data signature for this attach
*/
| VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
| ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
shmd->vm_file = NULL;
- shmd->vm_offset = 0;
+ shmd->vm_pgoff = 0;
shmd->vm_ops = &shm_vm_ops;
shp->u.shm_nattch++; /* prevent destruction */
for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
shmdnext = shmd->vm_next;
if (shmd->vm_ops == &shm_vm_ops
- && shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
+ && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr)
do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
}
up(¤t->mm->mmap_sem);
struct page * page;
shp = *(struct shmid_kernel **) shmd->vm_private_data;
- idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT;
+ idx = (address - shmd->vm_start) >> PAGE_SHIFT;
+ idx += shmd->vm_pgoff;
spin_lock(&shm_lock);
again:
if (pte_val(pte) != pte_val(shp->shm_pages[idx]))
goto changed;
} else {
- pte_t entry = pte;
+ swp_entry_t entry = pte_to_swp_entry(pte);
spin_unlock(&shm_lock);
page = lookup_swap_cache(entry);
{
pte_t page;
struct shmid_kernel *shp;
- pte_t swap_entry;
+ swp_entry_t swap_entry;
unsigned long id, idx;
int loop = 0;
int counter;
struct page * page_map;
counter = shm_rss >> prio;
+ if (!counter)
+ return 0;
lock_kernel();
- if (!counter || !pte_val(swap_entry = get_swap_page())) {
+ swap_entry = get_swap_page();
+ if (!swap_entry.val) {
unlock_kernel();
return 0;
}
goto check_table;
if (!(page_map = prepare_highmem_swapout(page_map)))
goto check_table;
- shp->shm_pages[idx] = swap_entry;
+ shp->shm_pages[idx] = swp_entry_to_pte(swap_entry);
swap_successes++;
shm_swp++;
shm_rss--;
* Free the swap entry and set the new pte for the shm page.
*/
static void shm_unuse_page(struct shmid_kernel *shp, unsigned long idx,
- pte_t entry, struct page *page)
+ swp_entry_t entry, struct page *page)
{
pte_t pte;
/*
* unuse_shm() search for an eventually swapped out shm page.
*/
-void shm_unuse(pte_t entry, struct page *page)
+void shm_unuse(swp_entry_t entry, struct page *page)
{
int i, n;
struct shmid_kernel *seg = shm_segs[i];
if ((seg == IPC_UNUSED) || (seg == IPC_NOID))
continue;
- for (n = 0; n < seg->shm_npages; n++)
- if (pte_val(seg->shm_pages[n]) == pte_val(entry)) {
+ for (n = 0; n < seg->shm_npages; n++) {
+ if (pte_none(seg->shm_pages[n]))
+ continue;
+ if (pte_present(seg->shm_pages[n]))
+ continue;
+ if (pte_to_swp_entry(seg->shm_pages[n]).val == entry.val) {
shm_unuse_page(seg, n, entry, page);
return;
}
+ }
}
spin_unlock(&shm_lock);
}
NULL /* revalidate */
};
-extern struct proc_dir_entry proc_sys_root;
+extern struct proc_dir_entry *proc_sys_root;
static void register_proc_table(ctl_table *, struct proc_dir_entry *);
static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
void __init sysctl_init(void)
{
#ifdef CONFIG_PROC_FS
- register_proc_table(root_table, &proc_sys_root);
+ register_proc_table(root_table, proc_sys_root);
#endif
}
else
DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
#ifdef CONFIG_PROC_FS
- register_proc_table(table, &proc_sys_root);
+ register_proc_table(table, proc_sys_root);
#endif
return tmp;
}
{
DLIST_DELETE(header, ctl_entry);
#ifdef CONFIG_PROC_FS
- unregister_proc_table(header->ctl_table, &proc_sys_root);
+ unregister_proc_table(header->ctl_table, proc_sys_root);
#endif
kfree(header);
}
return -ENOSYS;
}
+int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ return -ENOSYS;
+}
+
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
return -ENOSYS;
}
+int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ return -ENOSYS;
+}
+
int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
spinlock_t pagemap_lru_lock = SPIN_LOCK_UNLOCKED;
#define CLUSTER_PAGES (1 << page_cluster)
-#define CLUSTER_SHIFT (PAGE_CACHE_SHIFT + page_cluster)
-#define CLUSTER_BYTES (1 << CLUSTER_SHIFT)
-#define CLUSTER_OFFSET(x) (((x) >> CLUSTER_SHIFT) << CLUSTER_SHIFT)
+#define CLUSTER_OFFSET(x) (((x) >> page_cluster) << page_cluster)
void __add_page_to_hash_queue(struct page * page, struct page **p)
{
void truncate_inode_pages(struct inode * inode, unsigned long start)
{
struct list_head *head, *curr;
- unsigned long offset;
struct page * page;
- int partial = 0;
+ unsigned partial = start & (PAGE_CACHE_SIZE - 1);
+
+ start = (start + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
repeat:
head = &inode->i_data.pages;
spin_lock(&pagecache_lock);
curr = head->next;
while (curr != head) {
+ unsigned long offset;
page = list_entry(curr, struct page, list);
curr = curr->next;
- offset = page->offset;
+ offset = page->pg_offset;
/* page wholly truncated - free it */
if (offset >= start) {
/*
* there is only one partial page possible.
*/
- if (partial)
+ if (!partial)
+ continue;
+
+ /* and it's the one preceeding the first wholly truncated page */
+ if ((offset + 1) != start)
continue;
- offset = start - offset;
/* partial truncate, clear end of page */
- if (offset < PAGE_CACHE_SIZE) {
- get_page(page);
- spin_unlock(&pagecache_lock);
+ get_page(page);
+ spin_unlock(&pagecache_lock);
- lock_page(page);
- partial = 1;
+ lock_page(page);
- memclear_highpage_flush(page, offset,
- PAGE_CACHE_SIZE-offset);
- if (inode->i_op->flushpage)
- inode->i_op->flushpage(inode, page, offset);
- /*
- * we have dropped the spinlock so we have to
- * restart.
- */
- UnlockPage(page);
- page_cache_release(page);
- goto repeat;
- }
+ memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+ if (inode->i_op->flushpage)
+ inode->i_op->flushpage(inode, page, partial);
+
+ partial = 0;
+
+ /*
+ * we have dropped the spinlock so we have to
+ * restart.
+ */
+ UnlockPage(page);
+ page_cache_release(page);
+ goto repeat;
}
spin_unlock(&pagecache_lock);
}
goto not_found;
if (page->mapping != mapping)
continue;
- if (page->offset == offset)
+ if (page->pg_offset == offset)
break;
}
set_bit(PG_referenced, &page->flags);
int retval = 0;
head = &inode->i_data.pages;
- start &= PAGE_MASK;
spin_lock(&pagecache_lock);
curr = head->next;
curr = curr->next;
if (!page->buffers)
continue;
- if (page->offset >= end)
+ if (page->pg_offset >= end)
continue;
- if (page->offset < start)
+ if (page->pg_offset < start)
continue;
get_page(page);
*/
int generic_buffer_fdatasync(struct inode *inode, unsigned long start, unsigned long end)
{
+ unsigned long start_idx = start >> PAGE_CACHE_SHIFT;
+ unsigned long end_idx = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
int retval;
- retval = do_buffer_fdatasync(inode, start, end, writeout_one_page);
- retval |= do_buffer_fdatasync(inode, start, end, waitfor_one_page);
+ retval = do_buffer_fdatasync(inode, start_idx, end_idx, writeout_one_page);
+ retval |= do_buffer_fdatasync(inode, start_idx, end_idx, waitfor_one_page);
return retval;
}
flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced));
page->flags = flags | (1 << PG_locked);
get_page(page);
- page->offset = offset;
+ page->pg_offset = offset;
add_page_to_inode_queue(mapping, page);
__add_page_to_hash_queue(page, hash);
lru_cache_add(page);
* Read in an entire cluster at once. A cluster is usually a 64k-
* aligned block that includes the address requested in "offset."
*/
-static void read_cluster_nonblocking(struct file * file,
- unsigned long offset)
+static void read_cluster_nonblocking(struct file * file, unsigned long offset)
{
- off_t filesize = file->f_dentry->d_inode->i_size;
+ unsigned long filesize = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
unsigned long pages = CLUSTER_PAGES;
offset = CLUSTER_OFFSET(offset);
while ((pages-- > 0) && (offset < filesize)) {
page_cache_read(file, offset);
- offset += PAGE_CACHE_SIZE;
+ offset ++;
}
return;
total_rawin/total_reada,
(total_async*100)/total_reada);
#ifdef DEBUG_READAHEAD
- printk("Readahead snapshot: max=%ld, len=%ld, win=%ld, raend=%ld\n",
+ printk("Readahead snapshot: max=%ld, len=%ld, win=%ld, raend=%Ld\n",
filp->f_ramax, filp->f_ralen, filp->f_rawin, filp->f_raend);
#endif
ahead += PAGE_CACHE_SIZE;
if ((raend + ahead) >= inode->i_size)
break;
- page_cache_read(filp, raend + ahead);
+ page_cache_read(filp, (raend + ahead) >> PAGE_CACHE_SHIFT);
}
/*
* If we tried to read ahead some pages,
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
- size_t pos, pgpos;
+ unsigned long pos, pgpos;
struct page *cached_page;
int reada_ok;
int error;
int max_readahead = get_max_readahead(inode);
+ unsigned long pgoff;
cached_page = NULL;
pos = *ppos;
pgpos = pos & PAGE_CACHE_MASK;
+ pgoff = pos >> PAGE_CACHE_SHIFT;
/*
* If the current position is outside the previous read-ahead window,
* we reset the current read-ahead context and set read ahead max to zero
/*
* Try to find the data in the page cache..
*/
- hash = page_hash(&inode->i_data, pos & PAGE_CACHE_MASK);
+ hash = page_hash(&inode->i_data, pgoff);
spin_lock(&pagecache_lock);
- page = __find_page_nolock(&inode->i_data, pos & PAGE_CACHE_MASK, *hash);
+ page = __find_page_nolock(&inode->i_data, pgoff, *hash);
if (!page)
goto no_cached_page;
found_page:
*/
nr = actor(desc, page, offset, nr);
pos += nr;
+ pgoff = pos >> PAGE_CACHE_SHIFT;
page_cache_release(page);
if (nr && desc->count)
continue;
*/
page_not_up_to_date:
generic_file_readahead(reada_ok, filp, inode,
- pos & PAGE_CACHE_MASK, page);
+ pos & PAGE_CACHE_MASK, page);
if (Page_Uptodate(page))
goto page_ok;
* dropped the page cache lock. Check for that.
*/
spin_lock(&pagecache_lock);
- page = __find_page_nolock(&inode->i_data, pos & PAGE_CACHE_MASK, *hash);
+ page = __find_page_nolock(&inode->i_data, pgoff, *hash);
if (page)
goto found_page;
}
* Ok, add the new page to the hash-queues...
*/
page = cached_page;
- __add_to_page_cache(page, &inode->i_data, pos & PAGE_CACHE_MASK, hash);
+ __add_to_page_cache(page, &inode->i_data, pgoff, hash);
spin_unlock(&pagecache_lock);
cached_page = NULL;
retval = -EFAULT;
if (access_ok(VERIFY_WRITE, buf, count)) {
retval = 0;
+
if (count) {
read_descriptor_t desc;
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct page *page, **hash, *old_page;
+ unsigned long size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- unsigned long offset = address - area->vm_start + area->vm_offset;
+ unsigned long pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
/*
* Semantics for shared and private memory areas are different
* of the file is an error and results in a SIGBUS, while a
* private mapping just maps in a zero page.
*/
- if ((offset >= inode->i_size) &&
+ if ((pgoff >= size) &&
(area->vm_flags & VM_SHARED) && (area->vm_mm == current->mm))
return NULL;
/*
* Do we have something in the page cache already?
*/
- hash = page_hash(&inode->i_data, offset);
+ hash = page_hash(&inode->i_data, pgoff);
retry_find:
- page = __find_get_page(&inode->i_data, offset, hash);
+ page = __find_get_page(&inode->i_data, pgoff, hash);
if (!page)
goto no_cached_page;
* Otherwise, we're off the end of a privately mapped file,
* so we need to map a zero page.
*/
- if (offset < inode->i_size)
- read_cluster_nonblocking(file, offset);
+ if (pgoff < size)
+ read_cluster_nonblocking(file, pgoff);
else
- page_cache_read(file, offset);
+ page_cache_read(file, pgoff);
/*
* The page we want has now been added to the page cache.
unsigned long size;
int (*writepage) (struct file *, struct page *);
- size = offset + PAGE_SIZE;
+ size = (offset << PAGE_CACHE_SHIFT) + PAGE_CACHE_SIZE;
/* refuse to extend file size.. */
if (S_ISREG(inode->i_mode)) {
if (size > inode->i_size)
if (size < offset)
return -EIO;
}
- size -= offset;
retval = -EIO;
writepage = inode->i_op->writepage;
lock_page(page);
extern void wakeup_bdflush(int);
int filemap_swapout(struct page * page, struct file * file)
{
- int retval = filemap_write_page(file, page->offset, page, 0);
+ int retval = filemap_write_page(file, page->pg_offset, page, 0);
wakeup_bdflush(0);
return retval;
}
static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
{
+ unsigned long pgoff;
pte_t pte = *ptep;
struct page *page;
int error;
pte_clear(ptep);
flush_tlb_page(vma, address);
if (!pte_present(pte)) {
- swap_free(pte);
+ swap_free(pte_to_swp_entry(pte));
return 0;
}
page = pte_page(pte);
}
if (PageHighMem(page))
BUG();
- error = filemap_write_page(vma->vm_file, address - vma->vm_start + vma->vm_offset, page, 1);
+ pgoff = (address - vma->vm_start) >> PAGE_CACHE_SHIFT;
+ pgoff += vma->vm_pgoff;
+ if (page->pg_offset != pgoff) {
+ printk("weirdness: pgoff=%lu pg_offset=%lu address=%lu vm_start=%lu vm_pgoff=%lu\n",
+ pgoff, page->pg_offset, address, vma->vm_start, vma->vm_pgoff);
+ }
+ error = filemap_write_page(vma->vm_file, pgoff, page, 1);
page_cache_free(page);
return error;
}
}
while (count) {
- unsigned long bytes, pgpos, offset;
+ unsigned long bytes, pgoff, offset;
+
/*
* Try to find the page in the cache. If it isn't there,
* allocate a free page.
*/
- offset = (pos & ~PAGE_CACHE_MASK);
- pgpos = pos & PAGE_CACHE_MASK;
+ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
+ pgoff = pos >> PAGE_CACHE_SHIFT;
bytes = PAGE_CACHE_SIZE - offset;
if (bytes > count)
bytes = count;
- hash = page_hash(&inode->i_data, pgpos);
+ hash = page_hash(&inode->i_data, pgoff);
repeat_find:
- page = __find_lock_page(&inode->i_data, pgpos, hash);
+ page = __find_lock_page(&inode->i_data, pgoff, hash);
if (!page) {
if (!cached_page) {
cached_page = page_cache_alloc();
break;
}
page = cached_page;
- if (add_to_page_cache_unique(page,&inode->i_data,pgpos,hash))
+ if (add_to_page_cache_unique(page,&inode->i_data,pgoff,hash))
goto repeat_find;
cached_page = NULL;
kunmap(vaddr, KM_WRITE);
/* Preserve the caching of the swap_entry. */
- highpage->offset = page->offset;
- highpage->inode = page->inode;
+ highpage->pg_offset = page->pg_offset;
+ highpage->mapping = page->mapping;
/*
* We can just forget the old page since
if (pte_none(pte))
goto cont_copy_pte_range;
if (!pte_present(pte)) {
- swap_duplicate(pte);
+ swap_duplicate(pte_to_swp_entry(pte));
set_pte(dst_pte, pte);
goto cont_copy_pte_range;
}
free_page_and_swap_cache(mem_map+nr);
return 1;
}
- swap_free(page);
+ swap_free(pte_to_swp_entry(page));
return 0;
}
*/
void vmtruncate(struct inode * inode, unsigned long offset)
{
+ unsigned long partial, pgoff;
struct vm_area_struct * mpnt;
truncate_inode_pages(inode, offset);
spin_lock(&inode->i_shared_lock);
if (!inode->i_mmap)
goto out_unlock;
+
+ partial = offset & (PAGE_CACHE_SIZE - 1);
+ pgoff = offset >> PAGE_CACHE_SHIFT;
+ if (partial)
+ pgoff ++;
+
mpnt = inode->i_mmap;
do {
struct mm_struct *mm = mpnt->vm_mm;
unsigned long diff;
/* mapping wholly truncated? */
- if (mpnt->vm_offset >= offset) {
+ if (mpnt->vm_pgoff >= pgoff) {
flush_cache_range(mm, start, end);
zap_page_range(mm, start, len);
flush_tlb_range(mm, start, end);
continue;
}
+
/* mapping wholly unaffected? */
- diff = offset - mpnt->vm_offset;
+ len = len >> PAGE_SHIFT;
+ diff = pgoff - mpnt->vm_pgoff;
if (diff >= len)
continue;
+
/* Ok, partially affected.. */
- start += diff;
- len = (len - diff) & PAGE_MASK;
+ start += diff << PAGE_SHIFT;
+ len = (len - diff) << PAGE_SHIFT;
if (start & ~PAGE_MASK) {
partial_clear(mpnt, start);
start = (start + ~PAGE_MASK) & PAGE_MASK;
* because it doesn't cost us any seek time. We also make sure to queue
* the 'original' request together with the readahead ones...
*/
-void swapin_readahead(pte_t entry)
+void swapin_readahead(swp_entry_t entry)
{
int i;
struct page *new_page;
static int do_swap_page(struct task_struct * tsk,
struct vm_area_struct * vma, unsigned long address,
- pte_t * page_table, pte_t entry, int write_access)
+ pte_t * page_table, swp_entry_t entry, int write_access)
{
struct page *page = lookup_swap_cache(entry);
pte_t pte;
if (!pte_present(entry)) {
if (pte_none(entry))
return do_no_page(tsk, vma, address, write_access, pte);
- return do_swap_page(tsk, vma, address, pte, entry, write_access);
+ return do_swap_page(tsk, vma, address, pte, pte_to_swp_entry(entry), write_access);
}
/*
#include <linux/shm.h>
#include <linux/mman.h>
#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
vmlist_modify_lock(vma->vm_mm);
- vma->vm_offset += end - vma->vm_start;
+ vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = end;
insert_vm_struct(current->mm, n);
vmlist_modify_unlock(vma->vm_mm);
return -EAGAIN;
*n = *vma;
n->vm_start = start;
- n->vm_offset += n->vm_start - vma->vm_start;
+ n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT;
n->vm_flags = newflags;
if (n->vm_file)
get_file(n->vm_file);
*right = *vma;
left->vm_end = start;
right->vm_start = end;
- right->vm_offset += right->vm_start - left->vm_start;
+ right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT;
vma->vm_flags = newflags;
if (vma->vm_file)
atomic_add(2, &vma->vm_file->f_count);
vma->vm_ops->open(right);
}
vmlist_modify_lock(vma->vm_mm);
- vma->vm_offset += start - vma->vm_start;
+ vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = start;
vma->vm_end = end;
vma->vm_flags = newflags;
if (off + len < off)
return -EINVAL;
+ off = off >> PAGE_SHIFT;
+
/* Too many mappings? */
if (mm->map_count > MAX_MAP_COUNT)
return -ENOMEM;
vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
vma->vm_ops = NULL;
- vma->vm_offset = off;
+ vma->vm_pgoff = off;
vma->vm_file = NULL;
vma->vm_private_data = NULL;
area->vm_end = addr;
vmlist_modify_lock(current->mm);
} else if (addr == area->vm_start) {
- area->vm_offset += (end - area->vm_start);
+ area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;
area->vm_start = end;
vmlist_modify_lock(current->mm);
} else {
mpnt->vm_page_prot = area->vm_page_prot;
mpnt->vm_flags = area->vm_flags;
mpnt->vm_ops = area->vm_ops;
- mpnt->vm_offset = area->vm_offset + (end - area->vm_start);
+ mpnt->vm_pgoff = area->vm_pgoff;
+ area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;
mpnt->vm_file = area->vm_file;
mpnt->vm_private_data = area->vm_private_data;
if (mpnt->vm_file)
vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
vma->vm_ops = NULL;
- vma->vm_offset = 0;
+ vma->vm_pgoff = 0;
vma->vm_file = NULL;
vma->vm_private_data = NULL;
* the offsets must be contiguous..
*/
if ((mpnt->vm_file != NULL) || (mpnt->vm_flags & VM_SHM)) {
- unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
- if (off != mpnt->vm_offset)
+ unsigned long off = prev->vm_pgoff;
+ off += (prev->vm_end - prev->vm_start) >> PAGE_SHIFT;
+ if (off != mpnt->vm_pgoff)
continue;
}
prev->vm_end = mpnt->vm_end;
prev->vm_next = mpnt->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->close) {
- mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
+ mpnt->vm_pgoff += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
mpnt->vm_start = mpnt->vm_end;
vmlist_modify_unlock(mm);
mpnt->vm_ops->close(mpnt);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
vmlist_modify_lock(vma->vm_mm);
- vma->vm_offset += end - vma->vm_start;
+ vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = end;
insert_vm_struct(current->mm, n);
vmlist_modify_unlock(vma->vm_mm);
return -ENOMEM;
*n = *vma;
n->vm_start = start;
- n->vm_offset += n->vm_start - vma->vm_start;
+ n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT;
n->vm_flags = newflags;
n->vm_page_prot = prot;
if (n->vm_file)
*right = *vma;
left->vm_end = start;
right->vm_start = end;
- right->vm_offset += right->vm_start - left->vm_start;
+ right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT;
if (vma->vm_file)
atomic_add(2,&vma->vm_file->f_count);
if (vma->vm_ops && vma->vm_ops->open) {
vma->vm_ops->open(right);
}
vmlist_modify_lock(vma->vm_mm);
- vma->vm_offset += start - vma->vm_start;
+ vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = start;
vma->vm_end = end;
vma->vm_flags = newflags;
*new_vma = *vma;
new_vma->vm_start = new_addr;
new_vma->vm_end = new_addr+new_len;
- new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
+ new_vma->vm_pgoff = vma->vm_pgoff;
+ new_vma->vm_pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
if (new_vma->vm_file)
get_file(new_vma->vm_file);
if (new_vma->vm_ops && new_vma->vm_ops->open)
* that shared pages stay shared while being swapped.
*/
-static int rw_swap_page_base(int rw, pte_t entry, struct page *page, int wait)
+static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page, int wait)
{
unsigned long type, offset;
struct swap_info_struct * p;
return 0;
}
if (p->swap_map && !p->swap_map[offset]) {
- pte_ERROR(entry);
+ printk("VM: Bad swap entry %08lx\n", entry.val);
return 0;
}
if (!(p->flags & SWP_USED)) {
*/
void rw_swap_page(int rw, struct page *page, int wait)
{
- pte_t entry = get_pagecache_pte(page);
+ swp_entry_t entry;
+
+ entry.val = page->pg_offset;
if (!PageLocked(page))
PAGE_BUG(page);
* Therefore we can't use it. Later when we can remove the need for the
* lock map and we can reduce the number of functions exported.
*/
-void rw_swap_page_nolock(int rw, pte_t entry, char *buf, int wait)
+void rw_swap_page_nolock(int rw, swp_entry_t entry, char *buf, int wait)
{
struct page *page = mem_map + MAP_NR(buf);
/* If there is a different PAGE_SIZE around, and it works with this allocator,
* then change the following.
*/
-#if (PAGE_SIZE != 8192 && PAGE_SIZE != 4096)
+#if (PAGE_SIZE != 8192 && PAGE_SIZE != 4096 && PAGE_SIZE != 32768)
#error Your page size is probably not correctly supported - please check
#endif
}
#endif
-void add_to_swap_cache(struct page *page, pte_t entry)
+void add_to_swap_cache(struct page *page, swp_entry_t entry)
{
#ifdef SWAP_CACHE_INFO
swap_cache_add_total++;
BUG();
if (page->mapping)
BUG();
- add_to_page_cache(page, &swapper_space, pte_val(entry));
+ add_to_page_cache(page, &swapper_space, entry.val);
}
/*
* Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
* "permanent", but will be reclaimed by the next swapoff.
*/
-int swap_duplicate(pte_t entry)
+int swap_duplicate(swp_entry_t entry)
{
struct swap_info_struct * p;
unsigned long offset, type;
int result = 0;
- if (!pte_val(entry))
+ /* Swap entry 0 is illegal */
+ if (!entry.val)
goto out;
type = SWP_TYPE(entry);
if (type & SHM_SWP_TYPE)
else {
static int overflow = 0;
if (overflow++ < 5)
- pte_ERROR(entry);
+ printk("VM: swap entry overflow\n");
p->swap_map[offset] = SWAP_MAP_MAX;
}
result = 1;
return result;
bad_file:
- pte_ERROR(entry);
+ printk("Bad swap file entry %08lx\n", entry.val);
goto out;
bad_offset:
- pte_ERROR(entry);
+ printk("Bad swap offset entry %08lx\n", entry.val);
goto out;
bad_unused:
- pte_ERROR(entry);
+ printk("Unused swap offset entry %08lx\n", entry.val);
goto out;
}
{
struct swap_info_struct * p;
unsigned long offset, type;
- pte_t entry = get_pagecache_pte(page);
+ swp_entry_t entry;
int retval = 0;
- if (!pte_val(entry))
+ entry.val = page->pg_offset;
+ if (!entry.val)
goto bad_entry;
type = SWP_TYPE(entry);
if (type & SHM_SWP_TYPE)
printk(KERN_ERR "swap_count: null entry!\n");
goto out;
bad_file:
- pte_ERROR(entry);
+ printk("Bad swap file entry %08lx\n", entry.val);
goto out;
bad_offset:
- pte_ERROR(entry);
+ printk("Bad swap offset entry %08lx\n", entry.val);
goto out;
bad_unused:
- pte_ERROR(entry);
+ printk("Unused swap offset entry %08lx\n", entry.val);
goto out;
}
*/
void __delete_from_swap_cache(struct page *page)
{
- pte_t entry = get_pagecache_pte(page);
+ swp_entry_t entry;
+
+ entry.val = page->pg_offset;
#ifdef SWAP_CACHE_INFO
swap_cache_del_total++;
* lock before returning.
*/
-struct page * lookup_swap_cache(pte_t entry)
+struct page * lookup_swap_cache(swp_entry_t entry)
{
struct page *found;
#endif
while (1) {
/*
- * Right now the pagecache is 32-bit only.
+ * Right now the pagecache is 32-bit only. But it's a 32 bit index. =)
*/
- found = find_lock_page(&swapper_space, pte_val(entry));
+ found = find_lock_page(&swapper_space, entry.val);
if (!found)
return 0;
if (found->mapping != &swapper_space || !PageSwapCache(found))
* the swap entry is no longer in use.
*/
-struct page * read_swap_cache_async(pte_t entry, int wait)
+struct page * read_swap_cache_async(swp_entry_t entry, int wait)
{
struct page *found_page = 0, *new_page;
unsigned long new_page_addr;
return 0;
}
-pte_t get_swap_page(void)
+swp_entry_t get_swap_page(void)
{
struct swap_info_struct * p;
unsigned long offset;
- pte_t entry = __pte(0);
+ swp_entry_t entry;
int type, wrapped = 0;
+ entry.val = 0; /* Out of memory */
type = swap_list.next;
if (type < 0)
goto out;
}
-void swap_free(pte_t entry)
+void swap_free(swp_entry_t entry)
{
struct swap_info_struct * p;
unsigned long offset, type;
- if (!pte_val(entry))
+ if (!entry.val)
goto out;
type = SWP_TYPE(entry);
printk("swap_free: offset exceeds max\n");
goto out;
bad_free:
- pte_ERROR(entry);
+ printk("VM: Bad swap entry %08lx\n", entry.val);
goto out;
}
/* needs the big kernel lock */
-pte_t acquire_swap_entry(struct page *page)
+swp_entry_t acquire_swap_entry(struct page *page)
{
struct swap_info_struct * p;
unsigned long offset, type;
- pte_t entry;
+ swp_entry_t entry;
if (!test_bit(PG_swap_entry, &page->flags))
goto new_swap_entry;
/* We have the old entry in the page offset still */
- if (!page->offset)
+ if (!page->pg_offset)
goto new_swap_entry;
- entry = get_pagecache_pte(page);
+ entry.val = page->pg_offset;
type = SWP_TYPE(entry);
if (type & SHM_SWP_TYPE)
goto new_swap_entry;
* what to do if a write is requested later.
*/
static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
- pte_t *dir, pte_t entry, struct page* page)
+ pte_t *dir, swp_entry_t entry, struct page* page)
{
pte_t pte = *dir;
set_pte(dir, pte_mkdirty(pte));
return;
}
- if (pte_val(pte) != pte_val(entry))
+ if (pte_val(pte) != entry.val)
return;
set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
swap_free(entry);
static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
unsigned long address, unsigned long size, unsigned long offset,
- pte_t entry, struct page* page)
+ swp_entry_t entry, struct page* page)
{
pte_t * pte;
unsigned long end;
static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
unsigned long address, unsigned long size,
- pte_t entry, struct page* page)
+ swp_entry_t entry, struct page* page)
{
pmd_t * pmd;
unsigned long offset, end;
}
static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
- pte_t entry, struct page* page)
+ swp_entry_t entry, struct page* page)
{
unsigned long start = vma->vm_start, end = vma->vm_end;
}
static void unuse_process(struct mm_struct * mm,
- pte_t entry, struct page* page)
+ swp_entry_t entry, struct page* page)
{
struct vm_area_struct* vma;
struct swap_info_struct * si = &swap_info[type];
struct task_struct *p;
struct page *page;
- pte_t entry;
+ swp_entry_t entry;
int i;
while (1) {
*/
if (si->swap_map[i] != 0) {
if (si->swap_map[i] != SWAP_MAP_MAX)
- pte_ERROR(entry);
+ printk("VM: Undead swap entry %08lx\n", entry.val);
si->swap_map[i] = 0;
nr_swap_pages++;
}
*/
static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask)
{
- pte_t pte, entry;
+ pte_t pte;
+ swp_entry_t entry;
struct page * page;
int (*swapout)(struct page *, struct file *);
* memory, and we should just continue our scan.
*/
if (PageSwapCache(page)) {
- entry = get_pagecache_pte(page);
+ entry.val = page->pg_offset;
swap_duplicate(entry);
- set_pte(page_table, entry);
+ set_pte(page_table, swp_entry_to_pte(entry));
drop_pte:
vma->vm_mm->rss--;
flush_tlb_page(vma, address);
* page with that swap entry.
*/
entry = acquire_swap_entry(page);
- if (!pte_val(entry))
+ if (!entry.val)
goto out_failed; /* No swap space left */
if (!(page = prepare_highmem_swapout(page)))
goto out_swap_free;
vma->vm_mm->rss--;
- set_pte(page_table, entry);
+ set_pte(page_table, swp_entry_to_pte(entry));
vmlist_access_unlock(vma->vm_mm);
flush_tlb_page(vma, address);
* routing.
*/
-#ifdef CONFIG_PROC_FS
+#ifndef CONFIG_PROC_FS
+int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy) {}
+#else
int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy)
{
int len=0;
* too much for this.
*/
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry tr_rif_proc = {
- PROC_NET_TR_RIF, 6, "tr_rif",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rif_get_info
-};
-#endif
-
void __init rif_init(struct net_proto *unused)
{
rif_timer.expires = RIF_TIMEOUT;
init_timer(&rif_timer);
add_timer(&rif_timer);
-#ifdef CONFIG_PROC_FS
- proc_net_register(&tr_rif_proc);
-#endif
+ proc_net_create("tr_rif",0,rif_get_info);
}
#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_aarp_entries=
-{
- PROC_NET_AT_AARP, 4, "aarp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- aarp_get_info
-};
-
void aarp_register_proc_fs(void)
{
- proc_net_register(&proc_aarp_entries);
+ proc_net_create("aarp", 0, aarp_get_info);
}
void aarp_unregister_proc_fs(void)
{
- proc_net_unregister(PROC_NET_AT_AARP);
+ proc_net_remove("aarp");
}
#endif
EXPORT_SYMBOL(atrtr_get_dev);
EXPORT_SYMBOL(atalk_find_dev_addr);
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_appletalk=
-{
- PROC_NET_ATALK, 9, "appletalk",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- atalk_get_info
-};
-
-static struct proc_dir_entry proc_atalk_route=
-{
- PROC_NET_AT_ROUTE, 11,"atalk_route",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- atalk_rt_get_info
-};
-
-static struct proc_dir_entry proc_atalk_iface=
-{
- PROC_NET_ATIF, 11,"atalk_iface",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- atalk_if_get_info
-};
-#endif /* CONFIG_PROC_FS */
-
/* Called by proto.c on kernel start up */
void __init atalk_proto_init(struct net_proto *pro)
aarp_proto_init();
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_appletalk);
- proc_net_register(&proc_atalk_route);
- proc_net_register(&proc_atalk_iface);
+ proc_net_create("appletalk", 0, atalk_get_info);
+ proc_net_create("atalk_route", 0, atalk_rt_get_info);
+ proc_net_create("atalk_iface", 0, atalk_if_get_info);
aarp_register_proc_fs();
#endif /* CONFIG_PROC_FS */
#endif /* CONFIG_SYSCTL */
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_ATALK);
- proc_net_unregister(PROC_NET_AT_ROUTE);
- proc_net_unregister(PROC_NET_ATIF);
+ proc_net_remove("appletalk");
+ proc_net_remove("atalk_route");
+ proc_net_remove("atalk_iface");
aarp_unregister_proc_fs();
#endif /* CONFIG_PROC_FS */
EXPORT_SYMBOL(null_ax25_address);
EXPORT_SYMBOL(ax25_display_timer);
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_ax25_route = {
- PROC_NET_AX25_ROUTE, 10, "ax25_route",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ax25_rt_get_info
-};
-static struct proc_dir_entry proc_ax25 = {
- PROC_NET_AX25, 4, "ax25",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ax25_get_info
-};
-static struct proc_dir_entry proc_ax25_calls = {
- PROC_NET_AX25_CALLS, 10, "ax25_calls",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ax25_uid_get_info
-};
-#endif
-
void __init ax25_proto_init(struct net_proto *pro)
{
sock_register(&ax25_family_ops);
#endif
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_ax25_route);
- proc_net_register(&proc_ax25);
- proc_net_register(&proc_ax25_calls);
+ proc_net_create("ax25_route", 0, ax25_rt_get_info);
+ proc_net_create("ax25", 0, ax25_get_info);
+ proc_net_create("ax25_calls", 0, ax25_uid_get_info);
#endif
printk(KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n");
void cleanup_module(void)
{
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_AX25_ROUTE);
- proc_net_unregister(PROC_NET_AX25);
- proc_net_unregister(PROC_NET_AX25_CALLS);
- proc_net_unregister(PROC_NET_AX25_ROUTE);
+ proc_net_remove("ax25_route");
+ proc_net_remove("ax25");
+ proc_net_remove("ax25_calls");
#endif
ax25_rt_free();
ax25_uid_free();
return len;
}
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry proc_net_bridge= {
- PROC_NET_BRIDGE, 6, "bridge",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- br_tree_get_info
-};
-#endif
void __init br_init(void)
{ /* (4.8.1) */
int port_no;
br_stats.exempt_protocols = 0;
/*start_hello_timer();*/
/* Vova Oksman: register the function for the PROCfs "bridge" file */
-#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_bridge);
-#endif
+ proc_net_create("bridge", 0, br_tree_get_info);
}
static inline unsigned short make_port_id(int port_no)
extern int cpm_enet_init(void);
#endif /* CONFIG_8xx */
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_dev = {
- PROC_NET_DEV, 3, "dev",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- dev_get_info
-};
-#endif
-
-#ifdef CONFIG_NET_RADIO
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_wireless = {
- PROC_NET_WIRELESS, 8, "wireless",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- dev_get_wireless_info
-};
-#endif /* CONFIG_PROC_FS */
-#endif /* CONFIG_NET_RADIO */
-
int __init net_dev_init(void)
{
struct net_device *dev, **dp;
}
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_dev);
- {
- struct proc_dir_entry *ent = create_proc_entry("net/dev_stat", 0, 0);
- ent->read_proc = dev_proc_stats;
- }
-#endif
-
+ proc_net_create("dev", 0, dev_get_info);
+ create_proc_read_entry("net/dev_stat", 0, 0, dev_proc_stats, NULL);
#ifdef CONFIG_NET_RADIO
-#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_wireless);
-#endif /* CONFIG_PROC_FS */
+ proc_net_create("wireless", 0, dev_get_wireless_info);
#endif /* CONFIG_NET_RADIO */
+#endif /* CONFIG_PROC_FS */
init_bh(NET_BH, net_bh);
void __init dev_mcast_init(void)
{
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-
- ent = create_proc_entry("net/dev_mcast", 0, 0);
- ent->read_proc = dev_mc_read_proc;
+ create_proc_read_entry("net/dev_mcast", 0, 0, dev_mc_read_proc, NULL);
#endif
}
int i;
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-
- ent = create_proc_entry("net/profile", 0, 0);
- ent->read_proc = profile_read_proc;
+ create_proc_read_entry("net/profile", 0, 0, profile_read_proc, NULL);
#endif
register_netdevice(&whitehole_dev);
NULL,
};
-#ifdef CONFIG_PROC_FS
-
static int dn_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
struct sock *sk;
return len;
}
-struct proc_dir_entry decnet_linkinfo = {
- PROC_NET_DN_SKT, 6, "decnet", S_IFREG | S_IRUGO,
- 1, 0, 0, 0, &proc_net_inode_operations, dn_get_info
-};
-
#ifdef CONFIG_DECNET_RAW
extern int dn_raw_get_info(char *, char **, off_t, int, int);
-struct proc_dir_entry decnet_rawinfo = {
- PROC_NET_DN_RAW, 10, "decnet_raw", S_IFREG | S_IRUGO,
- 1, 0, 0, 0, &proc_net_inode_operations, dn_raw_get_info
-};
-
#endif /* CONFIG_DECNET_RAW */
-#endif /* CONFIG_PROC_FS */
static struct net_proto_family dn_family_ops = {
AF_DECnet,
dn_create
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
-#ifdef CONFIG_PROC_FS
- proc_net_register(&decnet_linkinfo);
+ proc_net_create("decnet", 0, dn_get_info);
#ifdef CONFIG_DECNET_RAW
- proc_net_register(&decnet_rawinfo);
-#endif
+ proc_net_create("decnet_raw", 0, dn_raw_get_info);
#endif
dn_dev_init();
dn_neigh_init();
dn_fib_cleanup();
#endif /* CONFIG_DECNET_ROUTER */
-#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_DN_SKT);
+ proc_net_remove("decnet");
#ifdef CONFIG_DECNET_RAW
- proc_net_unregister(PROC_NET_DN_RAW);
-#endif
+ proc_net_remove("decnet_raw");
#endif
dev_remove_pack(&dn_dix_packet_type);
return(len);
}
-static struct proc_dir_entry proc_net_decnet_dev = {
- PROC_NET_DN_DEV, 10, "decnet_dev",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- decnet_dev_get_info
-};
-
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_RTNETLINK
#endif /* CONFIG_RTNETLINK */
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_decnet_dev);
+ proc_net_create("decnet_dev", 0, decnet_dev_get_info);
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SYSCTL
#endif /* CONFIG_SYSCTL */
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_DN_DEV);
+ proc_net_remove("decnet_dev");
#endif /* CONFIG_PROC_FS */
dn_dev_devices_off();
return pinfo.len;
}
-static struct proc_dir_entry proc_net_decnet_route = {
- PROC_NET_DN_ROUTE, 12, "decnet_route",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- decnet_rt_get_info
-};
-
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_DECNET_MODULE
void dn_fib_cleanup(void)
{
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_DN_ROUTE);
+ proc_net_create("decnet_route",0,decnet_rt_get_info);
#endif /* CONFIG_PROC_FS */
}
#endif /* CONFIG_DECNET_MODULE */
memset(dn_fib_tables, 0, DN_NUM_TABLES * sizeof(struct dn_fib_table *));
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_decnet_route);
+ proc_net_remove("decnet_route");
#endif
}
return len;
}
-static struct proc_dir_entry proc_net_dn_neigh = {
- PROC_NET_DN_ADJ, 12, "decnet_neigh",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- dn_neigh_get_info
-};
-
#endif
void __init dn_neigh_init(void)
neigh_table_init(&dn_neigh_table);
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_dn_neigh);
+ proc_net_create("decnet_neigh",0,dn_neigh_get_info);
#endif /* CONFIG_PROC_FS */
}
void dn_neigh_cleanup(void)
{
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_DN_ADJ);
+ proc_net_remove("decnet_neigh");
#endif /* CONFIG_PROC_FS */
neigh_table_clear(&dn_neigh_table);
}
return(len);
}
-static struct proc_dir_entry proc_net_decnet_cache = {
- PROC_NET_DN_CACHE, 12, "decnet_cache",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- decnet_cache_get_info
-};
-
#endif /* CONFIG_PROC_FS */
void __init dn_route_init(void)
add_timer(&dn_route_timer);
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_decnet_cache);
+ proc_net_create("decnet_cache",0,decnet_cache_get_info);
#endif /* CONFIG_PROC_FS */
}
del_timer(&dn_route_timer);
dn_run_flush(0);
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_DN_CACHE);
+ proc_net_remove("decnet_cache");
#endif /* CONFIG_PROC_FS */
}
#endif /* CONFIG_DECNET_MODULE */
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_raw = {
- PROC_NET_RAW, 3, "raw",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- raw_get_info
-};
-static struct proc_dir_entry proc_net_netstat = {
- PROC_NET_NETSTAT, 7, "netstat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- netstat_get_info
-};
-static struct proc_dir_entry proc_net_snmp = {
- PROC_NET_SNMP, 4, "snmp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- snmp_get_info
-};
-static struct proc_dir_entry proc_net_sockstat = {
- PROC_NET_SOCKSTAT, 8, "sockstat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- afinet_get_info
-};
-static struct proc_dir_entry proc_net_tcp = {
- PROC_NET_TCP, 3, "tcp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- tcp_get_info
-};
-static struct proc_dir_entry proc_net_udp = {
- PROC_NET_UDP, 3, "udp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- udp_get_info
-};
-#endif /* CONFIG_PROC_FS */
-
extern void tcp_init(void);
extern void tcp_v4_init(struct net_proto_family *);
/*
* Create all the /proc entries.
*/
-
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_raw);
- proc_net_register(&proc_net_snmp);
- proc_net_register(&proc_net_netstat);
- proc_net_register(&proc_net_sockstat);
- proc_net_register(&proc_net_tcp);
- proc_net_register(&proc_net_udp);
+ proc_net_create ("raw", 0, raw_get_info);
+ proc_net_create ("netstat", 0, netstat_get_info);
+ proc_net_create ("snmp", 0, snmp_get_info);
+ proc_net_create ("sockstat", 0, afinet_get_info);
+ proc_net_create ("tcp", 0, tcp_get_info);
+ proc_net_create ("udp", 0, udp_get_info);
#endif /* CONFIG_PROC_FS */
}
/*
* Write the contents of the ARP cache to a PROCfs file.
*/
-#ifdef CONFIG_PROC_FS
-
+#ifndef CONFIG_PROC_FS
+static int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { return 0; }
+#else
#define HBUFFERLEN 30
-int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+static int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
int len=0;
off_t pos=0;
NULL
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_arp = {
- PROC_NET_ARP, 3, "arp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- arp_get_info
-};
-#endif
-
void __init arp_init (void)
{
neigh_table_init(&arp_tbl);
dev_add_pack(&arp_packet_type);
-#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_arp);
-#endif
+ proc_net_create ("arp", 0, arp_get_info);
+
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
#endif
void __init ip_fib_init(void)
{
#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_ROUTE, 5, "route",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- fib_get_procinfo
- });
+ proc_net_create("route",0,fib_get_procinfo);
#endif /* CONFIG_PROC_FS */
#ifndef CONFIG_IP_MULTIPLE_TABLES
};
-
-#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_IP_MULTICAST
-static struct proc_dir_entry proc_net_igmp = {
- PROC_NET_IGMP, 4, "igmp",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ip_mc_procinfo
-};
-#endif
-#endif
-
/*
* IP registers the packet type and then calls the subprotocol initialisers
*/
ip_rt_init();
-#ifdef CONFIG_PROC_FS
#ifdef CONFIG_IP_MULTICAST
- proc_net_register(&proc_net_igmp);
+ proc_net_create("igmp", S_IFREG | S_IRUGO, ip_mc_procinfo);
#endif
-#endif
}
}
#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_ipmr_vif = {
- PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ipmr_vif_info
-};
-static struct proc_dir_entry proc_net_ipmr_mfc = {
- PROC_NET_IPMR_MFC, 11 ,"ip_mr_cache",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- ipmr_mfc_info
-};
#endif
#ifdef CONFIG_IP_PIMSM_V2
ipmr_expire_timer.function=ipmr_expire_process;
register_netdevice_notifier(&ip_mr_notifier);
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_ipmr_vif);
- proc_net_register(&proc_net_ipmr_mfc);
+ proc_net_create("ip_mr_vif",0,ipmr_vif_info);
+ proc_net_create("ip_mr_cache",0,ipmr_mfc_info);
#endif
}
return (hash^(hash>>8)) & 0xFF;
}
-#ifdef CONFIG_PROC_FS
-
+#ifndef CONFIG_PROC_FS
+static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { return 0; }
+#else
static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
int len=0;
void __init ip_rt_init(void)
{
-#ifdef CONFIG_PROC_FS
-#ifdef CONFIG_NET_CLS_ROUTE
- struct proc_dir_entry *ent;
-#endif
-#endif
ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache",
sizeof(struct rtable),
0, SLAB_HWCACHE_ALIGN,
+ ip_rt_gc_interval;
add_timer(&rt_periodic_timer);
-#ifdef CONFIG_PROC_FS
- proc_net_register(&(struct proc_dir_entry) {
- PROC_NET_RTCACHE, 8, "rt_cache",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rt_cache_get_info
- });
+ proc_net_create ("rt_cache", 0, rt_cache_get_info);
#ifdef CONFIG_NET_CLS_ROUTE
- ent = create_proc_entry("net/rt_acct", 0, 0);
- ent->read_proc = ip_rt_acct_read;
-#endif
+ create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read);
#endif
}
return len;
}
-struct proc_dir_entry iface_proc_entry =
-{
- 0, 8, "if_inet6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL,
- &iface_proc_info
-};
#endif /* CONFIG_PROC_FS */
/*
#endif
#ifdef CONFIG_PROC_FS
- proc_net_register(&iface_proc_entry);
+ proc_net_create("if_inet6", 0, iface_proc_info);
#endif
addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
rtnl_unlock();
#ifdef CONFIG_PROC_FS
- proc_net_unregister(iface_proc_entry.low_ino);
+ proc_net_remove("if_inet6");
#endif
}
#endif /* MODULE */
inet6_create
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_raw6 = {
- PROC_NET_RAW6, 4, "raw6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- raw6_get_info
-};
-static struct proc_dir_entry proc_net_tcp6 = {
- PROC_NET_TCP6, 4, "tcp6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- tcp6_get_info
-};
-static struct proc_dir_entry proc_net_udp6 = {
- PROC_NET_RAW6, 4, "udp6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- udp6_get_info
-};
-static struct proc_dir_entry proc_net_sockstat6 = {
- PROC_NET_SOCKSTAT6, 9, "sockstat6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- afinet6_get_info
-};
-static struct proc_dir_entry proc_net_snmp6 = {
- PROC_NET_SNMP6, 5, "snmp6",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- afinet6_get_snmp
-};
-#endif /* CONFIG_PROC_FS */
-
#ifdef MODULE
int ipv6_unload(void)
{
/* Create /proc/foo6 entries. */
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_raw6);
- proc_net_register(&proc_net_tcp6);
- proc_net_register(&proc_net_udp6);
- proc_net_register(&proc_net_sockstat6);
- proc_net_register(&proc_net_snmp6);
+ proc_net_create("raw6", 0, raw6_get_info);
+ proc_net_create("tcp6", 0, tcp6_get_info);
+ proc_net_create("udp6", 0, udp6_get_info);
+ proc_net_create("sockstat6", 0, afinet6_get_info);
+ proc_net_create("snmp6", 0, afinet6_get_snmp);
#endif
/* Now the userspace is allowed to create INET6 sockets. */
/* First of all disallow new sockets creation. */
sock_unregister(PF_INET6);
#ifdef CONFIG_PROC_FS
- proc_net_unregister(proc_net_raw6.low_ino);
- proc_net_unregister(proc_net_tcp6.low_ino);
- proc_net_unregister(proc_net_udp6.low_ino);
- proc_net_unregister(proc_net_sockstat6.low_ino);
- proc_net_unregister(proc_net_snmp6.low_ino);
+ proc_net_remove("raw6");
+ proc_net_remove("tcp6");
+ proc_net_remove("udp6");
+ proc_net_remove("sockstat6");
+ proc_net_remove("snmp6");
#endif
/* Cleanup code parts. */
sit_cleanup();
void ip6_flowlabel_init()
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
-
init_timer(&ip6_fl_gc_timer);
ip6_fl_gc_timer.function = ip6_fl_gc;
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("net/ip6_flowlabel", 0, 0);
- ent->read_proc = ip6_fl_read_proc;
+ create_proc_read_entry("net/ip6_flowlabel", 0, 0, ip6_fl_read_proc, NULL);
#endif
}
int __init igmp6_init(struct net_proto_family *ops)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
struct sock *sk;
int err;
sk->net_pinfo.af_inet6.hop_limit = 1;
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("net/igmp6", 0, 0);
- ent->read_proc = igmp6_read_proc;
+ create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL);
#endif
return 0;
return len;
}
-struct proc_dir_entry ndisc_proc_entry =
-{
- PROC_NET_NDISC, 5, "ndisc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL,
- &ndisc_get_info
-};
#endif
#endif /* CONFIG_PROC_FS */
-
int __init ndisc_init(struct net_proto_family *ops)
{
struct sock *sk;
#ifdef CONFIG_PROC_FS
#ifndef CONFIG_RTNETLINK
- proc_net_register(&ndisc_proc_entry);
+ proc_net_create("ndisc", 0, ndisc_get_info);
#endif
#endif
#ifdef CONFIG_SYSCTL
{
#ifdef CONFIG_PROC_FS
#ifndef CONFIG_RTNETLINK
- proc_net_unregister(ndisc_proc_entry.low_ino);
+ proc_net_remove("ndisc");
#endif
#endif
neigh_table_clear(&nd_tbl);
return len;
}
-
-static struct proc_dir_entry proc_rt6_info = {
- PROC_NET_RT6, 10, "ipv6_route",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rt6_proc_info
-};
-static struct proc_dir_entry proc_rt6_stats = {
- PROC_NET_RT6_STATS, 9, "rt6_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rt6_proc_stats
-};
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SYSCTL
NULL, NULL);
fib6_init();
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_rt6_info);
- proc_net_register(&proc_rt6_stats);
+ proc_net_create("ipv6_route", 0, rt6_proc_info);
+ proc_net_create("rt6_stats", 0, rt6_proc_stats);
#endif
}
void ip6_route_cleanup(void)
{
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_RT6);
- proc_net_unregister(PROC_NET_RT6_STATS);
+ proc_net_remove("ipv6_route");
+ proc_net_remove("rt6_stats");
#endif
rt6_ifdown(NULL);
extern void destroy_EII_client(struct datalink_proto *);
extern void destroy_8023_client(struct datalink_proto *);
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry ipx_procinfo = {
- PROC_NET_IPX, 3, "ipx", S_IFREG | S_IRUGO,
- 1, 0, 0, 0, &proc_net_inode_operations, ipx_get_info
-};
-
-struct proc_dir_entry ipx_if_procinfo = {
- PROC_NET_IPX_INTERFACE, 13, "ipx_interface", S_IFREG | S_IRUGO,
- 1, 0, 0, 0, &proc_net_inode_operations, ipx_interface_get_info
-};
-
-struct proc_dir_entry ipx_rt_procinfo = {
- PROC_NET_IPX_ROUTE, 9, "ipx_route", S_IFREG | S_IRUGO,
- 1, 0, 0, 0, &proc_net_inode_operations, ipx_rt_get_info
-};
-#endif
-
static unsigned char ipx_8022_type = 0xE0;
static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
register_netdevice_notifier(&ipx_dev_notifier);
#ifdef CONFIG_PROC_FS
- proc_net_register(&ipx_procinfo);
- proc_net_register(&ipx_if_procinfo);
- proc_net_register(&ipx_rt_procinfo);
+ proc_net_create("ipx", 0, ipx_get_info);
+ proc_net_create("ipx_interface", 0, ipx_interface_get_info);
+ proc_net_create("ipx_route", 0, ipx_rt_get_info);
#endif
printk(KERN_INFO "NET4: Linux IPX 0.38 for NET4.0\n");
}
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_IPX_ROUTE);
- proc_net_unregister(PROC_NET_IPX_INTERFACE);
- proc_net_unregister(PROC_NET_IPX);
+ proc_net_remove("ipx_route");
+ proc_net_remove("ipx_interface");
+ proc_net_remove("ipx");
#endif
unregister_netdevice_notifier(&ipx_dev_notifier);
return -ENOMEM;
}
#ifdef CONFIG_PROC_FS
- create_proc_entry("irlan", 0, proc_irda)->get_info = irlan_proc_read;
+ create_proc_info_entry("irlan", 0, proc_irda, irlan_proc_read);
#endif /* CONFIG_PROC_FS */
DEBUG(4, __FUNCTION__ "()\n");
#endif /* MODULE */
for (i=0;i<IRDA_ENTRIES_NUM;i++)
- create_proc_entry(dir[i].name,0,proc_irda)->get_info=dir[i].fn;
+ create_proc_info_entry(dir[i].name,0,proc_irda,dir[i].fn);
}
/*
void netlink_proto_init(struct net_proto *pro)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
struct sk_buff *dummy_skb;
if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) {
}
sock_register(&netlink_family_ops);
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("net/netlink", 0, 0);
- ent->read_proc = netlink_read_proc;
+ create_proc_read_entry("net/netlink", 0, 0, netlink_read_proc, NULL);
#endif
}
0
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_nr = {
- PROC_NET_NR, 2, "nr",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_get_info
-};
-static struct proc_dir_entry proc_net_nr_neigh = {
- PROC_NET_NR_NEIGH, 8, "nr_neigh",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_neigh_get_info
-};
-static struct proc_dir_entry proc_net_nr_nodes = {
- PROC_NET_NR_NODES, 8, "nr_nodes",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- nr_nodes_get_info
-};
-#endif
-
static struct net_device *dev_nr;
void __init nr_proto_init(struct net_proto *pro)
nr_loopback_init();
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_nr);
- proc_net_register(&proc_net_nr_neigh);
- proc_net_register(&proc_net_nr_nodes);
+ proc_net_create("nr", 0, nr_get_info);
+ proc_net_create("nr_neigh", 0, nr_neigh_get_info);
+ proc_net_create("nr_nodes", 0, nr_nodes_get_info);
#endif
}
int i;
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_NR);
- proc_net_unregister(PROC_NET_NR_NEIGH);
- proc_net_unregister(PROC_NET_NR_NODES);
+ proc_net_remove("nr");
+ proc_net_remove("nr_neigh");
+ proc_net_remove("nr_nodes");
#endif
nr_loopback_clear();
0
};
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_rose = {
- PROC_NET_RS, 4, "rose",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rose_get_info
-};
-static struct proc_dir_entry proc_net_rose_neigh = {
- PROC_NET_RS_NEIGH, 10, "rose_neigh",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rose_neigh_get_info
-};
-static struct proc_dir_entry proc_net_rose_nodes = {
- PROC_NET_RS_NODES, 10, "rose_nodes",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rose_nodes_get_info
-};
-static struct proc_dir_entry proc_net_rose_routes = {
- PROC_NET_RS_ROUTES, 11, "rose_routes",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- rose_routes_get_info
-};
-#endif
-
static struct net_device *dev_rose;
void __init rose_proto_init(struct net_proto *pro)
rose_add_loopback_neigh();
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_rose);
- proc_net_register(&proc_net_rose_neigh);
- proc_net_register(&proc_net_rose_nodes);
- proc_net_register(&proc_net_rose_routes);
+ proc_net_create("rose", 0, rose_get_info);
+ proc_net_create("rose_neigh", 0, rose_neigh_get_info);
+ proc_net_create("rose_nodes", 0, rose_nodes_get_info);
+ proc_net_create("rose_routes", 0, rose_routes_get_info);
#endif
}
int i;
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_RS);
- proc_net_unregister(PROC_NET_RS_NEIGH);
- proc_net_unregister(PROC_NET_RS_NODES);
- proc_net_unregister(PROC_NET_RS_ROUTES);
+ proc_net_remove("rose");
+ proc_net_remove("rose_neigh");
+ proc_net_remove("rose_nodes");
+ proc_net_remove("rose_routes");
#endif
rose_loopback_clear();
#ifdef CONFIG_RTNETLINK
struct rtnetlink_link *link_p;
#endif
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
#if PSCHED_CLOCK_SOURCE == PSCHED_CPU
if (psched_calibrate_clock() < 0)
#endif
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("net/psched", 0, 0);
- ent->read_proc = psched_read_proc;
+ create_proc_read_entry("net/psched", 0, 0, psched_read_proc, NULL);
#endif
return 0;
static inline struct proc_dir_entry *
do_register(const char *name, void *data, int issvc)
{
- struct proc_dir_entry *ent;
-
dprintk("RPC: registering /proc/net/rpc/%s\n", name);
- ent = create_proc_entry(name, 0, proc_net_rpc);
- ent->read_proc = issvc? svc_proc_read : rpc_proc_read;
- ent->data = data;
-
- return ent;
+ return create_proc_read_entry(name, 0, proc_net_rpc,
+ issvc? svc_proc_read : rpc_proc_read,
+ data);
}
struct proc_dir_entry *
#endif
{
struct sk_buff *dummy_skb;
- struct proc_dir_entry *ent;
printk(KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n");
if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb))
}
sock_register(&unix_family_ops);
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("net/unix", 0, 0);
- ent->read_proc = unix_read_proc;
+ create_proc_read_entry("net/unix", 0, 0, unix_read_proc, NULL);
#endif
#ifdef MODULE
name_root, /* .name */
0555 | S_IFDIR, /* .mode */
2, /* .nlink */
- 0, /* .uid */
- 0, /* .gid */
- 0, /* .size */
- &proc_dir_inode_operations, /* .ops */
- NULL, /* .get_info */
- NULL, /* .fill_node */
- NULL, /* .next */
- NULL, /* .parent */
- NULL, /* .subdir */
- NULL, /* .data */
};
/*
}
}
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry proc_net_x25 = {
- PROC_NET_X25, 3, "x25",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- x25_get_info
-};
-static struct proc_dir_entry proc_net_x25_routes = {
- PROC_NET_X25_ROUTES, 10, "x25_routes",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- x25_routes_get_info
-};
-#endif
-
void __init x25_proto_init(struct net_proto *pro)
{
sock_register(&x25_family_ops);
#endif
#ifdef CONFIG_PROC_FS
- proc_net_register(&proc_net_x25);
- proc_net_register(&proc_net_x25_routes);
+ proc_net_create("x25", 0, x25_get_info);
+ proc_net_create("x25_routes", 0, x25_routes_get_info);
#endif
}
{
#ifdef CONFIG_PROC_FS
- proc_net_unregister(PROC_NET_X25);
- proc_net_unregister(PROC_NET_X25_ROUTES);
+ proc_net_remove("x25");
+ proc_net_remove("x25_routes");
#endif
x25_link_free();
# define_string define value
#
function define_string () {
- echo "$1="'"'$2'"' >>$CONFIG
- echo "#define $1 "'"'$2'"' >>$CONFIG_H
- eval "$1=$2"
+ echo "$1=\"$2\"" >>$CONFIG
+ echo "#define $1 \"$2\"" >>$CONFIG_H
+ eval "$1=\"$2\""
}
#