If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+AH/ESP match support
+CONFIG_IP_NF_MATCH_AH_ESP
+ These two match extensions (`ah' and `esp') allow you to match a
+ range of SPIs inside AH or ESP headers of IPSec packets.
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
TOS match support
CONFIG_IP_NF_MATCH_TOS
TOS matching allows you to match packets based on the Type Of
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+ULOG target support
+CONFIG_IP_NF_TARGET_ULOG
+ This option adds a `ULOG' target, which allows you to create rules in
+ any iptables table. The packet is passed to a userspace logging
+ daemon using netlink multicast sockets; unlike the LOG target
+ which can only be viewed through syslog.
+
+ The apropriate userspace logging daemon (ulogd) may be obtained from
+ http://www.gnumonks.org/projects/ulogd
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
LOG target support
CONFIG_IP_NF_TARGET_LOG
This option adds a `LOG' target, which allows you to create rules in
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+IPV6 queue handler (EXPERIMENTAL)
+CONFIG_IP6_NF_QUEUE
+
+ This option adds a queue handler to the kernel for IPv6
+ packets which lets us to receive the filtered packets
+ with QUEUE target using libiptc as we can do with
+ the IPv4 now.
+
+ (C) Fernando Anton 2001
+ IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ Universidad Carlos III de Madrid
+ Universidad Politecnica de Alcala de Henares
+ email: fanton@it.uc3m.es
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
Owner match support
CONFIG_IP6_NF_MATCH_OWNER
Packet owner matching allows you to match locally-generated packets
This driver supports the L7200 Color LCD.
Say Y if you want graphics support.
+NeoMagic display support (EXPERIMENTAL)
+CONFIG_FB_NEOMAGIC
+ This driver supports notebooks with NeoMagic PCI chips.
+ Say Y if you have such a graphics card.
+
+ The driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called neofb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
PowerMac "control" frame buffer device support
CONFIG_FB_CONTROL
This driver supports a frame buffer for the graphics adapter in the
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 3
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
/* Startup the timer source. */
alpha_mv.init_rtc();
- do_get_fast_time = do_gettimeofday;
-
/*
* If we had wanted SRM console printk echoing early, undo it now.
*
. = ALIGN(8);
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(2*8192); /* Align double page for init_task_union */
ecard_proc_init();
}
+subsys_initcall(ecard_init);
+
EXPORT_SYMBOL(ecard_startfind);
EXPORT_SYMBOL(ecard_find);
EXPORT_SYMBOL(ecard_readchunk);
*(.setup.init)
__setup_end = .;
__initcall_start = .;
- *(.initcall.init)
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
__initcall_end = .;
. = ALIGN(32768);
__init_end = .;
*(.setup.init)
__setup_end = .;
__initcall_start = .;
- *(.initcall.init)
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
__setup_end = .;
.initcall.init : {
__initcall_start = .;
- *(.initcall.init);
+ *(.initcall1.init);
+ *(.initcall2.init);
+ *(.initcall3.init);
+ *(.initcall4.init);
+ *(.initcall5.init);
+ *(.initcall6.init);
+ *(.initcall7.init);
__initcall_end = .;
/* We fill to the next page, so we can discard all init
#endif
}
+subsys_initcall(mca_init);
+
/*--------------------------------------------------------------------*/
static void mca_handle_nmi_slot(int slot, int check_flag)
#ifndef do_gettimeoffset
do_gettimeoffset = do_fast_gettimeoffset;
#endif
- do_get_fast_time = do_gettimeofday;
/* report CPU clock rate in Hz.
* The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
tv->tv_usec = usec;
}
-/* XXX there should be a cleaner way for declaring an alias... */
-asm (".global get_fast_time; get_fast_time = do_gettimeofday");
-
static void
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
{ *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET)
- { *(.initcall.init) }
+ .initcall.init : AT(ADDR(.initcall1.init) - PAGE_OFFSET)
+ {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(PAGE_SIZE);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(8192);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(8192);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096); /* Align double page for init_task_union */
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096); /* Align double page for init_task_union */
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096); /* Align double page for init_task_union */
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
__init_end = .;
}
}
+subsys_initcall(ppc_init);
+
/* Warning, IO base is not yet inited */
void __init setup_arch(char **cmdline_p)
{
tz.tz_dsttime = 0;
do_sys_settimeofday(NULL, &tz);
}
-
- do_get_fast_time = do_gettimeofday;
}
#define TICK_SIZE tick
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
init_timer_cc -= 0x8126d60e46000000LL -
(0x3c26700LL*1000000*4096);
tod_to_timeval(init_timer_cc, &xtime);
-
- /* Set do_get_fast_time function pointer. */
- do_get_fast_time = do_gettimeofday;
}
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
init_timer_cc -= 0x8126d60e46000000LL -
(0x3c26700LL*1000000*4096);
tod_to_timeval(init_timer_cc, &xtime);
-
- /* Set do_get_fast_time function pointer. */
- do_get_fast_time = do_gettimeofday;
}
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
__machvec_start = .;
.machvec.init : { *(.machvec.init) }
-/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
+/* $Id: pcic.c,v 1.23 2002/01/23 14:33:55 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
unsigned long v;
int timer_irq, irq;
- do_get_fast_time = pci_do_gettimeofday;
/* A hack until do_gettimeofday prototype is moved to arch specific headers
and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
((unsigned int *)do_gettimeofday)[0] =
-/* $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
+/* $Id: process.c,v 1.161 2002/01/23 11:27:32 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-/* $Id: time.c,v 1.59 2001/10/30 04:54:21 davem Exp $
+/* $Id: time.c,v 1.60 2002/01/23 14:33:55 davem Exp $
* linux/arch/sparc/kernel/time.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
struct intersil *iregs;
#endif
- do_get_fast_time = do_gettimeofday;
BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
btfixup();
.setup_init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
# CONFIG_BLK_DEV_IDEDISK_IBM is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
#
# IDE chipset support/bugfixes
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_AEC62XX_TUNING is not set
CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_HPT366 is not set
CONFIG_BLK_DEV_NS87415=y
# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
# CONFIG_BLK_DEV_PDC202XX is not set
# CONFIG_PDC202XX_BURST is not set
# CONFIG_PDC202XX_FORCE is not set
-/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
+/* $Id: pci_psycho.c,v 1.32 2002/01/23 11:27:32 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
/*0x2f*/15, /* Correctable ECC */
/*0x30*/15, /* PCI Bus A Error */
/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/1, /* Power Management */
+/*0x32*/15, /* Power Management */
};
static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = psycho_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
/* Now build the IRQ bucket. */
pil = psycho_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + imap_off;
imap += 4;
-/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
/*0x2f*/15, /* Correctable ECC */
/*0x30*/15, /* PCI Bus A Error */
/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/1, /* Power Management */
+/*0x32*/15, /* Power Management */
};
static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
ret = sabre_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
/* Now build the IRQ bucket. */
pil = sabre_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + imap_off;
imap += 4;
-/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
* pci_schizo.c: SCHIZO specific PCI controller support.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
ret = schizo_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 1;
+ ret = 2;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
break;
default:
- ret = 1;
+ ret = 2;
break;
};
}
/* Now build the IRQ bucket. */
pil = schizo_ino_to_pil(pdev, ino);
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = p->controller_regs + pbm_off + imap_off;
imap += 4;
-/* $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
+/* $Id: process.c,v 1.129 2002/01/23 11:27:32 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
-/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
+/* $Id: sbus.c,v 1.19 2002/01/23 11:27:32 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
/* SBUS SYSIO INO number to Sparc PIL level. */
static unsigned char sysio_ino_to_pil[] = {
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */
+ 0, 2, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */
3, /* Onboard SCSI */
5, /* Onboard Ethernet */
/*XXX*/ 8, /* Onboard BPP */
printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
panic("Bad SYSIO IRQ translations...");
}
+
+ if (PIL_RESERVED(pil))
+ BUG();
+
imap = sysio_irq_offsets[ino];
if (imap == ((unsigned long)-1)) {
prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
+ init_idle();
+
while (!smp_threads_ready)
membar("#LoadLoad");
- init_idle();
+ idle_startup_done();
}
void cpu_panic(void)
}
}
+/* Process migration IPIs. */
+
+extern unsigned long xcall_migrate_task;
+
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+void smp_migrate_task(int cpu, task_t *p)
+{
+ unsigned long mask = 1UL << cpu;
+
+ if (cpu == smp_processor_id())
+ return;
+
+ if (smp_processors_ready && (cpu_present_map & mask) != 0) {
+ u64 data0 = (((u64)&xcall_migrate_task) & 0xffffffff);
+
+ spin_lock(&migration_lock);
+ new_task = p;
+
+ if (tlb_type == spitfire)
+ spitfire_xcall_deliver(data0, 0, 0, mask);
+ else
+ cheetah_xcall_deliver(data0, 0, 0, mask);
+ }
+}
+
+/* Called at PIL level 1. */
+asmlinkage void smp_task_migration_interrupt(int irq, struct pt_regs *regs)
+{
+ task_t *p;
+
+ if (irq != PIL_MIGRATE)
+ BUG();
+
+ clear_softint(1 << irq);
+
+ p = new_task;
+ spin_unlock(&migration_lock);
+ sched_task_migrated(p);
+}
+
/* CPU capture. */
/* #define CAPTURE_DEBUG */
extern unsigned long xcall_capture;
-/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
+/* $Id: time.c,v 1.42 2002/01/23 14:33:55 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#endif
u8 tmp;
- do_get_fast_time = do_gettimeofday;
-
if (!mregs && !dregs) {
prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
-/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
+/* $Id: ttable.S,v 1.37 2002/01/23 11:27:32 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
*
* Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
tl0_privact: TRAP_NOSAVE(__do_privact)
tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2)
+#ifdef CONFIG_SMP
+tl0_irq1: TRAP_IRQ(smp_task_migration_interrupt, 1)
+#else
+tl0_irq1: BTRAP(0x41)
+#endif
+tl0_irq2: TRAP_IRQ(handler_irq, 2)
tl0_irq3: TRAP_IRQ(handler_irq, 3) TRAP_IRQ(handler_irq, 4)
tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
-/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
+/* $Id: ultra.S,v 1.71 2002/01/23 11:27:36 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
#include <asm/page.h>
#include <asm/spitfire.h>
#include <asm/mmu_context.h>
+#include <asm/pil.h>
/* Basically, all this madness has to do with the
* fact that Cheetah does not support IMMU flushes
b,pt %xcc, rtrap
clr %l6
+ .globl xcall_migrate_task
+xcall_migrate_task:
+ mov 1, %g2
+ sllx %g2, (PIL_MIGRATE), %g2
+ wr %g2, 0x0, %set_softint
+ retry
+
#endif /* CONFIG_SMP */
.setup_init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : { *(.initcall.init) }
+ .initcall.init : {
+ *(.initcall1.init)
+ *(.initcall2.init)
+ *(.initcall3.init)
+ *(.initcall4.init)
+ *(.initcall5.init)
+ *(.initcall6.init)
+ *(.initcall7.init)
+ }
__initcall_end = .;
. = ALIGN(8192);
__init_end = .;
#endif
#ifdef IFORCE_USB
struct usb_device *usbdev; /* USB transfer */
- struct urb irq, out, ctrl;
+ struct urb *irq, *out, *ctrl;
struct usb_ctrlrequest dr;
#endif
/* Force Feedback */
DECLARE_WAITQUEUE(wait, current);
int timeout = HZ; /* 1 second */
- memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));
- ((char*)iforce->out.transfer_buffer)[0] = HI(cmd);
- iforce->out.transfer_buffer_length = LO(cmd) + 2;
- iforce->out.dev = iforce->usbdev;
+ memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+ ((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+ iforce->out->transfer_buffer_length = LO(cmd) + 2;
+ iforce->out->dev = iforce->usbdev;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
- if (usb_submit_urb(&iforce->out)) {
+ if (usb_submit_urb(iforce->out)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return;
}
- while (timeout && iforce->out.status == -EINPROGRESS)
+ while (timeout && iforce->out->status == -EINPROGRESS)
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
if (!timeout)
- usb_unlink_urb(&iforce->out);
+ usb_unlink_urb(iforce->out);
return;
}
case IFORCE_USB:
iforce->dr.bRequest = packet[0];
- iforce->ctrl.dev = iforce->usbdev;
+ iforce->ctrl->dev = iforce->usbdev;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
- if (usb_submit_urb(&iforce->ctrl)) {
+ if (usb_submit_urb(iforce->ctrl)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1;
}
- while (timeout && iforce->ctrl.status == -EINPROGRESS)
+ while (timeout && iforce->ctrl->status == -EINPROGRESS)
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
if (!timeout) {
- usb_unlink_urb(&iforce->ctrl);
+ usb_unlink_urb(iforce->ctrl);
return -1;
}
case IFORCE_USB:
if (iforce->open++)
break;
- iforce->irq.dev = iforce->usbdev;
- if (usb_submit_urb(&iforce->irq))
+ iforce->irq->dev = iforce->usbdev;
+ if (usb_submit_urb(iforce->irq))
return -EIO;
break;
#endif
#ifdef IFORCE_USB
case IFORCE_USB:
if (!--iforce->open)
- usb_unlink_urb(&iforce->irq);
+ usb_unlink_urb(iforce->irq);
break;
#endif
}
if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
memset(iforce, 0, sizeof(struct iforce));
+ iforce->irq = usb_alloc_urb(0);
+ if (!iforce->irq) {
+ kfree(iforce);
+ return NULL;
+ }
+ iforce->out = usb_alloc_urb(0);
+ if (!iforce->out) {
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+ return NULL;
+ }
+ iforce->ctrl = usb_alloc_urb(0);
+ if (!iforce->ctrl) {
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+ return NULL;
+ }
+
iforce->bus = IFORCE_USB;
iforce->usbdev = dev;
iforce->dr.wIndex = 0;
iforce->dr.wLength = 16;
- FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+ FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
- FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+ FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
iforce + 1, 32, iforce_usb_out, iforce);
- FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+ FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
if (iforce_init_device(iforce)) {
+ usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
kfree(iforce);
return NULL;
}
static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
{
struct iforce *iforce = ptr;
- usb_unlink_urb(&iforce->irq);
+ usb_unlink_urb(iforce->irq);
input_unregister_device(&iforce->dev);
+ usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
kfree(iforce);
}
}
}
+subsys_initcall(dio_init);
+
/* Bear in mind that this is called in the very early stages of initialisation
* in order to get the virtual address of the serial port for the console...
*/
if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
reset_ir_status(d, i);
d->buffer_status[i] = VIDEO1394_BUFFER_READY;
- get_fast_time(&d->buffer_time[i]);
+ do_gettimeofday(&d->buffer_time[i]);
}
}
spin_unlock(&d->lock);
while (list) {
- get_fast_time(&list->buffer[list->head].time);
+ do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type;
list->buffer[list->head].code = code;
list->buffer[list->head].value = value;
}
frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
gbuf = &zr->jpg_gbuf[frame];
- get_fast_time(&gbuf->bs.timestamp);
+ do_gettimeofday(&gbuf->bs.timestamp);
if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
if (mtt)
{
/* Check how much time we have used already */
- get_fast_time(&self->now);
+ do_gettimeofday(&self->now);
diff = self->now.tv_usec - self->stamp.tv_usec;
/* self->stamp is set from ali_ircc_dma_receive_complete() */
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- get_fast_time(&self->stamp);
+ do_gettimeofday(&self->stamp);
skb = dev_alloc_skb(len+1);
if (skb == NULL)
mtt = irda_get_mtt(skb);
if (mtt) {
int diff;
- get_fast_time(&self->now);
+ do_gettimeofday(&self->now);
diff = self->now.tv_usec - self->stamp.tv_usec;
#ifdef IU_USB_MIN_RTT
/* Factor in USB delays -> Get rid of udelay() that
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- get_fast_time(&self->stamp);
+ do_gettimeofday(&self->stamp);
/* Fix skb, and remove USB-IrDA header */
skb_put(skb, urb->actual_length);
mtt = irda_get_mtt(skb);
if (mtt) {
/* Check how much time we have used already */
- get_fast_time(&self->now);
+ do_gettimeofday(&self->now);
diff = self->now.tv_usec - self->stamp.tv_usec;
if (diff < 0)
diff += 1000000;
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- get_fast_time(&self->stamp);
+ do_gettimeofday(&self->stamp);
skb = dev_alloc_skb(len+1);
if (skb == NULL) {
-/* $Id: sungem.c,v 1.48 2002/01/15 06:26:37 davem Exp $
+/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
* - Get rid of all those nasty mdelay's and replace them
* with schedule_timeout.
* - Implement WOL
+ * - Currently, forced Gb mode is only supported on bcm54xx
+ * PHY for which I use the SPD2 bit of the control register.
+ * On m1011 PHY, I can't force as I don't have the specs, but
+ * I can at least detect gigabit with autoneg.
*/
#include <linux/module.h>
BMCR_ANENABLE, /* 0 : autoneg */
0, /* 1 : 10bt half duplex */
BMCR_SPEED100, /* 2 : 100bt half duplex */
- BMCR_SPD2, /* verify this */ /* 3 : 1000bt half duplex */
+ BMCR_SPD2, /* bcm54xx only */ /* 3 : 1000bt half duplex */
BMCR_FULLDPLX, /* 4 : 10bt full duplex */
BMCR_SPEED100|BMCR_FULLDPLX, /* 5 : 100bt full duplex */
BMCR_SPD2|BMCR_FULLDPLX /* 6 : 1000bt full duplex */
*fd = 1;
if (val & (LPA_100FULL | LPA_100HALF))
*spd = 100;
+
+ if (gp->phy_mod == phymod_m1011) {
+ val = phy_read(gp, 0x0a);
+ if (val & 0xc00)
+ *spd = 1000;
+ if (val & 0x800)
+ *fd = 1;
+ }
}
}
gem_init_bcm5411_phy(gp);
gp->gigabit_capable = 1;
break;
+ case 0x1410c60:
+ printk("M1011 (Marvel ?)\n");
+ gp->phy_mod = phymod_m1011;
+ gp->gigabit_capable = 1;
+ break;
case 0x18074c0:
printk("Lucent\n");
break;
default:
- printk("Unknown\n");
+ printk("Unknown (Using generic mode)\n");
gp->phy_mod = phymod_generic;
break;
};
writel(val, gp->regs + PCS_SCTRL);
gp->gigabit_capable = 1;
}
+
+ /* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
+ if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
+ gp->phy_mod != phymod_bcm5411)
+ gp->link_cntl &= ~BMCR_SPD2;
+
}
static void gem_init_dma(struct gem *gp)
u32 mif_cfg;
/* On Apple's sungem, we can't rely on registers as the chip
- * was been powered down by the firmware. We do the PHY lookup
- * when the interface is opened and we configure the driver
- * with known values.
+ * was been powered down by the firmware. The PHY is looked
+ * up later on.
*/
if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
gp->phy_type = phy_mii_mdio0;
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
- udelay(100);
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout((21 * HZ) / 1000);
pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
#endif
phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
- }
+ } else if (gp->phy_mod == phymod_m1011)
+ phy_write(gp, MII_BMCR, BMCR_PDOWN);
/* According to Apple, we must set the MDIO pins to this begnign
* state or we may 1) eat more current, 2) damage some PHYs
-/* $Id: sungem.h,v 1.11 2002/01/12 07:19:55 davem Exp $
+/* $Id: sungem.h,v 1.12 2002/01/23 15:40:45 davem Exp $
* sungem.h: Definitions for Sun GEM ethernet driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
phymod_bcm5400,
phymod_bcm5401,
phymod_bcm5411,
+ phymod_m1011,
};
enum link_state {
nubus_proc_init();
#endif
}
+
+subsys_initcall(nubus_init);
memset(b, 0, sizeof(*b));
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
+ iobus_init(&b->iobus);
}
return b;
}
child->ops = parent->ops;
child->sysdata = parent->sysdata;
+ /* init generic fields */
+ child->iobus.self = &dev->dev;
+ child->iobus.parent = &parent->iobus;
+ dev->dev.subordinate = &child->iobus;
+
+ strcpy(child->iobus.name,dev->dev.name);
+
/*
* Set up the primary, secondary and subordinate
* bus numbers.
pci_write_config_word(dev, PCI_COMMAND, cr);
}
sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
return max;
}
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
+ /* make sure generic fields are setup properly */
+ device_init_dev(&dev->dev);
+
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
dev->dma_mask = 0xffffffff;
if (pci_setup_device(dev) < 0) {
kfree(dev);
- dev = NULL;
+ return NULL;
}
+
+ /* now put in global tree */
+ strcpy(dev->dev.name,dev->name);
+ strcpy(dev->dev.bus_id,dev->slot_name);
+
+ device_register(&dev->dev);
return dev;
}
DBG("Scanning bus %02x\n", bus->number);
max = bus->secondary;
+ /* we should know for sure what the bus number is, so set the bus ID
+ * for the bus and make sure it's registered in the device tree */
+ sprintf(bus->iobus.bus_id,"pci%d",bus->number);
+ iobus_register(&bus->iobus);
+
/* Create a device template */
memset(&dev0, 0, sizeof(dev0));
+ device_init_dev(&dev0.dev);
dev0.bus = bus;
dev0.sysdata = bus->sysdata;
+ dev0.dev.parent = &bus->iobus;
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8) {
}
b = pci_alloc_bus();
+ if (!b)
+ return NULL;
list_add_tail(&b->node, &pci_root_buses);
+ sprintf(b->iobus.bus_id,"pci%d",bus);
+ strcpy(b->iobus.name,"Host/PCI Bridge");
+ iobus_register(&b->iobus);
+
b->number = b->secondary = bus;
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
}
-void __devinit pci_init(void)
+static int __devinit pci_init(void)
{
struct pci_dev *dev;
#ifdef CONFIG_PM
pm_register(PM_PCI_DEV, 0, pci_pm_callback);
#endif
+ return 0;
}
static int __devinit pci_setup(char *str)
return 1;
}
+subsys_initcall(pci_init);
+
__setup("pci=", pci_setup);
EXPORT_SYMBOL(pci_read_config_byte);
return 0;
}
-#ifdef MODULE
+late_initcall(init_pcmcia_ds);
-int __init init_module(void)
-{
- return init_pcmcia_ds();
-}
+#ifdef MODULE
void __exit cleanup_module(void)
{
return 0;
}
-#ifdef MODULE
+subsys_initcall(isapnp_init);
-int init_module(void)
-{
- return isapnp_init();
-}
+#ifdef MODULE
void cleanup_module(void)
{
}
#endif
}
+
+subsys_initcall(sbus_init);
The driver is currently maintained by Kai M{kisara (email
Kai.Makisara@metla.fi)
-Last modified: Thu Nov 1 22:41:59 2001 by makisara@kai.makisara.local
+Last modified: Tue Jan 22 21:08:57 2002 by makisara
BASICS
The compile options are defined in the file linux/drivers/scsi/st_options.h.
+4. If the open option O_NONBLOCK is used, open succeeds even if the
+drive is not ready. If O_NONBLOCK is not used, the driver waits for
+the drive to become ready. If this does not happen in ST_BLOCK_SECONDS
+seconds, open fails with the errno value EIO.
+
BSD AND SYS V SEMANTICS
0xffffff means that the default is not used any more.
MT_ST_DEF_DENSITY
MT_ST_DEF_DRVBUFFER
+ Used to set or clear the density (8 bits), and drive buffer
+ state (3 bits). If the value is MT_ST_CLEAR_DEFAULT
+ (0xfffff) the default will not be used any more. Otherwise
+ the lowermost bits of the value contain the new value of
+ the parameter.
MT_ST_DEF_COMPRESSION
- Used to set or clear the density (8 bits), drive buffer
- state (3 bits), and compression (single bit). If the value is
- MT_ST_CLEAR_DEFAULT (0xfffff), the default will not be used
- any more. Otherwise the lower-most bits of the value contain
- the new value of the parameter.
+ The compression default will not be used if the value of
+ the lowermost byte is 0xff. Otherwise the lowermost bit
+ contains the new default. If the bits 8-15 are set to a
+ non-zero number, and this number is not 0xff, the number is
+ used as the compression algorithm. The value
+ MT_ST_CLEAR_DEFAULT can be used to clear the compression
+ default.
MT_ST_SET_TIMEOUT
Set the normal timeout in seconds for this device. The
default is 900 seconds (15 minutes). The timeout should be
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2001 Kai Makisara
+ Copyright 1992 - 2002 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sat Nov 3 19:30:55 2001 by makisara@kai.makisara.local
+ Last modified: Wed Jan 23 20:22:42 2002 by makisara
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
-
- Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI
- error handling will be discarded.
*/
-static char *verstr = "20011103";
+static char *verstr = "20020123";
#include <linux/module.h>
static int append_to_buffer(const char *, ST_buffer *, int);
static int from_buffer(ST_buffer *, char *, int);
-static int st_init(void);
static int st_attach(Scsi_Device *);
static int st_detect(Scsi_Device *);
static void st_detach(Scsi_Device *);
-static struct Scsi_Device_Template st_template =
-{
- name:"tape",
- tag:"st",
- scsi_type:TYPE_TAPE,
- major:SCSI_TAPE_MAJOR,
- detect:st_detect,
- init:st_init,
- attach:st_attach,
- detach:st_detach
+static struct Scsi_Device_Template st_template = {
+ module: THIS_MODULE,
+ name: "tape",
+ tag: "st",
+ scsi_type: TYPE_TAPE,
+ major: SCSI_TAPE_MAJOR,
+ detect: st_detect,
+ attach: st_attach,
+ detach: st_detach
};
static int st_compression(Scsi_Tape *, int);
return 0;
}
- if (driver_byte(result) & DRIVER_SENSE)
+ if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
scode = sense[2] & 0x0f;
else {
sense[0] = 0;
return 0;
}
\f
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+ error code. */
+#define CHKRES_READY 0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY 2
+#define CHKRES_NO_TAPE 3
+
+#define MAX_ATTENTIONS 10
+
+static int test_ready(Scsi_Tape *STp, int do_wait)
+{
+ int attentions, waits, max_wait, scode;
+ int retval = CHKRES_READY, new_session = FALSE;
+ unsigned char cmd[MAX_COMMAND_SIZE];
+ Scsi_Request *SRpnt = NULL;
+
+ max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+ for (attentions=waits=0; ; ) {
+ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+ cmd[0] = TEST_UNIT_READY;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+ STp->long_timeout, MAX_READY_RETRIES, TRUE);
+
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ break;
+ }
+
+ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+
+ scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+
+ if (scode == UNIT_ATTENTION) { /* New media? */
+ new_session = TRUE;
+ if (attentions < MAX_ATTENTIONS) {
+ attentions++;
+ continue;
+ }
+ else {
+ retval = (-EIO);
+ break;
+ }
+ }
+
+ if (scode == NOT_READY) {
+ if (waits < max_wait) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ if (signal_pending(current)) {
+ retval = (-EINTR);
+ break;
+ }
+ waits++;
+ continue;
+ }
+ else {
+ if ((STp->device)->scsi_level >= SCSI_2 &&
+ SRpnt->sr_sense_buffer[12] == 0x3a) /* Check ASC */
+ retval = CHKRES_NO_TAPE;
+ else
+ retval = CHKRES_NOT_READY;
+ break;
+ }
+ }
+ }
+
+ retval = (STp->buffer)->syscall_result;
+ if (!retval)
+ retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+ break;
+ }
+
+ if (SRpnt != NULL)
+ scsi_release_request(SRpnt);
+ return retval;
+}
+
+
/* See if the drive is ready and gather information about the tape. Return values:
< 0 negative error code from errno.h
0 drive ready
1 drive not ready (possibly no tape)
*/
-#define CHKRES_READY 0
-#define CHKRES_NOT_READY 1
-
static int check_tape(Scsi_Tape *STp, struct file *filp)
{
- int i, retval, new_session = FALSE;
+ int i, retval, new_session = FALSE, do_wait;
unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
unsigned short st_flags = filp->f_flags;
- Scsi_Request *SRpnt;
+ Scsi_Request *SRpnt = NULL;
ST_mode *STm;
ST_partstat *STps;
int dev = TAPE_NR(STp->devt);
}
STm = &(STp->modes[STp->current_mode]);
- memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
saved_cleaning = STp->cleaning_req;
STp->cleaning_req = 0;
- SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
- MAX_READY_RETRIES, TRUE);
- if (!SRpnt) {
- retval = (STp->buffer)->syscall_result;
- goto err_out;
- }
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+ do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
+ retval = test_ready(STp, do_wait);
- /* Flush the queued UNIT ATTENTION sense data */
- for (i=0; i < 10; i++) {
- memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
- SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
- STp->long_timeout, MAX_READY_RETRIES, TRUE);
- if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
- (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
- break;
- }
+ if (retval < 0)
+ goto err_out;
+ if (retval == CHKRES_NEW_SESSION) {
(STp->device)->was_reset = 0;
STp->partition = STp->new_partition = 0;
if (STp->can_partitions)
}
new_session = TRUE;
}
- else
+ else {
STp->cleaning_req |= saved_cleaning;
- if ((STp->buffer)->syscall_result != 0) {
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
- (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
- SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
- STp->ready = ST_NO_TAPE;
- } else
- STp->ready = ST_NOT_READY;
- scsi_release_request(SRpnt);
- SRpnt = NULL;
- STp->density = 0; /* Clear the erroneous "residue" */
- STp->write_prot = 0;
- STp->block_size = 0;
- STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
- STp->partition = STp->new_partition = 0;
- STp->door_locked = ST_UNLOCKED;
- return CHKRES_NOT_READY;
+ if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+ if (retval == CHKRES_NO_TAPE)
+ STp->ready = ST_NO_TAPE;
+ else
+ STp->ready = ST_NOT_READY;
+
+ STp->density = 0; /* Clear the erroneous "residue" */
+ STp->write_prot = 0;
+ STp->block_size = 0;
+ STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+ STp->partition = STp->new_partition = 0;
+ STp->door_locked = ST_UNLOCKED;
+ return CHKRES_NOT_READY;
+ }
}
if (STp->omit_blklims)
SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
MAX_READY_RETRIES, TRUE);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ goto err_out;
+ }
if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
STp->max_block = ((STp->buffer)->b_data[1] << 16) |
SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
MAX_READY_RETRIES, TRUE);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
+ goto err_out;
+ }
if ((STp->buffer)->syscall_result != 0) {
DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
Scsi_Tape *STp;
ST_partstat *STps;
int dev = TAPE_NR(inode->i_rdev);
- unsigned long flags;
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
STp = scsi_tapes[dev];
if (dev >= st_template.dev_max || STp == NULL) {
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
return (-ENXIO);
}
if (STp->in_use) {
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
return (-EBUSY);
}
STp->in_use = 1;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0;
if (STp->device->host->hostt->module)
/* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma;
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
for (i = 0; i < st_nbr_buffers; i++)
if (!st_buffers[i]->in_use &&
(!need_dma_buffer || st_buffers[i]->dma)) {
(STp->buffer)->in_use = 1;
break;
}
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
if (i >= st_nbr_buffers) {
STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE);
if (STp->buffer == NULL) {
retval = check_tape(STp, filp);
if (retval < 0)
goto err_out;
+ if ((filp->f_flags & O_NONBLOCK) == 0 &&
+ retval != CHKRES_READY) {
+ retval = (-EIO);
+ goto err_out;
+ }
return 0;
err_out:
{
int result = 0;
Scsi_Tape *STp;
- unsigned long flags;
kdev_t devt = inode->i_rdev;
int dev;
if (STp->buffer != NULL) {
normalize_buffer(STp->buffer);
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
(STp->buffer)->in_use = 0;
STp->buffer = NULL;
}
else {
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
}
STp->in_use = 0;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
STp->device->access_count--;
if (STp->device->host->hostt->module)
__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
STm->default_blksize = value;
printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
dev, STm->default_blksize);
+ if (STp->ready == ST_READY) {
+ STp->blksize_changed = FALSE;
+ set_mode_densblk(STp, STm);
+ }
}
} else if (code == MT_ST_TIMEOUTS) {
value = (options & ~MT_ST_OPTIONS);
STm->default_density = value & 0xff;
printk(KERN_INFO "st%d: Density default set to %x\n",
dev, STm->default_density);
+ if (STp->ready == ST_READY) {
+ STp->density_changed = FALSE;
+ set_mode_densblk(STp, STm);
+ }
}
} else if (code == MT_ST_DEF_DRVBUFFER) {
if (value == MT_ST_CLEAR_DEFAULT) {
printk(KERN_INFO
"st%d: Drive buffer default set to %x\n",
dev, STp->default_drvbuffer);
+ if (STp->ready == ST_READY)
+ st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
}
} else if (code == MT_ST_DEF_COMPRESSION) {
if (value == MT_ST_CLEAR_DEFAULT) {
printk(KERN_INFO
"st%d: Compression default disabled.\n", dev);
} else {
- STm->default_compression = (value & 1 ? ST_YES : ST_NO);
- printk(KERN_INFO "st%d: Compression default set to %x\n",
- dev, (value & 1));
+ if ((value & 0xff00) != 0) {
+ STp->c_algo = (value & 0xff00) >> 8;
+ printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n",
+ dev, STp->c_algo);
+ }
+ if ((value & 0xff) != 0xff) {
+ STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+ printk(KERN_INFO "st%d: Compression default set to %x\n",
+ dev, (value & 1));
+ if (STp->ready == ST_READY) {
+ STp->compression_changed = FALSE;
+ st_compression(STp, (STm->default_compression == ST_YES));
+ }
+ }
}
}
} else
#define COMPRESSION_PAGE_LENGTH 16
#define CP_OFF_DCE_DCC 2
+#define CP_OFF_C_ALGO 7
#define DCE_MASK 0x80
#define DCC_MASK 0x40
(b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
/* Check if compression can be changed */
- if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
+ if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
return (-EIO);
}
/* Do the change */
- if (state)
+ if (state) {
b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
- else
+ if (STp->c_algo != 0)
+ b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
+ }
+ else {
b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
+ if (STp->c_algo != 0)
+ b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
+ }
retval = write_mode_page(STp, COMPRESSION_PAGE);
if (retval) {
*/
if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
&& load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
- DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+ DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n",
dev, (cmd[4]) ? "" : "un",
load_code - MT_ST_HPLOADER_OFFSET));
cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
if (!load_code)
STp->rew_at_close = 0;
- else
+ else {
STp->rew_at_close = STp->autorew_dev;
-
- retval = check_tape(STp, filp);
- if (retval > 0)
- retval = 0;
+ retval = check_tape(STp, filp);
+ if (retval > 0)
+ retval = 0;
+ }
}
else {
STps = &(STp->ps[STp->partition]);
new_tape_buffer(int from_initialization, int need_dma, int in_use)
{
int i, priority, b_size, order, got = 0, segs = 0;
- unsigned long flags;
ST_buffer *tb;
read_lock(&st_dev_arr_lock);
tb->buffer_size = got;
tb->writing = 0;
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
st_buffers[st_nbr_buffers++] = tb;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
return tb;
}
ST_mode *STm;
ST_partstat *STps;
int i, mode, target_nbr, dev_num;
- unsigned long flags = 0;
char *stp;
if (SDp->type != TYPE_TAPE)
return 1;
}
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
if (st_template.nr_dev >= st_template.dev_max) {
Scsi_Tape **tmp_da;
ST_buffer **tmp_ba;
tmp_dev_max = ST_MAX_TAPES;
if (tmp_dev_max <= st_template.nr_dev) {
SDp->attached--;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
ST_MAX_TAPES);
return 1;
if (tmp_ba != NULL)
kfree(tmp_ba);
SDp->attached--;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't extend device array.\n");
return 1;
}
tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
if (tpnt == NULL) {
SDp->attached--;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't allocate device descriptor.\n");
return 1;
}
init_MUTEX(&tpnt->lock);
st_template.nr_dev++;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
printk(KERN_WARNING
"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
return 1;
}
-static int st_registered = 0;
-
-/* Driver initialization (not __init because may be called later) */
-static int st_init()
-{
- unsigned long flags;
-
- if (st_template.dev_noticed == 0 || st_registered)
- return 0;
-
- printk(KERN_INFO
- "st: Version %s, bufsize %d, wrt %d, max init. bufs %d, s/g segs %d\n",
- verstr, st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
-
- write_lock_irqsave(&st_dev_arr_lock, flags);
- if (!st_registered) {
- if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
- printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
- MAJOR_NR);
- return 1;
- }
- st_registered++;
- }
-
- st_template.dev_max = 0;
- st_nbr_buffers = 0;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
-
- return 0;
-}
-
static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape *tpnt;
int i, mode;
- unsigned long flags;
- write_lock_irqsave(&st_dev_arr_lock, flags);
+ write_lock(&st_dev_arr_lock);
for (i = 0; i < st_template.dev_max; i++) {
tpnt = scsi_tapes[i];
if (tpnt != NULL && tpnt->device == SDp) {
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
return;
}
}
- write_unlock_irqrestore(&st_dev_arr_lock, flags);
+ write_unlock(&st_dev_arr_lock);
return;
}
-
static int __init init_st(void)
{
validate_options();
- st_template.module = THIS_MODULE;
- return scsi_register_device(&st_template);
+ printk(KERN_INFO
+ "st: Version %s, bufsize %d, wrt %d, "
+ "max init. bufs %d, s/g segs %d\n",
+ verstr, st_buffer_size, st_write_threshold,
+ st_max_buffers, st_max_sg_segs);
+
+ if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
+ return scsi_register_device(&st_template);
+
+ printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+ return 1;
}
static void __exit exit_st(void)
scsi_unregister_device(&st_template);
devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
- st_registered--;
if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i)
if (scsi_tapes[i])
unsigned char cln_sense_value;
unsigned char cln_sense_mask;
unsigned char use_pf; /* Set Page Format bit in all mode selects? */
+ unsigned char c_algo; /* compression algorithm */
int tape_type;
int write_threshold;
int timeout; /* timeout for normal commands */
Copyright 1995-2000 Kai Makisara.
- Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
+ Last modified: Tue Jan 22 21:52:34 2002 by makisara
*/
#ifndef _ST_OPTIONS_H
The default is BSD semantics. */
#define ST_SYSV 0
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS 120
#endif
static int cm_open_mixdev(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct cm_state *s = devs;
while (s && s->dev_mixer != minor)
static int cm_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct cm_state *s = devs;
unsigned char fmtm = ~0, fmts = 0;
static int cm_midi_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct cm_state *s = devs;
unsigned long flags;
static int cm_dmfm_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
struct cm_state *s = devs;
while (s && s->dev_dmfm != minor)
struct cm_state *s;
mm_segment_t fs;
int i, val;
+#if defined(CONFIG_SOUND_CMPCI_MIDI) || defined(CONFIG_SOUND_CMPCI_FM)
unsigned char reg_mask = 0;
+#endif
struct {
unsigned short deviceid;
char *devicename;
u32 lpfK = ymfpci_calc_lpfK(rate);
ymfpci_playback_bank_t *bank;
int nbank;
- unsigned le_0x40000000 = cpu_to_le32(0x40000000);
+
+ /*
+ * The gain is a floating point number. According to the manual,
+ * bit 31 indicates a sign bit, bit 30 indicates an integer part,
+ * and bits [29:15] indicate a decimal fraction part. Thus,
+ * for a gain of 1.0 the constant of 0x40000000 is loaded.
+ */
+ unsigned default_gain = cpu_to_le32(0x40000000);
format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
if (stereo)
bank->loop_start = 0;
bank->loop_end = cpu_to_le32(end);
bank->loop_frac = 0;
- bank->eg_gain_end = le_0x40000000;
+ bank->eg_gain_end = default_gain;
bank->lpfQ = cpu_to_le32(lpfQ);
bank->status = 0;
bank->num_of_frames = 0;
bank->delta_end = cpu_to_le32(delta);
bank->lpfK =
bank->lpfK_end = cpu_to_le32(lpfK);
- bank->eg_gain = le_0x40000000;
+ bank->eg_gain = default_gain;
bank->lpfD1 =
bank->lpfD2 = 0;
bank->left_gain =
bank->right_gain =
bank->left_gain_end =
- bank->right_gain_end = le_0x40000000;
+ bank->right_gain_end = default_gain;
} else {
bank->eff2_gain =
bank->eff2_gain_end =
bank->eff3_gain =
- bank->eff3_gain_end = le_0x40000000;
+ bank->eff3_gain_end = default_gain;
}
} else {
if (!spdif) {
if ((voice->number & 1) == 0) {
bank->left_gain =
- bank->left_gain_end = le_0x40000000;
+ bank->left_gain_end = default_gain;
} else {
bank->format |= cpu_to_le32(1);
bank->right_gain =
- bank->right_gain_end = le_0x40000000;
+ bank->right_gain_end = default_gain;
}
} else {
if ((voice->number & 1) == 0) {
bank->eff2_gain =
- bank->eff2_gain_end = le_0x40000000;
+ bank->eff2_gain_end = default_gain;
} else {
bank->format |= cpu_to_le32(1);
bank->eff3_gain =
- bank->eff3_gain_end = le_0x40000000;
+ bank->eff3_gain_end = default_gain;
}
}
}
}
}
+subsys_initcall(tc_init);
+
EXPORT_SYMBOL(search_tc_card);
EXPORT_SYMBOL(claim_tc_card);
EXPORT_SYMBOL(release_tc_card);
goon:
// Prep the USB to wait for another frame
- FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb,
+ FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
ether_dev->rx_buff, ether_dev->wMaxSegmentSize,
read_bulk_callback, ether_dev );
// Give this to the USB subsystem so it can tell us
// when more data arrives.
- if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) {
+ if ( (res = usb_submit_urb(ether_dev->rx_urb)) ) {
warn( __FUNCTION__ " failed submint rx_urb %d", res);
}
warn("%s: Tx timed out.", net->name);
// Tear the waiting frame off the list
- ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
- usb_unlink_urb( ðer_dev->tx_urb );
+ ether_dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb( ether_dev->tx_urb );
// Update statistics
ether_dev->stats.tx_errors++;
memcpy(ether_dev->tx_buff, skb->data, skb->len);
// Fill in the URB for shipping it out.
- FILL_BULK_URB( ðer_dev->tx_urb, ether_dev->usb,
+ FILL_BULK_URB( ether_dev->tx_urb, ether_dev->usb,
usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
ether_dev->tx_buff, ether_dev->wMaxSegmentSize,
write_bulk_callback, ether_dev );
// Tell the URB how much it will be transporting today
- ether_dev->tx_urb.transfer_buffer_length = count;
+ ether_dev->tx_urb->transfer_buffer_length = count;
// Send the URB on its merry way.
- if ((res = usb_submit_urb(ðer_dev->tx_urb))) {
+ if ((res = usb_submit_urb(ether_dev->tx_urb))) {
// Hmm... It didn't go. Tell someone...
warn("failed tx_urb %d", res);
// update some stats...
}
// Prep a receive URB
- FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb,
+ FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
ether_dev->rx_buff, ether_dev->wMaxSegmentSize,
read_bulk_callback, ether_dev );
// Put it out there so the device can send us stuff
- if ( (res = usb_submit_urb(ðer_dev->rx_urb)) )
+ if ( (res = usb_submit_urb(ether_dev->rx_urb)) )
{
// Hmm... Okay...
warn( __FUNCTION__ " failed rx_urb %d", res );
}
// We don't need the URBs anymore.
- usb_unlink_urb( ðer_dev->rx_urb );
- usb_unlink_urb( ðer_dev->tx_urb );
- usb_unlink_urb( ðer_dev->intr_urb );
+ usb_unlink_urb( ether_dev->rx_urb );
+ usb_unlink_urb( ether_dev->tx_urb );
+ usb_unlink_urb( ether_dev->intr_urb );
// That's it. I'm done.
return 0;
// Zero everything out.
memset(ether_dev, 0, sizeof(ether_dev_t));
+ ether_dev->rx_urb = usb_alloc_urb(0);
+ if (!ether_dev->rx_urb) {
+ kfree(ether_dev);
+ return NULL;
+ }
+ ether_dev->tx_urb = usb_alloc_urb(0);
+ if (!ether_dev->tx_urb) {
+ usb_free_urb(ether_dev->rx_urb);
+ kfree(ether_dev);
+ return NULL;
+ }
+ ether_dev->intr_urb = usb_alloc_urb(0);
+ if (!ether_dev->intr_urb) {
+ usb_free_urb(ether_dev->tx_urb);
+ usb_free_urb(ether_dev->rx_urb);
+ kfree(ether_dev);
+ return NULL;
+ }
+
// Let's see if we can find a configuration we can use.
rc = find_valid_configuration( usb, ether_dev );
if (rc) {
&(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
// No more tied up kernel memory
+ usb_free_urb(ether_dev->intr_urb);
+ usb_free_urb(ether_dev->rx_urb);
+ usb_free_urb(ether_dev->rx_urb);
kfree( ether_dev );
// This does no good, but it looks nice!
__u16 wNumberMCFilters;
__u8 bNumberPowerFilters;
int intr_interval;
- struct urb rx_urb, tx_urb, intr_urb;
+ struct urb *rx_urb, *tx_urb, *intr_urb;
unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
unsigned char ALIGN(intr_buff[8]);
#define FLG_CONNECTED 32
struct my_data_urb {
- struct urb urb;
+ struct urb *urb;
struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
};
struct my_sync_urb {
- struct urb urb;
+ struct urb *urb;
struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
};
spin_unlock_irqrestore(&as->lock, flags);
if (notkilled && signal_pending(current)) {
if (i & FLG_URB0RUNNING)
- usb_unlink_urb(&u->durb[0].urb);
+ usb_unlink_urb(u->durb[0].urb);
if (i & FLG_URB1RUNNING)
- usb_unlink_urb(&u->durb[1].urb);
+ usb_unlink_urb(u->durb[1].urb);
if (i & FLG_SYNC0RUNNING)
- usb_unlink_urb(&u->surb[0].urb);
+ usb_unlink_urb(u->surb[0].urb);
if (i & FLG_SYNC1RUNNING)
- usb_unlink_urb(&u->surb[1].urb);
+ usb_unlink_urb(u->surb[1].urb);
notkilled = 0;
}
}
set_current_state(TASK_RUNNING);
- if (u->durb[0].urb.transfer_buffer)
- kfree(u->durb[0].urb.transfer_buffer);
- if (u->durb[1].urb.transfer_buffer)
- kfree(u->durb[1].urb.transfer_buffer);
- if (u->surb[0].urb.transfer_buffer)
- kfree(u->surb[0].urb.transfer_buffer);
- if (u->surb[1].urb.transfer_buffer)
- kfree(u->surb[1].urb.transfer_buffer);
- u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer =
- u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+ if (u->durb[0].urb->transfer_buffer)
+ kfree(u->durb[0].urb->transfer_buffer);
+ if (u->durb[1].urb->transfer_buffer)
+ kfree(u->durb[1].urb->transfer_buffer);
+ if (u->surb[0].urb->transfer_buffer)
+ kfree(u->surb[0].urb->transfer_buffer);
+ if (u->surb[1].urb->transfer_buffer)
+ kfree(u->surb[1].urb->transfer_buffer);
+ u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer =
+ u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
}
static inline void usbin_release(struct usb_audiodev *as)
#if 0
printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
#endif
- if (urb == &u->durb[0].urb)
+ if (urb == u->durb[0].urb)
mask = FLG_URB0RUNNING;
- else if (urb == &u->durb[1].urb)
+ else if (urb == u->durb[1].urb)
mask = FLG_URB1RUNNING;
else {
mask = 0;
#if 0
printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
#endif
- if (urb == &u->surb[0].urb)
+ if (urb == u->surb[0].urb)
mask = FLG_SYNC0RUNNING;
- else if (urb == &u->surb[1].urb)
+ else if (urb == u->surb[1].urb)
mask = FLG_SYNC1RUNNING;
else {
mask = 0;
u->phase = 0;
maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
bufsz = DESCFRAMES * maxsze;
- if (u->durb[0].urb.transfer_buffer)
- kfree(u->durb[0].urb.transfer_buffer);
- u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
- u->durb[0].urb.transfer_buffer_length = bufsz;
- if (u->durb[1].urb.transfer_buffer)
- kfree(u->durb[1].urb.transfer_buffer);
- u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
- u->durb[1].urb.transfer_buffer_length = bufsz;
+ if (u->durb[0].urb->transfer_buffer)
+ kfree(u->durb[0].urb->transfer_buffer);
+ u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+ u->durb[0].urb->transfer_buffer_length = bufsz;
+ if (u->durb[1].urb->transfer_buffer)
+ kfree(u->durb[1].urb->transfer_buffer);
+ u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+ u->durb[1].urb->transfer_buffer_length = bufsz;
if (u->syncpipe) {
- if (u->surb[0].urb.transfer_buffer)
- kfree(u->surb[0].urb.transfer_buffer);
- u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
- u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
- if (u->surb[1].urb.transfer_buffer)
- kfree(u->surb[1].urb.transfer_buffer);
- u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
- u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
- }
- if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer ||
- (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+ if (u->surb[0].urb->transfer_buffer)
+ kfree(u->surb[0].urb->transfer_buffer);
+ u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+ u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+ if (u->surb[1].urb->transfer_buffer)
+ kfree(u->surb[1].urb->transfer_buffer);
+ u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+ u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
+ }
+ if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer ||
+ (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
return 0;
}
}
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
- urb = &u->durb[0].urb;
+ urb = u->durb[0].urb;
urb->dev = dev;
urb->pipe = u->datapipe;
urb->transfer_flags = USB_ISO_ASAP;
u->flags &= ~FLG_RUNNING;
}
if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
- urb = &u->durb[1].urb;
+ urb = u->durb[1].urb;
urb->dev = dev;
urb->pipe = u->datapipe;
urb->transfer_flags = USB_ISO_ASAP;
}
if (u->syncpipe) {
if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
- urb = &u->surb[0].urb;
+ urb = u->surb[0].urb;
urb->dev = dev;
urb->pipe = u->syncpipe;
urb->transfer_flags = USB_ISO_ASAP;
u->flags &= ~FLG_RUNNING;
}
if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
- urb = &u->surb[1].urb;
+ urb = u->surb[1].urb;
urb->dev = dev;
urb->pipe = u->syncpipe;
urb->transfer_flags = USB_ISO_ASAP;
spin_unlock_irqrestore(&as->lock, flags);
if (notkilled && signal_pending(current)) {
if (i & FLG_URB0RUNNING)
- usb_unlink_urb(&u->durb[0].urb);
+ usb_unlink_urb(u->durb[0].urb);
if (i & FLG_URB1RUNNING)
- usb_unlink_urb(&u->durb[1].urb);
+ usb_unlink_urb(u->durb[1].urb);
if (i & FLG_SYNC0RUNNING)
- usb_unlink_urb(&u->surb[0].urb);
+ usb_unlink_urb(u->surb[0].urb);
if (i & FLG_SYNC1RUNNING)
- usb_unlink_urb(&u->surb[1].urb);
+ usb_unlink_urb(u->surb[1].urb);
notkilled = 0;
}
}
set_current_state(TASK_RUNNING);
- if (u->durb[0].urb.transfer_buffer)
- kfree(u->durb[0].urb.transfer_buffer);
- if (u->durb[1].urb.transfer_buffer)
- kfree(u->durb[1].urb.transfer_buffer);
- if (u->surb[0].urb.transfer_buffer)
- kfree(u->surb[0].urb.transfer_buffer);
- if (u->surb[1].urb.transfer_buffer)
- kfree(u->surb[1].urb.transfer_buffer);
- u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer =
- u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+ if (u->durb[0].urb->transfer_buffer)
+ kfree(u->durb[0].urb->transfer_buffer);
+ if (u->durb[1].urb->transfer_buffer)
+ kfree(u->durb[1].urb->transfer_buffer);
+ if (u->surb[0].urb->transfer_buffer)
+ kfree(u->surb[0].urb->transfer_buffer);
+ if (u->surb[1].urb->transfer_buffer)
+ kfree(u->surb[1].urb->transfer_buffer);
+ u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer =
+ u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
}
static inline void usbout_release(struct usb_audiodev *as)
#if 0
printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
#endif
- if (urb == &u->durb[0].urb)
+ if (urb == u->durb[0].urb)
mask = FLG_URB0RUNNING;
- else if (urb == &u->durb[1].urb)
+ else if (urb == u->durb[1].urb)
mask = FLG_URB1RUNNING;
else {
mask = 0;
#if 0
printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
#endif
- if (urb == &u->surb[0].urb)
+ if (urb == u->surb[0].urb)
mask = FLG_SYNC0RUNNING;
- else if (urb == &u->surb[1].urb)
+ else if (urb == u->surb[1].urb)
mask = FLG_SYNC1RUNNING;
else {
mask = 0;
u->phase = 0;
maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
bufsz = DESCFRAMES * maxsze;
- if (u->durb[0].urb.transfer_buffer)
- kfree(u->durb[0].urb.transfer_buffer);
- u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
- u->durb[0].urb.transfer_buffer_length = bufsz;
- if (u->durb[1].urb.transfer_buffer)
- kfree(u->durb[1].urb.transfer_buffer);
- u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
- u->durb[1].urb.transfer_buffer_length = bufsz;
+ if (u->durb[0].urb->transfer_buffer)
+ kfree(u->durb[0].urb->transfer_buffer);
+ u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+ u->durb[0].urb->transfer_buffer_length = bufsz;
+ if (u->durb[1].urb->transfer_buffer)
+ kfree(u->durb[1].urb->transfer_buffer);
+ u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+ u->durb[1].urb->transfer_buffer_length = bufsz;
if (u->syncpipe) {
- if (u->surb[0].urb.transfer_buffer)
- kfree(u->surb[0].urb.transfer_buffer);
- u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
- u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
- if (u->surb[1].urb.transfer_buffer)
- kfree(u->surb[1].urb.transfer_buffer);
- u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
- u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
- }
- if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer ||
- (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+ if (u->surb[0].urb->transfer_buffer)
+ kfree(u->surb[0].urb->transfer_buffer);
+ u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+ u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+ if (u->surb[1].urb->transfer_buffer)
+ kfree(u->surb[1].urb->transfer_buffer);
+ u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+ u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
+ }
+ if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer ||
+ (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
return 0;
}
}
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
- urb = &u->durb[0].urb;
+ urb = u->durb[0].urb;
urb->dev = dev;
urb->pipe = u->datapipe;
urb->transfer_flags = USB_ISO_ASAP;
u->flags &= ~FLG_RUNNING;
}
if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
- urb = &u->durb[1].urb;
+ urb = u->durb[1].urb;
urb->dev = dev;
urb->pipe = u->datapipe;
urb->transfer_flags = USB_ISO_ASAP;
}
if (u->syncpipe) {
if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
- urb = &u->surb[0].urb;
+ urb = u->surb[0].urb;
urb->dev = dev;
urb->pipe = u->syncpipe;
urb->transfer_flags = USB_ISO_ASAP;
u->flags &= ~FLG_RUNNING;
}
if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
- urb = &u->surb[1].urb;
+ urb = u->surb[1].urb;
urb->dev = dev;
urb->pipe = u->syncpipe;
urb->transfer_flags = USB_ISO_ASAP;
usbout_release(as);
dmabuf_release(&as->usbin.dma);
dmabuf_release(&as->usbout.dma);
+ usb_free_urb(as->usbin.durb[0].urb);
+ usb_free_urb(as->usbin.durb[1].urb);
+ usb_free_urb(as->usbin.surb[0].urb);
+ usb_free_urb(as->usbin.surb[1].urb);
+ usb_free_urb(as->usbout.durb[0].urb);
+ usb_free_urb(as->usbout.durb[1].urb);
+ usb_free_urb(as->usbout.surb[0].urb);
+ usb_free_urb(as->usbout.surb[1].urb);
kfree(as);
}
while (!list_empty(&s->mixerlist)) {
init_waitqueue_head(&as->usbin.dma.wait);
init_waitqueue_head(&as->usbout.dma.wait);
spin_lock_init(&as->lock);
- spin_lock_init(&as->usbin.durb[0].urb.lock);
- spin_lock_init(&as->usbin.durb[1].urb.lock);
- spin_lock_init(&as->usbin.surb[0].urb.lock);
- spin_lock_init(&as->usbin.surb[1].urb.lock);
- spin_lock_init(&as->usbout.durb[0].urb.lock);
- spin_lock_init(&as->usbout.durb[1].urb.lock);
- spin_lock_init(&as->usbout.surb[0].urb.lock);
- spin_lock_init(&as->usbout.surb[1].urb.lock);
+ as->usbin.durb[0].urb = usb_alloc_urb(0);
+ as->usbin.durb[1].urb = usb_alloc_urb(0);
+ as->usbin.surb[0].urb = usb_alloc_urb(0);
+ as->usbin.surb[1].urb = usb_alloc_urb(0);
+ as->usbout.durb[0].urb = usb_alloc_urb(0);
+ as->usbout.durb[1].urb = usb_alloc_urb(0);
+ as->usbout.surb[0].urb = usb_alloc_urb(0);
+ as->usbout.surb[1].urb = usb_alloc_urb(0);
+ if ((!as->usbin.durb[0].urb) ||
+ (!as->usbin.durb[1].urb) ||
+ (!as->usbin.surb[0].urb) ||
+ (!as->usbin.surb[1].urb) ||
+ (!as->usbout.durb[0].urb) ||
+ (!as->usbout.durb[1].urb) ||
+ (!as->usbout.surb[0].urb) ||
+ (!as->usbout.surb[1].urb)) {
+ usb_free_urb(as->usbin.durb[0].urb);
+ usb_free_urb(as->usbin.durb[1].urb);
+ usb_free_urb(as->usbin.surb[0].urb);
+ usb_free_urb(as->usbin.surb[1].urb);
+ usb_free_urb(as->usbout.durb[0].urb);
+ usb_free_urb(as->usbout.durb[1].urb);
+ usb_free_urb(as->usbout.surb[0].urb);
+ usb_free_urb(as->usbout.surb[1].urb);
+ kfree(as);
+ return;
+ }
as->state = s;
as->usbin.interface = asifin;
as->usbout.interface = asifout;
}
}
if (as->numfmtin == 0 && as->numfmtout == 0) {
+ usb_free_urb(as->usbin.durb[0].urb);
+ usb_free_urb(as->usbin.durb[1].urb);
+ usb_free_urb(as->usbin.surb[0].urb);
+ usb_free_urb(as->usbin.surb[1].urb);
+ usb_free_urb(as->usbout.durb[0].urb);
+ usb_free_urb(as->usbout.durb[1].urb);
+ usb_free_urb(as->usbout.surb[0].urb);
+ usb_free_urb(as->usbout.surb[1].urb);
kfree(as);
return;
}
if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
printk(KERN_ERR "usbaudio: cannot register dsp\n");
+ usb_free_urb(as->usbin.durb[0].urb);
+ usb_free_urb(as->usbin.durb[1].urb);
+ usb_free_urb(as->usbin.surb[0].urb);
+ usb_free_urb(as->usbin.surb[1].urb);
+ usb_free_urb(as->usbout.durb[0].urb);
+ usb_free_urb(as->usbout.durb[1].urb);
+ usb_free_urb(as->usbout.surb[0].urb);
+ usb_free_urb(as->usbout.surb[1].urb);
kfree(as);
return;
}
void (*callback)(struct catc *catc, struct ctrl_queue *q);
} ctrl_queue[CTRL_QUEUE];
- struct urb tx_urb, rx_urb, irq_urb, ctrl_urb;
+ struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
};
/*
}
if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
- catc->rx_urb.dev = catc->usbdev;
- if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
+ catc->rx_urb->dev = catc->usbdev;
+ if ((status = usb_submit_urb(catc->rx_urb)) < 0) {
err("submit(rx_urb) status %d", status);
return;
}
{
int status;
- catc->tx_urb.transfer_buffer_length = catc->tx_ptr;
- catc->tx_urb.transfer_buffer = catc->tx_buf[catc->tx_idx];
- catc->tx_urb.dev = catc->usbdev;
+ catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
+ catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
+ catc->tx_urb->dev = catc->usbdev;
- if ((status = usb_submit_urb(&catc->tx_urb)) < 0)
+ if ((status = usb_submit_urb(catc->tx_urb)) < 0)
err("submit(tx_urb), status %d", status);
catc->tx_idx = !catc->tx_idx;
struct catc *catc = netdev->priv;
warn("Transmit timed out.");
- catc->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
- usb_unlink_urb(&catc->tx_urb);
+ catc->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb(catc->tx_urb);
}
/*
{
struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
struct usb_device *usbdev = catc->usbdev;
- struct urb *urb = &catc->ctrl_urb;
+ struct urb *urb = catc->ctrl_urb;
struct usb_ctrlrequest *dr = &catc->ctrl_dr;
int status;
if (!q->dir && q->buf && q->len)
memcpy(catc->ctrl_buf, q->buf, q->len);
- if ((status = usb_submit_urb(&catc->ctrl_urb)))
+ if ((status = usb_submit_urb(catc->ctrl_urb)))
err("submit(ctrl_urb) status %d", status);
}
struct catc *catc = netdev->priv;
int status;
- catc->irq_urb.dev = catc->usbdev;
- if ((status = usb_submit_urb(&catc->irq_urb)) < 0) {
+ catc->irq_urb->dev = catc->usbdev;
+ if ((status = usb_submit_urb(catc->irq_urb)) < 0) {
err("submit(irq_urb) status %d", status);
return -1;
}
del_timer_sync(&catc->timer);
- usb_unlink_urb(&catc->rx_urb);
- usb_unlink_urb(&catc->tx_urb);
- usb_unlink_urb(&catc->irq_urb);
- usb_unlink_urb(&catc->ctrl_urb);
+ usb_unlink_urb(catc->rx_urb);
+ usb_unlink_urb(catc->tx_urb);
+ usb_unlink_urb(catc->irq_urb);
+ usb_unlink_urb(catc->ctrl_urb);
return 0;
}
catc->timer.data = (long) catc;
catc->timer.function = catc_stats_timer;
- FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
+ catc->ctrl_urb = usb_alloc_urb(0);
+ catc->tx_urb = usb_alloc_urb(0);
+ catc->rx_urb = usb_alloc_urb(0);
+ catc->irq_urb = usb_alloc_urb(0);
+ if ((!catc->ctrl_urb) || (!catc->tx_urb) ||
+ (!catc->rx_urb) || (!catc->irq_urb)) {
+ err("No free urbs available.");
+ return NULL;
+ }
+
+ FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
NULL, NULL, 0, catc_ctrl_done, catc);
- FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
+ FILL_BULK_URB(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
NULL, 0, catc_tx_done, catc);
- FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
+ FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc);
- FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
+ FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
catc->irq_buf, 2, catc_irq_done, catc, 1);
dbg("Checking memory size\n");
{
struct catc *catc = dev_ptr;
unregister_netdev(catc->netdev);
+ usb_free_urb(catc->ctrl_urb);
+ usb_free_urb(catc->tx_urb);
+ usb_free_urb(catc->rx_urb);
+ usb_free_urb(catc->irq_urb);
kfree(catc->netdev);
kfree(catc);
}
unsigned int signr;
void *userbuffer;
void *userurb;
- struct urb urb;
+ struct urb *urb;
};
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
if (!as)
return NULL;
memset(as, 0, assize);
- as->urb.number_of_packets = numisoframes;
- spin_lock_init(&as->urb.lock);
+ as->urb = usb_alloc_urb(numisoframes);
+ if (!as->urb) {
+ kfree(as);
+ return NULL;
+ }
return as;
}
static void free_async(struct async *as)
{
- if (as->urb.transfer_buffer)
- kfree(as->urb.transfer_buffer);
- if (as->urb.setup_packet)
- kfree(as->urb.setup_packet);
+ if (as->urb->transfer_buffer)
+ kfree(as->urb->transfer_buffer);
+ if (as->urb->setup_packet)
+ kfree(as->urb->setup_packet);
+ usb_free_urb(as->urb);
kfree(as);
}
wake_up(&ps->wait);
if (as->signr) {
sinfo.si_signo = as->signr;
- sinfo.si_errno = as->urb.status;
+ sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
send_sig_info(as->signr, &sinfo, as->task);
INIT_LIST_HEAD(&as->asynclist);
spin_unlock_irqrestore(&ps->lock, flags);
/* usb_unlink_urb calls the completion handler with status == -ENOENT */
- usb_unlink_urb(&as->urb);
+ usb_unlink_urb(as->urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
kfree(dr);
return -ENOMEM;
}
- if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+ if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
if (isopkt)
kfree(isopkt);
if (dr)
free_async(as);
return -ENOMEM;
}
- as->urb.next = NULL;
- as->urb.dev = ps->dev;
- as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
- as->urb.transfer_flags = uurb.flags;
- as->urb.transfer_buffer_length = uurb.buffer_length;
- as->urb.setup_packet = (unsigned char*)dr;
- as->urb.start_frame = uurb.start_frame;
- as->urb.number_of_packets = uurb.number_of_packets;
- as->urb.context = as;
- as->urb.complete = async_completed;
+ as->urb->next = NULL;
+ as->urb->dev = ps->dev;
+ as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb.flags;
+ as->urb->transfer_buffer_length = uurb.buffer_length;
+ as->urb->setup_packet = (unsigned char*)dr;
+ as->urb->start_frame = uurb.start_frame;
+ as->urb->number_of_packets = uurb.number_of_packets;
+ as->urb->context = as;
+ as->urb->complete = async_completed;
for (totlen = u = 0; u < uurb.number_of_packets; u++) {
- as->urb.iso_frame_desc[u].offset = totlen;
- as->urb.iso_frame_desc[u].length = isopkt[u].length;
+ as->urb->iso_frame_desc[u].offset = totlen;
+ as->urb->iso_frame_desc[u].length = isopkt[u].length;
totlen += isopkt[u].length;
}
if (isopkt)
as->signr = uurb.signr;
as->task = current;
if (!(uurb.endpoint & USB_DIR_IN)) {
- if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
async_newpending(as);
- if ((ret = usb_submit_urb(&as->urb))) {
+ if ((ret = usb_submit_urb(as->urb))) {
printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
async_removepending(as);
free_async(as);
as = async_getpending(ps, arg);
if (!as)
return -EINVAL;
- usb_unlink_urb(&as->urb);
+ usb_unlink_urb(as->urb);
return 0;
}
static int processcompl(struct async *as)
{
+ struct urb *urb = as->urb;
unsigned int i;
if (as->userbuffer)
- if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+ if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(as->urb.status,
+ if (put_user(urb->status,
&((struct usbdevfs_urb *)as->userurb)->status))
return -EFAULT;
- if (put_user(as->urb.actual_length,
+ if (put_user(urb->actual_length,
&((struct usbdevfs_urb *)as->userurb)->actual_length))
return -EFAULT;
- if (put_user(as->urb.error_count,
+ if (put_user(urb->error_count,
&((struct usbdevfs_urb *)as->userurb)->error_count))
return -EFAULT;
- if (!(usb_pipeisoc(as->urb.pipe)))
+ if (!(usb_pipeisoc(urb->pipe)))
return 0;
- for (i = 0; i < as->urb.number_of_packets; i++) {
- if (put_user(as->urb.iso_frame_desc[i].actual_length,
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (put_user(urb->iso_frame_desc[i].actual_length,
&((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
return -EFAULT;
- if (put_user(as->urb.iso_frame_desc[i].status,
+ if (put_user(urb->iso_frame_desc[i].status,
&((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
return -EFAULT;
}
MODULE_PARM(radio_nr, "i");
typedef struct
-{ struct urb readurb,writeurb;
+{
struct usb_device *dev;
unsigned char transfer_buffer[TB_LEN];
int curfreq;
return NULL;
DEBUG ("Allocated memory\n");
memset (new, 0, sizeof (struct hpusbscsi));
- spin_lock_init (&new->dataurb.lock);
- spin_lock_init (&new->controlurb.lock);
+ new->dataurb = usb_alloc_urb(0);
+ if (!new->dataurb) {
+ kfree (new);
+ return NULL;
+ }
+ new->controlurb = usb_alloc_urb(0);
+ if (!new->controlurb) {
+ usb_free_urb (new->dataurb);
+ kfree (new);
+ return NULL;
+ }
new->dev = dev;
init_waitqueue_head (&new->pending);
init_waitqueue_head (&new->deathrow);
return new;
err_out:
+ usb_free_urb (new->controlurb);
+ usb_free_urb (new->dataurb);
kfree (new);
return NULL;
}
static void
hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
{
- usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
+ usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
((struct hpusbscsi *) ptr)->dev = NULL;
}
old = tmp;
tmp = tmp->next;
o = (struct hpusbscsi *)old;
- usb_unlink_urb(&o->controlurb);
+ usb_unlink_urb(o->controlurb);
scsi_unregister_host(&o->ctempl);
+ usb_free_urb(o->controlurb);
+ usb_free_urb(o->dataurb);
kfree(old);
}
sht->proc_dir = NULL;
/* build and submit an interrupt URB for status byte handling */
- FILL_INT_URB(&desc->controlurb,
+ FILL_INT_URB(desc->controlurb,
desc->dev,
usb_rcvintpipe(desc->dev,desc->ep_int),
&desc->scsi_state_byte,
desc->interrupt_interval
);
- if ( 0 > usb_submit_urb(&desc->controlurb)) {
+ if ( 0 > usb_submit_urb(desc->controlurb)) {
kfree(sht->proc_name);
return 0;
}
desc->host = scsi_register (sht, sizeof (desc));
if (desc->host == NULL) {
kfree (sht->proc_name);
- usb_unlink_urb(&desc->controlurb);
+ usb_unlink_urb(desc->controlurb);
return 0;
}
desc->host->hostdata[0] = (unsigned long) desc;
/* We prepare the urb for writing out the scsi command */
FILL_BULK_URB(
- &hpusbscsi->dataurb,
+ hpusbscsi->dataurb,
hpusbscsi->dev,
usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
srb->cmnd,
hpusbscsi->scallback = callback;
hpusbscsi->srb = srb;
- res = usb_submit_urb(&hpusbscsi->dataurb);
+ res = usb_submit_urb(hpusbscsi->dataurb);
if (unlikely(res)) {
hpusbscsi->state = HP_STATE_FREE;
TRACE_STATE;
struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
printk(KERN_DEBUG"Requested is canceled.\n");
- usb_unlink_urb(&hpusbscsi->dataurb);
- usb_unlink_urb(&hpusbscsi->controlurb);
+ usb_unlink_urb(hpusbscsi->dataurb);
+ usb_unlink_urb(hpusbscsi->controlurb);
hpusbscsi->state = HP_STATE_FREE;
return SCSI_ABORT_PENDING;
wait_queue_head_t pending;
wait_queue_head_t deathrow;
- struct urb dataurb;
- struct urb controlurb;
+ struct urb *dataurb;
+ struct urb *controlurb;
int fragment;
int state;
void usbfs_add_device(struct usb_device *dev)
{
char name[8];
+ int i;
+ int i_size;
sprintf (name, "%03d", dev->devnum);
dev->dentry = fs_create_file (name,
if (dev->dentry == NULL)
return;
+ /* Set the size of the device's file to be
+ * equal to the size of the device descriptors. */
+ i_size = sizeof (struct usb_device_descriptor);
+ for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
+ struct usb_config_descriptor *config =
+ (struct usb_config_descriptor *)dev->rawdescriptors[i];
+ i_size += le16_to_cpu (config->wTotalLength);
+ }
+ if (dev->dentry->d_inode)
+ dev->dentry->d_inode->i_size = i_size;
+
usbfs_update_special();
usbdevfs_conn_disc_event();
}
MTS_DEBUG_GOT_HERE();
mts_debug_dump(desc);
- usb_unlink_urb( &desc->urb );
+ usb_unlink_urb( desc->urb );
}
static struct mts_desc * mts_list; /* list of active scanners */
scsi_unregister_host(&to_remove->ctempl);
unlock_kernel();
+ usb_free_urb(to_remove->urb);
kfree( to_remove );
}
}
- FILL_BULK_URB(&desc->urb,
+ FILL_BULK_URB(desc->urb,
desc->usb_dev,
usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
srb->cmnd,
mts_build_transfer_context( srb, desc );
desc->context.final_callback = callback;
- res=usb_submit_urb(&desc->urb);
+ res=usb_submit_urb(desc->urb);
if(unlikely(res)){
MTS_ERROR("error %d submitting URB\n",(int)res);
return NULL;
}
- /* As done by usb_alloc_urb */
memset( new_desc, 0, sizeof(*new_desc) );
- spin_lock_init(&new_desc->urb.lock);
-
+ new_desc->urb = usb_alloc_urb(0);
+ if (!new_desc->urb) {
+ kfree(new_desc);
+ return NULL;
+ }
/* initialising that descriptor */
new_desc->usb_dev = dev;
struct semaphore lock;
- struct urb urb;
+ struct urb *urb;
struct mts_transfer_context context;
};
pegasus->dr.wValue = cpu_to_le16 (0);
pegasus->dr.wIndex = cpu_to_le16p(&indx);
pegasus->dr.wLength = cpu_to_le16p(&size);
- pegasus->ctrl_urb.transfer_buffer_length = size;
+ pegasus->ctrl_urb->transfer_buffer_length = size;
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_rcvctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, size, ctrl_callback, pegasus );
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+ if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRLs %d", ret);
goto out;
}
pegasus->dr.wValue = cpu_to_le16 (0);
pegasus->dr.wIndex = cpu_to_le16p( &indx );
pegasus->dr.wLength = cpu_to_le16p( &size );
- pegasus->ctrl_urb.transfer_buffer_length = size;
+ pegasus->ctrl_urb->transfer_buffer_length = size;
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, size, ctrl_callback, pegasus );
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+ if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
goto out;
}
pegasus->dr.wValue = cpu_to_le16p( &dat);
pegasus->dr.wIndex = cpu_to_le16p( &indx );
pegasus->dr.wLength = cpu_to_le16( 1 );
- pegasus->ctrl_urb.transfer_buffer_length = 1;
+ pegasus->ctrl_urb->transfer_buffer_length = 1;
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
buffer, 1, ctrl_callback, pegasus );
add_wait_queue( &pegasus->ctrl_wait, &wait );
set_current_state( TASK_UNINTERRUPTIBLE );
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+ if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
goto out;
}
pegasus->dr.wValue = 0;
pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
pegasus->dr.wLength = cpu_to_le16(3);
- pegasus->ctrl_urb.transfer_buffer_length = 3;
+ pegasus->ctrl_urb->transfer_buffer_length = 3;
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
pegasus->eth_regs, 3, ctrl_callback, pegasus );
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+ if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
return ret;
pegasus->stats.rx_bytes += pkt_len;
goon:
- FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+ FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
read_bulk_callback, pegasus );
- if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+ if ( (res = usb_submit_urb(pegasus->rx_urb)) )
warn( __FUNCTION__ " failed submint rx_urb %d", res);
pegasus->flags &= ~PEGASUS_RX_BUSY;
}
return;
warn("%s: Tx timed out.", net->name);
- pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
- usb_unlink_urb( &pegasus->tx_urb );
+ pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb( pegasus->tx_urb );
pegasus->stats.tx_errors++;
}
((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
memcpy(pegasus->tx_buff+2, skb->data, skb->len);
- FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,
+ FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
usb_sndbulkpipe(pegasus->usb, 2),
pegasus->tx_buff, PEGASUS_MAX_MTU,
write_bulk_callback, pegasus );
- pegasus->tx_urb.transfer_buffer_length = count;
- if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+ pegasus->tx_urb->transfer_buffer_length = count;
+ if ((res = usb_submit_urb(pegasus->tx_urb))) {
warn("failed tx_urb %d", res);
pegasus->stats.tx_errors++;
netif_start_queue( net );
err("can't enable_net_traffic() - %d", res);
return -EIO;
}
- FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+ FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
pegasus->rx_buff, PEGASUS_MAX_MTU,
read_bulk_callback, pegasus );
- if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+ if ( (res = usb_submit_urb(pegasus->rx_urb)) )
warn( __FUNCTION__ " failed rx_urb %d", res );
#ifdef PEGASUS_USE_INTR
- FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
+ FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval );
- if ( (res = usb_submit_urb(&pegasus->intr_urb)) )
+ if ( (res = usb_submit_urb(pegasus->intr_urb)) )
warn( __FUNCTION__ " failed intr_urb %d", res);
#endif
netif_start_queue( net );
if ( !(pegasus->flags & PEGASUS_UNPLUG) )
disable_net_traffic( pegasus );
- usb_unlink_urb( &pegasus->rx_urb );
- usb_unlink_urb( &pegasus->tx_urb );
- usb_unlink_urb( &pegasus->ctrl_urb );
+ usb_unlink_urb( pegasus->rx_urb );
+ usb_unlink_urb( pegasus->tx_urb );
+ usb_unlink_urb( pegasus->ctrl_urb );
#ifdef PEGASUS_USE_INTR
- usb_unlink_urb( &pegasus->intr_urb );
+ usb_unlink_urb( pegasus->intr_urb );
#endif
return 0;
}
pegasus->flags |= ETH_REGS_CHANGE;
- ctrl_callback( &pegasus->ctrl_urb );
+ ctrl_callback( pegasus->ctrl_urb );
netif_wake_queue(net);
}
pegasus->dev_index = dev_index;
init_waitqueue_head( &pegasus->ctrl_wait );
+ pegasus->ctrl_urb = usb_alloc_urb(0);
+ if (!pegasus->ctrl_urb) {
+ kfree (pegasus);
+ return NULL;
+ }
+ pegasus->rx_urb = usb_alloc_urb(0);
+ if (!pegasus->rx_urb) {
+ usb_free_urb (pegasus->ctrl_urb);
+ kfree (pegasus);
+ return NULL;
+ }
+ pegasus->tx_urb = usb_alloc_urb(0);
+ if (!pegasus->tx_urb) {
+ usb_free_urb (pegasus->rx_urb);
+ usb_free_urb (pegasus->ctrl_urb);
+ kfree (pegasus);
+ return NULL;
+ }
+ pegasus->intr_urb = usb_alloc_urb(0);
+ if (!pegasus->intr_urb) {
+ usb_free_urb (pegasus->tx_urb);
+ usb_free_urb (pegasus->rx_urb);
+ usb_free_urb (pegasus->ctrl_urb);
+ kfree (pegasus);
+ return NULL;
+ }
+
net = init_etherdev( NULL, 0 );
if ( !net ) {
kfree( pegasus );
if ( reset_mac(pegasus) ) {
err("can't reset MAC");
unregister_netdev( pegasus->net );
+ kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
return NULL;
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev( pegasus->net );
usb_dec_dev_use( dev );
+ usb_free_urb (pegasus->intr_urb);
+ usb_free_urb (pegasus->tx_urb);
+ usb_free_urb (pegasus->rx_urb);
+ usb_free_urb (pegasus->ctrl_urb);
+ kfree( pegasus->net );
kfree( pegasus );
pegasus = NULL;
}
unsigned features;
int dev_index;
int intr_interval;
- struct urb ctrl_urb, rx_urb, tx_urb, intr_urb;
+ struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
struct semaphore ctrl_sem;
#define VENDOR_SMARTBRIDGES 0x08d1
#define VENDOR_SMC 0x0707
#define VENDOR_SOHOWARE 0x15e8
+#define VENDOR_SIEMENS 0x067c
#else /* PEGASUS_DEV */
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+ DEFAULT_GPIO_RESET )
PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
VENDOR_ADMTEK, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
+ DEFAULT_GPIO_RESET )
#endif /* PEGASUS_DEV */
}
memset (scn, 0, sizeof(struct scn_usb_data));
+ scn->scn_irq = usb_alloc_urb(0);
+ if (!scn->scn_irq) {
+ kfree(scn);
+ up(&scn_mutex);
+ return NULL;
+ }
+
init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
/* Ok, if we detected an interrupt EP, setup a handler for it */
if (have_intr) {
dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
- FILL_INT_URB(&scn->scn_irq, dev,
+ FILL_INT_URB(scn->scn_irq, dev,
usb_rcvintpipe(dev, have_intr),
&scn->button, 1, irq_scanner, scn,
// endpoint[(int)have_intr].bInterval);
250);
- if (usb_submit_urb(&scn->scn_irq)) {
+ if (usb_submit_urb(scn->scn_irq)) {
err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
kfree(scn);
up(&scn_mutex);
if(scn->intr_ep) {
dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
- usb_unlink_urb(&scn->scn_irq);
+ usb_unlink_urb(scn->scn_irq);
}
usb_driver_release_interface(&scanner_driver,
&scn->scn_dev->actconfig->interface[scn->ifnum]);
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
devfs_unregister(scn->devfs);
p_scn_table[scn->scn_minor] = NULL;
+ usb_free_urb(scn->scn_irq);
up (&(scn->sem));
kfree (scn);
up (&scn_mutex);
struct scn_usb_data {
struct usb_device *scn_dev;
devfs_handle_t devfs; /* devfs device */
- struct urb scn_irq;
+ struct urb *scn_irq;
unsigned int ifnum; /* Interface number of the USB device */
int scn_minor; /* Scanner minor - used in disconnect() */
unsigned char button; /* Front panel buffer */
* (C) Copyright 1999 Randy Dunlap
* (C) Copyright 1999 Gregory P. Smith
*
- * $Id: usb-uhci.c,v 1.268 2001/08/29 14:08:43 acher Exp $
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/pm.h>
+#include <linux/timer.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
-#define VERSTR "$Revision: 1.268 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
#include <linux/usb.h>
#include "usb-uhci.h"
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.268"
+#define DRIVER_VERSION "v1.275"
#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
#define DRIVER_DESC "USB Universal Host Controller Interface driver"
#define DEBUG_SYMBOLS
#ifdef DEBUG_SYMBOLS
#define _static
+ #ifndef EXPORT_SYMTAB
+ #define EXPORT_SYMTAB
+ #endif
#else
#define _static static
#endif
// cleanup the rest
switch (usb_pipetype (urb->pipe)) {
+ case PIPE_INTERRUPT:
case PIPE_ISOCHRONOUS:
uhci_wait_ms(1);
uhci_clean_iso_step2(s, urb_priv);
type = usb_pipetype (urb->pipe);
hcpriv = (urb_priv_t*)urb->hcpriv;
-
- if ( urb->timeout &&
- ((hcpriv->started + urb->timeout) < jiffies)) {
+
+ if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
async_dbg("uhci_check_timeout: timeout for %p",urb);
uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
}
#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&
- (hcpriv->use_loop) &&
- ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+ (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
disable_desc_loop(s, urb);
#endif
break;
}
- if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) {
+ if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
// do not process one-shot TDs, no recycling
break;
}
}
else {
uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+ // correct toggle after unlink
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
clr_td_ioc(desc); // inactivate TD
}
}
if (status != 1) {
// Avoid too much error messages at a time
- if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+ if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
warn("interrupt, status %x, frame# %i", status,
UHCI_GET_CURRENT_FRAME(s));
s->last_error_time = jiffies;
break;
}
}
- if ((jiffies - s->timeout_check) > (HZ/30))
+ if (time_after(jiffies, s->timeout_check + (HZ/30)))
uhci_check_timeouts(s);
clean_descs(s, CLEAN_NOT_FORCED);
_static void start_hc (uhci_t *s)
{
unsigned int io_addr = s->io_addr;
- int timeout = 1000;
+ int timeout = 10;
/*
* Reset the HC - this will force us to get a
err("USBCMD_HCRESET timed out!");
break;
}
+ udelay(1);
}
/* Turn on all interrupts */
s->running = 1;
}
-_static void __devexit
+/* No __devexit, since it maybe called from alloc_uhci() */
+_static void
uhci_pci_remove (struct pci_dev *dev)
{
uhci_t *s = pci_get_drvdata(dev);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
-
struct usb_device *usbdev;
unsigned char new[8];
unsigned char old[8];
- struct urb irq, led;
+ struct urb *irq, *led;
struct usb_ctrlrequest dr;
unsigned char leds, newleds;
char name[128];
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
- if (kbd->led.status == -EINPROGRESS)
+ if (kbd->led->status == -EINPROGRESS)
return 0;
if (kbd->leds == kbd->newleds)
return 0;
kbd->leds = kbd->newleds;
- kbd->led.dev = kbd->usbdev;
- if (usb_submit_urb(&kbd->led))
+ kbd->led->dev = kbd->usbdev;
+ if (usb_submit_urb(kbd->led))
err("usb_submit_urb(leds) failed");
return 0;
return;
kbd->leds = kbd->newleds;
- kbd->led.dev = kbd->usbdev;
- if (usb_submit_urb(&kbd->led))
+ kbd->led->dev = kbd->usbdev;
+ if (usb_submit_urb(kbd->led))
err("usb_submit_urb(leds) failed");
}
if (kbd->open++)
return 0;
- kbd->irq.dev = kbd->usbdev;
- if (usb_submit_urb(&kbd->irq))
+ kbd->irq->dev = kbd->usbdev;
+ if (usb_submit_urb(kbd->irq))
return -EIO;
return 0;
struct usb_kbd *kbd = dev->private;
if (!--kbd->open)
- usb_unlink_urb(&kbd->irq);
+ usb_unlink_urb(kbd->irq);
}
static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
memset(kbd, 0, sizeof(struct usb_kbd));
+ kbd->irq = usb_alloc_urb(0);
+ if (!kbd->irq) {
+ kfree(kbd);
+ return NULL;
+ }
+ kbd->led = usb_alloc_urb(0);
+ if (!kbd->led) {
+ usb_free_urb(kbd->irq);
+ kfree(kbd);
+ return NULL;
+ }
+
kbd->usbdev = dev;
kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
kbd->dev.open = usb_kbd_open;
kbd->dev.close = usb_kbd_close;
- FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
+ FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
usb_kbd_irq, kbd, endpoint->bInterval);
kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
kfree(buf);
- FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
+ FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
input_register_device(&kbd->dev);
static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_kbd *kbd = ptr;
- usb_unlink_urb(&kbd->irq);
+ usb_unlink_urb(kbd->irq);
input_unregister_device(&kbd->dev);
+ usb_free_urb(kbd->irq);
+ usb_free_urb(kbd->led);
kfree(kbd);
}
char name[128];
struct usb_device *usbdev;
struct input_dev dev;
- struct urb irq;
+ struct urb *irq;
int open;
};
if (mouse->open++)
return 0;
- mouse->irq.dev = mouse->usbdev;
- if (usb_submit_urb(&mouse->irq))
+ mouse->irq->dev = mouse->usbdev;
+ if (usb_submit_urb(mouse->irq))
return -EIO;
return 0;
struct usb_mouse *mouse = dev->private;
if (!--mouse->open)
- usb_unlink_urb(&mouse->irq);
+ usb_unlink_urb(mouse->irq);
}
static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
memset(mouse, 0, sizeof(struct usb_mouse));
+ mouse->irq = usb_alloc_urb(0);
+ if (!mouse->irq) {
+ kfree(mouse);
+ return NULL;
+ }
+
mouse->usbdev = dev;
mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
kfree(buf);
- FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
+ FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
usb_mouse_irq, mouse, endpoint->bInterval);
input_register_device(&mouse->dev);
static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_mouse *mouse = ptr;
- usb_unlink_urb(&mouse->irq);
+ usb_unlink_urb(mouse->irq);
input_unregister_device(&mouse->dev);
+ usb_free_urb(mouse->irq);
kfree(mouse);
}
synchronize(vicam);
mdelay(10);
vicam_parameters(vicam);
- printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+ printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
#endif
}
vicam_parameters(vicam);
- FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+ FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
buf, 0x1e480, vicam_bulk, vicam);
- printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+ printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
return 0;
error:
return NULL;
}
memset(vicam, 0, sizeof(*vicam));
-
+
+ vicam->readurb = usb_alloc_urb(0);
+ if (!vicam->readurb) {
+ kfree(vicam);
+ return NULL;
+ }
+
vicam->udev = udev;
vicam->camera_name = camera_name;
vicam->win.brightness = 128;
if (!vicam->open_count) {
/* Other random junk */
+ usb_free_urb(vicam->readurb);
kfree(vicam);
vicam = NULL;
}
int maxframesize;
struct picture_parm win;
struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */
- struct urb readurb;
+ struct urb *readurb;
};
#endif
signed char data[10];
struct input_dev dev;
struct usb_device *usbdev;
- struct urb irq;
+ struct urb *irq;
struct wacom_features *features;
int tool[2];
int open;
if (wacom->open++)
return 0;
- wacom->irq.dev = wacom->usbdev;
- if (usb_submit_urb(&wacom->irq))
+ wacom->irq->dev = wacom->usbdev;
+ if (usb_submit_urb(wacom->irq))
return -EIO;
return 0;
struct wacom *wacom = dev->private;
if (!--wacom->open)
- usb_unlink_urb(&wacom->irq);
+ usb_unlink_urb(wacom->irq);
}
static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
memset(wacom, 0, sizeof(struct wacom));
+ wacom->irq = usb_alloc_urb(0);
+ if (!wacom->irq) {
+ kfree(wacom);
+ return NULL;
+ }
+
wacom->features = wacom_features + id->driver_info;
wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ FILL_INT_URB(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
input_register_device(&wacom->dev);
static void wacom_disconnect(struct usb_device *dev, void *ptr)
{
struct wacom *wacom = ptr;
- usb_unlink_urb(&wacom->irq);
+ usb_unlink_urb(wacom->irq);
input_unregister_device(&wacom->dev);
+ usb_free_urb(wacom->irq);
kfree(wacom);
}
bool ' SIS 630/540/730 support' CONFIG_FB_SIS_300
bool ' SIS 315H/315 support' CONFIG_FB_SIS_315
fi
+ tristate ' NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
tristate ' 3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
fi
"$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
"$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
"$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
- "$CONFIG_FB_SIS" = "y" ]; then
+ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
define_tristate CONFIG_FBCON_CFB8 y
else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
"$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
"$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
- "$CONFIG_FB_TX3912" = "m" ]; then
+ "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
define_tristate CONFIG_FBCON_CFB8 m
fi
fi
"$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
"$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
"$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
- "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+ "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+ "$CONFIG_FB_NEOMAGIC" = "y" ]; then
define_tristate CONFIG_FBCON_CFB16 y
else
if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
"$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
"$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
"$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
- "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+ "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+ "$CONFIG_FB_NEOMAGIC" = "m" ]; then
define_tristate CONFIG_FBCON_CFB16 m
fi
fi
"$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
"$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
"$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
- "$CONFIG_FB_VOODOO1" = "y" ]; then
+ "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
define_tristate CONFIG_FBCON_CFB24 y
else
if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
"$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
"$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
"$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
- "$CONFIG_FB_VOODOO1" = "m" ]; then
+ "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
define_tristate CONFIG_FBCON_CFB24 m
fi
fi
obj-$(CONFIG_FB_ATARI) += atafb.o
obj-$(CONFIG_FB_ATY128) += aty128fb.o
obj-$(CONFIG_FB_RADEON) += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
strcpy(fb_info.modename, "Trio64 ");
strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &s3trio_ops;
#if 0
fb_info.fbvar_num = 1;
strcpy(fb_info.modename, "Acorn");
strcpy(fb_info.fontname, "Acorn8x8");
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &acornfb_ops;
fb_info.disp = &global_disp;
fb_info.changevar = NULL;
strcpy(fb_info.modename, amifb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &amifb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &amifbcon_switch;
strcpy(fb_info.modename, "Atari Builtin ");
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &atafb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &atafb_switch;
/* fill in info */
strcpy(info->fb_info.modename, aty128fb_name);
- info->fb_info.node = -1;
+ info->fb_info.node = NODEV;
info->fb_info.fbops = &aty128fb_ops;
info->fb_info.disp = &info->disp;
strcpy(info->fb_info.fontname, fontname);
p->disp.scrollmode = SCROLL_YREDRAW;
strcpy(p->info.modename, p->fix.id);
- p->info.node = -1;
+ p->info.node = NODEV;
p->info.fbops = &chipsfb_ops;
p->info.disp = &p->disp;
p->info.fontname[0] = 0;
sizeof (fb_info->gen.info.modename));
fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
- fb_info->gen.info.node = -1;
+ fb_info->gen.info.node = NODEV;
fb_info->gen.info.fbops = &clgenfb_ops;
fb_info->gen.info.disp = &disp;
fb_info->gen.info.changevar = NULL;
static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
{
strcpy(info->modename, "control");
- info->node = -1; /* ??? danj */
+ info->node = NODEV;
info->fbops = &controlfb_ops;
info->disp = &p->display;
strcpy(info->fontname, fontname);
strcpy(fb_info.modename, cyberfb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &cyberfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &Cyberfb_switch;
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.blank=&dnfbcon_blank;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &dn_fb_ops;
fb_info.flags = FBINFO_FLAG_DEFAULT;
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.blank=&dnfbcon_blank;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &dn_fb_ops;
printk("dn_fb_init: register\n");
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.blank=&dnfbcon_blank;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &dn_fb_ops;
dn_fb_get_var(&disp[0].var,0, &fb_info);
fb_info.gen.fbhw->detect();
strcpy(fb_info.gen.info.modename, "SED1355");
fb_info.gen.info.changevar = NULL;
- fb_info.gen.info.node = -1;
+ fb_info.gen.info.node = NODEV;
fb_info.gen.info.fbops = &e1355fb_ops;
fb_info.gen.info.disp = &disp;
fb_info.gen.parsize = sizeof(struct e1355_par);
extern int atyfb_setup(char*);
extern int aty128fb_init(void);
extern int aty128fb_setup(char*);
+extern int neofb_init(void);
+extern int neofb_setup(char*);
extern int igafb_init(void);
extern int igafb_setup(char*);
extern int imsttfb_init(void);
#ifdef CONFIG_FB_ATY128
{ "aty128fb", aty128fb_init, aty128fb_setup },
#endif
+#ifdef CONFIG_FB_NEOMAGIC
+ { "neo", neofb_init, neofb_setup },
+#endif
#ifdef CONFIG_FB_VIRGE
{ "virge", virgefb_init, virgefb_setup },
#endif
disp.scrollmode = SCROLL_YREDRAW;
strcpy(fb_info.modename, fb_fix.id);
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &fm2fb_ops;
fb_info.disp = &disp;
fb_info.fontname[0] = '\0';
disp.dispsw = &fbcon_g364cfb8;
strcpy(fb_info.modename, fb_fix.id);
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &g364fb_ops;
fb_info.disp = &disp;
fb_info.fontname[0] = '\0';
disp.scrollmode = SCROLL_YREDRAW;
strcpy (fb_info.modename, hga_fix.id);
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.flags = FBINFO_FLAG_DEFAULT;
/* fb_info.open = ??? */
fb_info.var = hga_default_var;
int __init hitfb_init(void)
{
strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
- fb_info.gen.info.node = -1;
+ fb_info.gen.info.node = NODEV;
fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
fb_info.gen.info.fbops = &hitfb_ops;
fb_info.gen.info.disp = &fb_info.disp;
*/
strcpy(fb_info.modename, "Topcat");
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &hpfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &hpfb_switch;
}
strcpy(info->fb_info.modename, igafb_name);
- info->fb_info.node = -1;
+ info->fb_info.node = NODEV;
info->fb_info.fbops = &igafb_ops;
info->fb_info.disp = &info->disp;
strcpy(info->fb_info.fontname, fontname);
strcpy(p->info.modename, p->fix.id);
strcpy(p->info.fontname, fontname);
- p->info.node = -1;
+ p->info.node = NODEV;
p->info.fbops = &imsttfb_ops;
p->info.disp = &p->disp;
p->info.changevar = 0;
}
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &macfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &macfb_switch;
strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
/* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &maxinefb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &maxinefb_switch;
--- /dev/null
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ *
+ * 0.3.1
+ * - added module license (dok)
+ *
+ * 0.3
+ * - hardware accelerated clear and move for 2200 and above (dok)
+ * - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ * - correct panning after X usage (dok)
+ * - added module and kernel parameters (dok)
+ * - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ * - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "neofb.h"
+
+
+#define NEOFB_VERSION "0.3.1"
+
+/* --------------------------------------------------------------------- */
+
+static int disabled = 0;
+static int internal = 0;
+static int external = 0;
+static int nostretch = 0;
+static int nopciburst = 0;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
+MODULE_PARM(internal, "i");
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+MODULE_PARM(external, "i");
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+MODULE_PARM(nostretch, "i");
+MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM(nopciburst, "i");
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {
+ { 320, 240, 0x40 },
+ { 300, 400, 0x42 },
+ { 640, 400, 0x20 },
+ { 640, 480, 0x21 },
+ { 800, 600, 0x23 },
+ { 1024, 768, 0x25 },
+};
+
+static biosMode bios16[] = {
+ { 320, 200, 0x2e },
+ { 320, 240, 0x41 },
+ { 300, 400, 0x43 },
+ { 640, 480, 0x31 },
+ { 800, 600, 0x34 },
+ { 1024, 768, 0x37 },
+};
+
+static biosMode bios24[] = {
+ { 640, 480, 0x32 },
+ { 800, 600, 0x35 },
+ { 1024, 768, 0x38 }
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+ { 640, 480, 0x33 },
+ { 800, 600, 0x36 },
+ { 1024, 768, 0x39 }
+ };
+#endif
+
+static int neoFindMode (int xres, int yres, int depth)
+{
+ int xres_s;
+ int i, size;
+ biosMode *mode;
+
+ switch (depth)
+ {
+ case 8:
+ size = sizeof(bios8) / sizeof(biosMode);
+ mode = bios8;
+ break;
+ case 16:
+ size = sizeof(bios16) / sizeof(biosMode);
+ mode = bios16;
+ break;
+ case 24:
+ size = sizeof(bios24) / sizeof(biosMode);
+ mode = bios24;
+ break;
+#ifdef NO_32BIT_SUPPORT_YET
+ case 32:
+ size = sizeof(bios32) / sizeof(biosMode);
+ mode = bios32;
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ for (i = 0; i < size; i++)
+ {
+ if (xres <= mode[i].x_res)
+ {
+ xres_s = mode[i].x_res;
+ for (; i < size; i++)
+ {
+ if (mode[i].x_res != xres_s)
+ return mode[i-1].mode;
+ if (yres <= mode[i].y_res)
+ return mode[i].mode;
+ }
+ }
+ }
+ return mode[size - 1].mode;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle (struct neofb_info *fb)
+{
+ int waitcycles;
+
+ while (fb->neo2200->bltStat & 1)
+ waitcycles++;
+}
+
+static inline void neo2200_wait_fifo (struct neofb_info *fb,
+ int requested_fifo_space)
+{
+ // ndev->neo.waitfifo_calls++;
+ // ndev->neo.waitfifo_sum += requested_fifo_space;
+
+ /* FIXME: does not work
+ if (neo_fifo_space < requested_fifo_space)
+ {
+ neo_fifo_waitcycles++;
+
+ while (1)
+ {
+ neo_fifo_space = (neo2200->bltStat >> 8);
+ if (neo_fifo_space >= requested_fifo_space)
+ break;
+ }
+ }
+ else
+ {
+ neo_fifo_cache_hits++;
+ }
+
+ neo_fifo_space -= requested_fifo_space;
+ */
+
+ neo2200_wait_idle (fb);
+}
+
+static inline void neo2200_accel_init (struct neofb_info *fb,
+ struct fb_var_screeninfo *var)
+{
+ Neo2200 *neo2200 = fb->neo2200;
+ u32 bltMod, pitch;
+
+ neo2200_wait_idle (fb);
+
+ switch (var->bits_per_pixel)
+ {
+ case 8:
+ bltMod = NEO_MODE1_DEPTH8;
+ pitch = var->xres_virtual;
+ break;
+ case 15:
+ case 16:
+ bltMod = NEO_MODE1_DEPTH16;
+ pitch = var->xres_virtual * 2;
+ break;
+ default:
+ printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
+ return;
+ }
+
+ neo2200->bltStat = bltMod << 16;
+ neo2200->pitch = (pitch << 16) | pitch;
+}
+
+static void neo2200_accel_setup (struct display *p)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+ struct fb_var_screeninfo *var = &p->fb_info->var;
+
+ fb->dispsw->setup(p);
+
+ neo2200_accel_init (fb, var);
+}
+
+static void
+neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+ struct fb_var_screeninfo *var = &p->fb_info->var;
+ Neo2200 *neo2200 = fb->neo2200;
+ u_long src, dst;
+ int bpp, pitch, inc_y;
+ u_int fh, fw;
+
+ /* setting blitting direction does not work, so this case is unaccelerated */
+ if (sx != dx)
+ {
+ neo2200_wait_idle (fb);
+ fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
+ return;
+ }
+
+ bpp = (var->bits_per_pixel+7) / 8;
+ pitch = var->xres_virtual * bpp;
+
+ fw = fontwidth(p);
+ sx *= fw * bpp;
+ dx *= fw * bpp;
+ width *= fw;
+
+ fh = fontheight(p);
+ sy *= fh;
+ dy *= fh;
+
+ if (sy > dy)
+ inc_y = fh;
+ else
+ {
+ inc_y = -fh;
+ sy += (height - 1) * fh;
+ dy += (height - 1) * fh;
+ }
+
+ neo2200_wait_fifo (fb, 1);
+
+ /* set blt control */
+ neo2200->bltCntl = NEO_BC3_FIFO_EN |
+ NEO_BC3_SKIP_MAPPING | 0x0c0000;
+
+ /* looks silly, but setting the blitting direction did not work */
+ while (height--)
+ {
+ src = sx + sy * pitch;
+ dst = dx + dy * pitch;
+
+ neo2200_wait_fifo (fb, 3);
+
+ neo2200->srcStart = src;
+ neo2200->dstStart = dst;
+ neo2200->xyExt = (fh << 16) | (width & 0xffff);
+
+ sy += inc_y;
+ dy += inc_y;
+ }
+}
+
+static void
+neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
+ int height, int width)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+ struct fb_var_screeninfo *var = &p->fb_info->var;
+ Neo2200 *neo2200 = fb->neo2200;
+ u_long dst;
+ u_int fw, fh;
+ u32 bgx = attr_bgcol_ec(p, conp);
+
+ fw = fontwidth(p);
+ fh = fontheight(p);
+
+ dst = sx * fw + sy * var->xres_virtual * fh;
+ width = width * fw;
+ height = height * fh;
+
+ neo2200_wait_fifo (fb, 4);
+
+ /* set blt control */
+ neo2200->bltCntl = NEO_BC3_FIFO_EN |
+ NEO_BC0_SRC_IS_FG |
+ NEO_BC3_SKIP_MAPPING | 0x0c0000;
+
+ switch (var->bits_per_pixel)
+ {
+ case 8:
+ neo2200->fgColor = bgx;
+ break;
+ case 16:
+ neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
+ break;
+ }
+
+ neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+
+ neo2200->xyExt = (height << 16) | (width & 0xffff);
+}
+
+static void
+neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+ neo2200_wait_idle (fb);
+ fb->dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+neo2200_accel_putcs (struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy, int xx)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+ neo2200_wait_idle (fb);
+ fb->dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void neo2200_accel_revc (struct display *p, int xx, int yy)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+ neo2200_wait_idle (fb);
+ fb->dispsw->revc (p, xx, yy);
+}
+
+static void
+neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
+ int bottom_only)
+{
+ struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+ fb->dispsw->clear_margins (conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_neo2200_accel = {
+ setup: neo2200_accel_setup,
+ bmove: neo2200_accel_bmove,
+ clear: neo2200_accel_clear,
+ putc: neo2200_accel_putc,
+ putcs: neo2200_accel_putcs,
+ revc: neo2200_accel_revc,
+ clear_margins: neo2200_accel_clear_margins,
+ fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Set a single color register. Return != 0 for invalid regno.
+ */
+static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+
+ if (regno >= NR_PALETTE)
+ return -EINVAL;
+
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+ info->palette[regno].transp = transp;
+
+ switch (fb->var.bits_per_pixel)
+ {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ outb(regno, 0x3c8);
+
+ outb(red >> 10, 0x3c9);
+ outb(green >> 10, 0x3c9);
+ outb(blue >> 10, 0x3c9);
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ if (regno < 16)
+ ((u16 *)fb->pseudo_palette)[regno] = ((red & 0xf800) ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ if (regno < 16)
+ ((u32 *)fb->pseudo_palette)[regno] = ((red & 0xff00) << 8) |
+ ((green & 0xff00) ) |
+ ((blue & 0xff00) >> 8);
+ break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ if (regno < 16)
+ ((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
+ ((red & 0xff00) << 8) |
+ ((green & 0xff00) ) |
+ ((blue & 0xff00) >> 8);
+ break;
+#endif
+#endif
+
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static void vgaHWLock (void)
+{
+ /* Protect CRTC[0-7] */
+ VGAwCR (0x11, VGArCR (0x11) | 0x80);
+}
+
+static void vgaHWUnlock (void)
+{
+ /* Unprotect CRTC[0-7] */
+ VGAwCR (0x11, VGArCR (0x11) & ~0x80);
+}
+
+static void neoLock (void)
+{
+ VGAwGR (0x09, 0x00);
+ vgaHWLock();
+}
+
+static void neoUnlock (void)
+{
+ vgaHWUnlock();
+ VGAwGR (0x09, 0x26);
+}
+
+/*
+ * vgaHWSeqReset
+ * perform a sequencer reset.
+ */
+void
+vgaHWSeqReset(int start)
+{
+ if (start)
+ VGAwSEQ (0x00, 0x01); /* Synchronous Reset */
+ else
+ VGAwSEQ (0x00, 0x03); /* End Reset */
+}
+
+void
+vgaHWProtect(int on)
+{
+ unsigned char tmp;
+
+ if (on)
+ {
+ /*
+ * Turn off screen and disable sequencer.
+ */
+ tmp = VGArSEQ (0x01);
+
+ vgaHWSeqReset (1); /* start synchronous reset */
+ VGAwSEQ (0x01, tmp | 0x20); /* disable the display */
+
+ VGAenablePalette();
+ }
+ else
+ {
+ /*
+ * Reenable sequencer, then turn on screen.
+ */
+
+ tmp = VGArSEQ (0x01);
+
+ VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */
+ vgaHWSeqReset (0); /* clear synchronousreset */
+
+ VGAdisablePalette();
+ }
+}
+
+static void vgaHWRestore (const struct neofb_info *info,
+ const struct neofb_par *par)
+{
+ int i;
+
+ VGAwMISC (par->MiscOutReg);
+
+ for (i = 1; i < 5; i++)
+ VGAwSEQ (i, par->Sequencer[i]);
+
+ /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+ VGAwCR (17, par->CRTC[17] & ~0x80);
+
+ for (i = 0; i < 25; i++)
+ VGAwCR (i, par->CRTC[i]);
+
+ for (i = 0; i < 9; i++)
+ VGAwGR (i, par->Graphics[i]);
+
+ VGAenablePalette();
+
+ for (i = 0; i < 21; i++)
+ VGAwATTR (i, par->Attribute[i]);
+
+ VGAdisablePalette();
+}
+
+static void neofb_set_par (struct neofb_info *info,
+ const struct neofb_par *par)
+{
+ unsigned char temp;
+ int i;
+ int clock_hi = 0;
+
+ DBG("neofb_set_par");
+
+ neoUnlock();
+
+ vgaHWProtect (1); /* Blank the screen */
+
+ /* linear colormap for non palettized modes */
+ switch (par->depth)
+ {
+ case 8:
+ break;
+ case 16:
+ for (i=0; i<64; i++)
+ {
+ outb(i, 0x3c8);
+
+ outb(i << 1, 0x3c9);
+ outb(i, 0x3c9);
+ outb(i << 1, 0x3c9);
+ }
+ break;
+ case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+ case 32:
+#endif
+ for (i=0; i<256; i++)
+ {
+ outb(i, 0x3c8);
+
+ outb(i, 0x3c9);
+ outb(i, 0x3c9);
+ outb(i, 0x3c9);
+ }
+ break;
+ }
+
+ /* alread unlocked above */
+ /* BOGUS VGAwGR (0x09, 0x26);*/
+
+ /* don't know what this is, but it's 0 from bootup anyway */
+ VGAwGR (0x15, 0x00);
+
+ /* was set to 0x01 by my bios in text and vesa modes */
+ VGAwGR (0x0A, par->GeneralLockReg);
+
+ /*
+ * The color mode needs to be set before calling vgaHWRestore
+ * to ensure the DAC is initialized properly.
+ *
+ * NOTE: Make sure we don't change bits make sure we don't change
+ * any reserved bits.
+ */
+ temp = VGArGR(0x90);
+ switch (info->accel)
+ {
+ case FB_ACCEL_NEOMAGIC_NM2070:
+ temp &= 0xF0; /* Save bits 7:4 */
+ temp |= (par->ExtColorModeSelect & ~0xF0);
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2090:
+ case FB_ACCEL_NEOMAGIC_NM2093:
+ case FB_ACCEL_NEOMAGIC_NM2097:
+ case FB_ACCEL_NEOMAGIC_NM2160:
+ case FB_ACCEL_NEOMAGIC_NM2200:
+ case FB_ACCEL_NEOMAGIC_NM2230:
+ case FB_ACCEL_NEOMAGIC_NM2360:
+ case FB_ACCEL_NEOMAGIC_NM2380:
+ temp &= 0x70; /* Save bits 6:4 */
+ temp |= (par->ExtColorModeSelect & ~0x70);
+ break;
+ }
+
+ VGAwGR(0x90,temp);
+
+ /*
+ * In some rare cases a lockup might occur if we don't delay
+ * here. (Reported by Miles Lane)
+ */
+ //mdelay(200);
+
+ /*
+ * Disable horizontal and vertical graphics and text expansions so
+ * that vgaHWRestore works properly.
+ */
+ temp = VGArGR(0x25);
+ temp &= 0x39;
+ VGAwGR (0x25, temp);
+
+ /*
+ * Sleep for 200ms to make sure that the two operations above have
+ * had time to take effect.
+ */
+ mdelay(200);
+
+ /*
+ * This function handles restoring the generic VGA registers. */
+ vgaHWRestore (info, par);
+
+
+ VGAwGR(0x0E, par->ExtCRTDispAddr);
+ VGAwGR(0x0F, par->ExtCRTOffset);
+ temp = VGArGR(0x10);
+ temp &= 0x0F; /* Save bits 3:0 */
+ temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
+ VGAwGR(0x10, temp);
+
+ VGAwGR(0x11, par->SysIfaceCntl2);
+ VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
+ VGAwGR(0x16, 0 /*par->DualAddrPage*/);
+
+ temp = VGArGR(0x20);
+ switch (info->accel)
+ {
+ case FB_ACCEL_NEOMAGIC_NM2070:
+ temp &= 0xFC; /* Save bits 7:2 */
+ temp |= (par->PanelDispCntlReg1 & ~0xFC);
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2090:
+ case FB_ACCEL_NEOMAGIC_NM2093:
+ case FB_ACCEL_NEOMAGIC_NM2097:
+ case FB_ACCEL_NEOMAGIC_NM2160:
+ temp &= 0xDC; /* Save bits 7:6,4:2 */
+ temp |= (par->PanelDispCntlReg1 & ~0xDC);
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2200:
+ case FB_ACCEL_NEOMAGIC_NM2230:
+ case FB_ACCEL_NEOMAGIC_NM2360:
+ case FB_ACCEL_NEOMAGIC_NM2380:
+ temp &= 0x98; /* Save bits 7,4:3 */
+ temp |= (par->PanelDispCntlReg1 & ~0x98);
+ break;
+ }
+ VGAwGR(0x20, temp);
+
+ temp = VGArGR(0x25);
+ temp &= 0x38; /* Save bits 5:3 */
+ temp |= (par->PanelDispCntlReg2 & ~0x38);
+ VGAwGR(0x25, temp);
+
+ if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+ {
+ temp = VGArGR(0x30);
+ temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
+ temp |= (par->PanelDispCntlReg3 & ~0xEF);
+ VGAwGR(0x30, temp);
+ }
+
+ VGAwGR(0x28, par->PanelVertCenterReg1);
+ VGAwGR(0x29, par->PanelVertCenterReg2);
+ VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+ if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+ {
+ VGAwGR(0x32, par->PanelVertCenterReg4);
+ VGAwGR(0x33, par->PanelHorizCenterReg1);
+ VGAwGR(0x34, par->PanelHorizCenterReg2);
+ VGAwGR(0x35, par->PanelHorizCenterReg3);
+ }
+
+ if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
+ VGAwGR(0x36, par->PanelHorizCenterReg4);
+
+ if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+ {
+ VGAwGR(0x36, par->PanelHorizCenterReg4);
+ VGAwGR(0x37, par->PanelVertCenterReg5);
+ VGAwGR(0x38, par->PanelHorizCenterReg5);
+
+ clock_hi = 1;
+ }
+
+ /* Program VCLK3 if needed. */
+ if (par->ProgramVCLK
+ && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+ || (VGArGR(0x9F) != par->VCLK3Denominator)
+ || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+ != (par->VCLK3NumeratorHigh & ~0x0F)))))
+ {
+ VGAwGR(0x9B, par->VCLK3NumeratorLow);
+ if (clock_hi)
+ {
+ temp = VGArGR(0x8F);
+ temp &= 0x0F; /* Save bits 3:0 */
+ temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+ VGAwGR(0x8F, temp);
+ }
+ VGAwGR(0x9F, par->VCLK3Denominator);
+ }
+
+ if (par->biosMode)
+ VGAwCR(0x23, par->biosMode);
+
+ VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
+
+ /* Program vertical extension register */
+ if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+ {
+ VGAwCR(0x70, par->VerticalExt);
+ }
+
+
+ vgaHWProtect (0); /* Turn on screen */
+
+ /* Calling this also locks offset registers required in update_start */
+ neoLock();
+}
+
+static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
+{
+ int oldExtCRTDispAddr;
+ int Base;
+
+ DBG("neofb_update_start");
+
+ Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+ Base *= (var->bits_per_pixel + 7) / 8;
+
+ neoUnlock();
+
+ /*
+ * These are the generic starting address registers.
+ */
+ VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+ VGAwCR(0x0D, (Base & 0x00FF));
+
+ /*
+ * Make sure we don't clobber some other bits that might already
+ * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+ * be needed.
+ */
+ oldExtCRTDispAddr = VGArGR(0x0E);
+ VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+ neoLock();
+}
+
+/*
+ * Set the Colormap
+ */
+static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+ struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
+ struct fb_cmap *dcmap = &disp->cmap;
+ int err = 0;
+
+ /* no colormap allocated? */
+ if (!dcmap->len)
+ {
+ int size;
+
+ if (fb->var.bits_per_pixel == 8)
+ size = NR_PALETTE;
+ else
+ size = 32;
+
+ err = fb_alloc_cmap (dcmap, size, 0);
+ }
+
+ /*
+ * we should be able to remove this test once fbcon has been
+ * "improved" --rmk
+ */
+ if (!err && con == info->currcon)
+ {
+ err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
+ dcmap = &fb->cmap;
+ }
+
+ if (!err)
+ fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
+
+ return err;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 14.31818
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
+{
+ int n, d, f;
+ double f_out;
+ double f_diff;
+ int n_best = 0, d_best = 0, f_best = 0;
+ double f_best_diff = 999999.0;
+ double f_target = freq/1000.0;
+
+ for (f = 0; f <= MAX_F; f++)
+ for (n = 0; n <= MAX_N; n++)
+ for (d = 0; d <= MAX_D; d++)
+ {
+ f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
+ f_diff = abs(f_out-f_target);
+ if (f_diff < f_best_diff)
+ {
+ f_best_diff = f_diff;
+ n_best = n;
+ d_best = d;
+ f_best = f;
+ }
+ }
+
+ if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+ info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+ {
+ /* NOT_DONE: We are trying the full range of the 2200 clock.
+ We should be able to try n up to 2047 */
+ par->VCLK3NumeratorLow = n_best;
+ par->VCLK3NumeratorHigh = (f_best << 7);
+ }
+ else
+ par->VCLK3NumeratorLow = n_best | (f_best << 7);
+
+ par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+ printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
+ f_target,
+ par->VCLK3NumeratorLow,
+ par->VCLK3NumeratorHigh,
+ par->VCLK3Denominator,
+ f_best_diff);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ * Handle the initialization, etc. of a screen.
+ * Return FALSE on failure.
+ */
+
+static int vgaHWInit (const struct fb_var_screeninfo *var,
+ const struct neofb_info *info,
+ struct neofb_par *par,
+ struct xtimings *timings)
+{
+ par->MiscOutReg = 0x23;
+
+ if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+ par->MiscOutReg |= 0x40;
+
+ if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+ par->MiscOutReg |= 0x80;
+
+ /*
+ * Time Sequencer
+ */
+ par->Sequencer[0] = 0x00;
+ par->Sequencer[1] = 0x01;
+ par->Sequencer[2] = 0x0F;
+ par->Sequencer[3] = 0x00; /* Font select */
+ par->Sequencer[4] = 0x0E; /* Misc */
+
+ /*
+ * CRTC Controller
+ */
+ par->CRTC[0] = (timings->HTotal >> 3) - 5;
+ par->CRTC[1] = (timings->HDisplay >> 3) - 1;
+ par->CRTC[2] = (timings->HDisplay >> 3) - 1;
+ par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+ par->CRTC[4] = (timings->HSyncStart >> 3);
+ par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+ | (((timings->HSyncEnd >> 3)) & 0x1F);
+ par->CRTC[6] = (timings->VTotal - 2) & 0xFF;
+ par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8)
+ | (((timings->VDisplay - 1) & 0x100) >> 7)
+ | ((timings->VSyncStart & 0x100) >> 6)
+ | (((timings->VDisplay - 1) & 0x100) >> 5)
+ | 0x10
+ | (((timings->VTotal - 2) & 0x200) >> 4)
+ | (((timings->VDisplay - 1) & 0x200) >> 3)
+ | ((timings->VSyncStart & 0x200) >> 2);
+ par->CRTC[8] = 0x00;
+ par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+ if (timings->dblscan)
+ par->CRTC[9] |= 0x80;
+
+ par->CRTC[10] = 0x00;
+ par->CRTC[11] = 0x00;
+ par->CRTC[12] = 0x00;
+ par->CRTC[13] = 0x00;
+ par->CRTC[14] = 0x00;
+ par->CRTC[15] = 0x00;
+ par->CRTC[16] = timings->VSyncStart & 0xFF;
+ par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+ par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+ par->CRTC[19] = var->xres_virtual >> 4;
+ par->CRTC[20] = 0x00;
+ par->CRTC[21] = (timings->VDisplay - 1) & 0xFF;
+ par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+ par->CRTC[23] = 0xC3;
+ par->CRTC[24] = 0xFF;
+
+ /*
+ * are these unnecessary?
+ * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+ * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+ */
+
+ /*
+ * Graphics Display Controller
+ */
+ par->Graphics[0] = 0x00;
+ par->Graphics[1] = 0x00;
+ par->Graphics[2] = 0x00;
+ par->Graphics[3] = 0x00;
+ par->Graphics[4] = 0x00;
+ par->Graphics[5] = 0x40;
+ par->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */
+ par->Graphics[7] = 0x0F;
+ par->Graphics[8] = 0xFF;
+
+
+ par->Attribute[0] = 0x00; /* standard colormap translation */
+ par->Attribute[1] = 0x01;
+ par->Attribute[2] = 0x02;
+ par->Attribute[3] = 0x03;
+ par->Attribute[4] = 0x04;
+ par->Attribute[5] = 0x05;
+ par->Attribute[6] = 0x06;
+ par->Attribute[7] = 0x07;
+ par->Attribute[8] = 0x08;
+ par->Attribute[9] = 0x09;
+ par->Attribute[10] = 0x0A;
+ par->Attribute[11] = 0x0B;
+ par->Attribute[12] = 0x0C;
+ par->Attribute[13] = 0x0D;
+ par->Attribute[14] = 0x0E;
+ par->Attribute[15] = 0x0F;
+ par->Attribute[16] = 0x41;
+ par->Attribute[17] = 0xFF;
+ par->Attribute[18] = 0x0F;
+ par->Attribute[19] = 0x00;
+ par->Attribute[20] = 0x00;
+
+ return 0;
+}
+
+static int neofb_decode_var (struct fb_var_screeninfo *var,
+ const struct neofb_info *info,
+ struct neofb_par *par)
+{
+ struct xtimings timings;
+ int lcd_stretch;
+ int hoffset, voffset;
+ int memlen, vramlen;
+ int mode_ok = 0;
+ unsigned int pixclock = var->pixclock;
+
+ DBG("neofb_decode_var");
+
+ if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
+ timings.pixclock = 1000000000 / pixclock;
+ if (timings.pixclock < 1) timings.pixclock = 1;
+ timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+ timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+ timings.HDisplay = var->xres;
+ timings.HSyncStart = timings.HDisplay + var->right_margin;
+ timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+ timings.HTotal = timings.HSyncEnd + var->left_margin;
+ timings.VDisplay = var->yres;
+ timings.VSyncStart = timings.VDisplay + var->lower_margin;
+ timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+ timings.VTotal = timings.VSyncEnd + var->upper_margin;
+ timings.sync = var->sync;
+
+ if (timings.pixclock > info->maxClock)
+ return -EINVAL;
+
+ /* Is the mode larger than the LCD panel? */
+ if ((var->xres > info->NeoPanelWidth) ||
+ (var->yres > info->NeoPanelHeight))
+ {
+ printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+ var->xres,
+ var->yres,
+ info->NeoPanelWidth,
+ info->NeoPanelHeight);
+ return -EINVAL;
+ }
+
+ /* Is the mode one of the acceptable sizes? */
+ switch (var->xres)
+ {
+ case 1280:
+ if (var->yres == 1024)
+ mode_ok = 1;
+ break;
+ case 1024:
+ if (var->yres == 768)
+ mode_ok = 1;
+ break;
+ case 800:
+ if (var->yres == 600)
+ mode_ok = 1;
+ break;
+ case 640:
+ if (var->yres == 480)
+ mode_ok = 1;
+ break;
+ }
+
+ if (!mode_ok)
+ {
+ printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
+ var->xres, var->yres);
+ return -EINVAL;
+ }
+
+
+ switch (var->bits_per_pixel)
+ {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+ case 32:
+ break;
+# endif
+#endif
+
+ default:
+ return -EINVAL;
+ }
+
+ par->depth = var->bits_per_pixel;
+
+ vramlen = info->video.len;
+ if (vramlen > 4*1024*1024)
+ vramlen = 4*1024*1024;
+
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+ memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+ if (memlen > vramlen)
+ {
+ var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+ memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+ }
+
+ /* we must round yres/xres down, we already rounded y/xres_virtual up
+ if it was possible. We should return -EINVAL, but I disagree */
+ if (var->yres_virtual < var->yres)
+ var->yres = var->yres_virtual;
+ if (var->xres_virtual < var->xres)
+ var->xres = var->xres_virtual;
+ if (var->xoffset + var->xres > var->xres_virtual)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yoffset + var->yres > var->yres_virtual)
+ var->yoffset = var->yres_virtual - var->yres;
+
+
+ /*
+ * This will allocate the datastructure and initialize all of the
+ * generic VGA registers.
+ */
+
+ if (vgaHWInit (var, info, par, &timings))
+ return -EINVAL;
+
+ /*
+ * The default value assigned by vgaHW.c is 0x41, but this does
+ * not work for NeoMagic.
+ */
+ par->Attribute[16] = 0x01;
+
+ switch (var->bits_per_pixel)
+ {
+ case 8:
+ par->CRTC[0x13] = var->xres_virtual >> 3;
+ par->ExtCRTOffset = var->xres_virtual >> 11;
+ par->ExtColorModeSelect = 0x11;
+ break;
+ case 16:
+ par->CRTC[0x13] = var->xres_virtual >> 2;
+ par->ExtCRTOffset = var->xres_virtual >> 10;
+ par->ExtColorModeSelect = 0x13;
+ break;
+ case 24:
+ par->CRTC[0x13] = (var->xres_virtual * 3) >> 3;
+ par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
+ par->ExtColorModeSelect = 0x14;
+ break;
+#ifdef NO_32BIT_SUPPORT_YET
+ case 32: /* FIXME: guessed values */
+ par->CRTC[0x13] = var->xres_virtual >> 1;
+ par->ExtCRTOffset = var->xres_virtual >> 9;
+ par->ExtColorModeSelect = 0x15;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ par->ExtCRTDispAddr = 0x10;
+
+ /* Vertical Extension */
+ par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
+ | (((timings.VDisplay -1) & 0x400) >> 9 )
+ | (((timings.VSyncStart) & 0x400) >> 8 )
+ | (((timings.VSyncStart) & 0x400) >> 7 );
+
+ /* Fast write bursts on unless disabled. */
+ if (info->pci_burst)
+ par->SysIfaceCntl1 = 0x30;
+ else
+ par->SysIfaceCntl1 = 0x00;
+
+ par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
+
+ /* Enable any user specified display devices. */
+ par->PanelDispCntlReg1 = 0x00;
+ if (info->internal_display)
+ par->PanelDispCntlReg1 |= 0x02;
+ if (info->external_display)
+ par->PanelDispCntlReg1 |= 0x01;
+
+ /* If the user did not specify any display devices, then... */
+ if (par->PanelDispCntlReg1 == 0x00) {
+ /* Default to internal (i.e., LCD) only. */
+ par->PanelDispCntlReg1 |= 0x02;
+ }
+
+ /* If we are using a fixed mode, then tell the chip we are. */
+ switch (var->xres)
+ {
+ case 1280:
+ par->PanelDispCntlReg1 |= 0x60;
+ break;
+ case 1024:
+ par->PanelDispCntlReg1 |= 0x40;
+ break;
+ case 800:
+ par->PanelDispCntlReg1 |= 0x20;
+ break;
+ case 640:
+ default:
+ break;
+ }
+
+ /* Setup shadow register locking. */
+ switch (par->PanelDispCntlReg1 & 0x03)
+ {
+ case 0x01: /* External CRT only mode: */
+ par->GeneralLockReg = 0x00;
+ /* We need to program the VCLK for external display only mode. */
+ par->ProgramVCLK = 1;
+ break;
+ case 0x02: /* Internal LCD only mode: */
+ case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
+ par->GeneralLockReg = 0x01;
+ /* Don't program the VCLK when using the LCD. */
+ par->ProgramVCLK = 0;
+ break;
+ }
+
+ /*
+ * If the screen is to be stretched, turn on stretching for the
+ * various modes.
+ *
+ * OPTION_LCD_STRETCH means stretching should be turned off!
+ */
+ par->PanelDispCntlReg2 = 0x00;
+ par->PanelDispCntlReg3 = 0x00;
+
+ if (info->lcd_stretch &&
+ (par->PanelDispCntlReg1 == 0x02) && /* LCD only */
+ (var->xres != info->NeoPanelWidth))
+ {
+ switch (var->xres)
+ {
+ case 320: /* Needs testing. KEM -- 24 May 98 */
+ case 400: /* Needs testing. KEM -- 24 May 98 */
+ case 640:
+ case 800:
+ case 1024:
+ lcd_stretch = 1;
+ par->PanelDispCntlReg2 |= 0xC6;
+ break;
+ default:
+ lcd_stretch = 0;
+ /* No stretching in these modes. */
+ }
+ }
+ else
+ lcd_stretch = 0;
+
+ /*
+ * If the screen is to be centerd, turn on the centering for the
+ * various modes.
+ */
+ par->PanelVertCenterReg1 = 0x00;
+ par->PanelVertCenterReg2 = 0x00;
+ par->PanelVertCenterReg3 = 0x00;
+ par->PanelVertCenterReg4 = 0x00;
+ par->PanelVertCenterReg5 = 0x00;
+ par->PanelHorizCenterReg1 = 0x00;
+ par->PanelHorizCenterReg2 = 0x00;
+ par->PanelHorizCenterReg3 = 0x00;
+ par->PanelHorizCenterReg4 = 0x00;
+ par->PanelHorizCenterReg5 = 0x00;
+
+
+ if (par->PanelDispCntlReg1 & 0x02)
+ {
+ if (var->xres == info->NeoPanelWidth)
+ {
+ /*
+ * No centering required when the requested display width
+ * equals the panel width.
+ */
+ }
+ else
+ {
+ par->PanelDispCntlReg2 |= 0x01;
+ par->PanelDispCntlReg3 |= 0x10;
+
+ /* Calculate the horizontal and vertical offsets. */
+ if (!lcd_stretch)
+ {
+ hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
+ voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
+ }
+ else
+ {
+ /* Stretched modes cannot be centered. */
+ hoffset = 0;
+ voffset = 0;
+ }
+
+ switch (var->xres)
+ {
+ case 320: /* Needs testing. KEM -- 24 May 98 */
+ par->PanelHorizCenterReg3 = hoffset;
+ par->PanelVertCenterReg2 = voffset;
+ break;
+ case 400: /* Needs testing. KEM -- 24 May 98 */
+ par->PanelHorizCenterReg4 = hoffset;
+ par->PanelVertCenterReg1 = voffset;
+ break;
+ case 640:
+ par->PanelHorizCenterReg1 = hoffset;
+ par->PanelVertCenterReg3 = voffset;
+ break;
+ case 800:
+ par->PanelHorizCenterReg2 = hoffset;
+ par->PanelVertCenterReg4 = voffset;
+ break;
+ case 1024:
+ par->PanelHorizCenterReg5 = hoffset;
+ par->PanelVertCenterReg5 = voffset;
+ break;
+ case 1280:
+ default:
+ /* No centering in these modes. */
+ break;
+ }
+ }
+ }
+
+ par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
+
+ /*
+ * Calculate the VCLK that most closely matches the requested dot
+ * clock.
+ */
+ neoCalcVCLK (info, par, timings.pixclock);
+
+ /* Since we program the clocks ourselves, always use VCLK3. */
+ par->MiscOutReg |= 0x0C;
+
+ return 0;
+}
+
+static int neofb_set_var (struct fb_var_screeninfo *var, int con,
+ struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+ struct display *display;
+ struct neofb_par par;
+ int err, chgvar = 0;
+
+ DBG("neofb_set_var");
+
+ err = neofb_decode_var (var, info, &par);
+ if (err)
+ return err;
+
+ if (var->activate & FB_ACTIVATE_TEST)
+ return 0;
+
+ if (con < 0)
+ {
+ display = fb->disp;
+ chgvar = 0;
+ }
+ else
+ {
+ display = fb_display + con;
+
+ if (fb->var.xres != var->xres)
+ chgvar = 1;
+ if (fb->var.yres != var->yres)
+ chgvar = 1;
+ if (fb->var.xres_virtual != var->xres_virtual)
+ chgvar = 1;
+ if (fb->var.yres_virtual != var->yres_virtual)
+ chgvar = 1;
+ if (fb->var.bits_per_pixel != var->bits_per_pixel)
+ chgvar = 1;
+ }
+
+ if (!info->neo2200)
+ var->accel_flags &= ~FB_ACCELF_TEXT;
+
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+
+ switch (var->bits_per_pixel)
+ {
+#ifdef FBCON_HAS_CFB8
+ case 8: /* PSEUDOCOLOUR, 256 */
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->dispsw = &fbcon_cfb8;
+ display->dispsw_data = NULL;
+ display->next_line = var->xres_virtual;
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+ case 16: /* DIRECTCOLOUR, 64k */
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+
+ fb->fix.visual = FB_VISUAL_DIRECTCOLOR;
+ info->dispsw = &fbcon_cfb16;
+ display->dispsw_data = fb->pseudo_palette;
+ display->next_line = var->xres_virtual * 2;
+ break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+ case 24: /* TRUECOLOUR, 16m */
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ fb->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->dispsw = &fbcon_cfb24;
+ display->dispsw_data = fb->pseudo_palette;
+ display->next_line = var->xres_virtual * 3;
+
+ var->accel_flags &= ~FB_ACCELF_TEXT;
+ break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+ case 32: /* TRUECOLOUR, 16m */
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+
+ fb->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->dispsw = &fbcon_cfb32;
+ display->dispsw_data = fb->pseudo_palette;
+ display->next_line = var->xres_virtual * 4;
+
+ var->accel_flags &= ~FB_ACCELF_TEXT;
+ break;
+# endif
+#endif
+
+ default:
+ printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
+ info->dispsw = &fbcon_dummy;
+ var->accel_flags &= ~FB_ACCELF_TEXT;
+ break;
+ }
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ display->dispsw = &fbcon_neo2200_accel;
+ else
+ display->dispsw = info->dispsw;
+
+ fb->fix.line_length = display->next_line;
+
+ display->screen_base = fb->screen_base;
+ display->line_length = fb->fix.line_length;
+ display->visual = fb->fix.visual;
+ display->type = fb->fix.type;
+ display->type_aux = fb->fix.type_aux;
+ display->ypanstep = fb->fix.ypanstep;
+ display->ywrapstep = fb->fix.ywrapstep;
+ display->can_soft_blank = 1;
+ display->inverse = 0;
+
+ fb->var = *var;
+ fb->var.activate &= ~FB_ACTIVATE_ALL;
+
+ /*
+ * Update the old var. The fbcon drivers still use this.
+ * Once they are using cfb->fb.var, this can be dropped.
+ * --rmk
+ */
+ display->var = fb->var;
+
+ /*
+ * If we are setting all the virtual consoles, also set the
+ * defaults used to create new consoles.
+ */
+ if (var->activate & FB_ACTIVATE_ALL)
+ fb->disp->var = fb->var;
+
+ if (chgvar && fb && fb->changevar)
+ fb->changevar (con);
+
+ if (con == info->currcon)
+ {
+ if (chgvar || con < 0)
+ neofb_set_par (info, &par);
+
+ neofb_update_start (info, var);
+ fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ neo2200_accel_init (info, var);
+ }
+
+ return 0;
+}
+
+/*
+ * Pan or Wrap the Display
+ */
+static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
+ struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+ u_int y_bottom;
+
+ y_bottom = var->yoffset;
+
+ if (!(var->vmode & FB_VMODE_YWRAP))
+ y_bottom += var->yres;
+
+ if (var->xoffset > (var->xres_virtual - var->xres))
+ return -EINVAL;
+ if (y_bottom > fb->var.yres_virtual)
+ return -EINVAL;
+
+ neofb_update_start (info, var);
+
+ fb->var.xoffset = var->xoffset;
+ fb->var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ fb->var.vmode |= FB_VMODE_YWRAP;
+ else
+ fb->var.vmode &= ~FB_VMODE_YWRAP;
+
+ return 0;
+}
+
+
+/*
+ * Update the `var' structure (called by fbcon.c)
+ *
+ * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ * Since it's called by a kernel driver, no range checking is done.
+ */
+static int neofb_updatevar (int con, struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+
+ neofb_update_start (info, &fb_display[con].var);
+
+ return 0;
+}
+
+static int neofb_switch (int con, struct fb_info *fb)
+{
+ struct neofb_info *info = (struct neofb_info *)fb;
+ struct display *disp;
+ struct fb_cmap *cmap;
+
+ if (info->currcon >= 0)
+ {
+ disp = fb_display + info->currcon;
+
+ /*
+ * Save the old colormap and video mode.
+ */
+ disp->var = fb->var;
+ if (disp->cmap.len)
+ fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
+ }
+
+ info->currcon = con;
+ disp = fb_display + con;
+
+ /*
+ * Install the new colormap and change the video mode. By default,
+ * fbcon sets all the colormaps and video modes to the default
+ * values at bootup.
+ *
+ * Really, we want to set the colourmap size depending on the
+ * depth of the new video mode. For now, we leave it at its
+ * default 256 entry.
+ */
+ if (disp->cmap.len)
+ cmap = &disp->cmap;
+ else
+ cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+ fb_copy_cmap(cmap, &fb->cmap, 0);
+
+ disp->var.activate = FB_ACTIVATE_NOW;
+ neofb_set_var(&disp->var, con, fb);
+
+ return 0;
+}
+
+/*
+ * (Un)Blank the display.
+ */
+static void neofb_blank (int blank, struct fb_info *fb)
+{
+ // struct neofb_info *info = (struct neofb_info *)fb;
+
+ /*
+ * Blank the screen if blank_mode != 0, else unblank. If
+ * blank == NULL then the caller blanks by setting the CLUT
+ * (Color Look Up Table) to all black. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed due to e.g. a
+ * video mode which doesn't support it. Implements VESA
+ * suspend and powerdown modes on hardware that supports
+ * disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ *
+ * wms...Enable VESA DMPS compatible powerdown mode
+ * run "setterm -powersave powerdown" to take advantage
+ */
+
+ switch (blank)
+ {
+ case 4: /* powerdown - both sync lines down */
+ break;
+ case 3: /* hsync off */
+ break;
+ case 2: /* vsync off */
+ break;
+ case 1: /* just software blanking of screen */
+ break;
+ default: /* case 0, or anything else: unblank */
+ break;
+ }
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
+{
+ fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+ *fix = fb->fix;
+ return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+ *var = fb->var;
+ return 0;
+}
+
+static struct fb_ops neofb_ops = {
+ owner: THIS_MODULE,
+ fb_set_var: neofb_set_var,
+ fb_set_cmap: neofb_set_cmap,
+ fb_pan_display: neofb_pan_display,
+ fb_get_fix: gen_get_fix,
+ fb_get_var: gen_get_var,
+ fb_get_cmap: gen_get_cmap,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
+ accel_flags: FB_ACCELF_TEXT,
+ xres: 640,
+ yres: 480,
+ xres_virtual: 640,
+ yres_virtual: 30000,
+ bits_per_pixel: 8,
+ pixclock: 39722,
+ left_margin: 48,
+ right_margin: 16,
+ upper_margin: 33,
+ lower_margin: 10,
+ hsync_len: 96,
+ vsync_len: 2,
+ sync: 0,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
+ accel_flags: FB_ACCELF_TEXT,
+ xres: 800,
+ yres: 600,
+ xres_virtual: 800,
+ yres_virtual: 30000,
+ bits_per_pixel: 8,
+ pixclock: 25000,
+ left_margin: 88,
+ right_margin: 40,
+ upper_margin: 23,
+ lower_margin: 1,
+ hsync_len: 128,
+ vsync_len: 4,
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
+ accel_flags: FB_ACCELF_TEXT,
+ xres: 1024,
+ yres: 768,
+ xres_virtual: 1024,
+ yres_virtual: 30000,
+ bits_per_pixel: 8,
+ pixclock: 15385,
+ left_margin: 160,
+ right_margin: 24,
+ upper_margin: 29,
+ lower_margin: 3,
+ hsync_len: 136,
+ vsync_len: 6,
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
+#ifdef NOT_DONE
+static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
+ accel_flags: FB_ACCELF_TEXT,
+ xres: 1280,
+ yres: 1024,
+ xres_virtual: 1280,
+ yres_virtual: 30000,
+ bits_per_pixel: 8,
+ pixclock: 9260,
+ left_margin: 248,
+ right_margin: 48,
+ upper_margin: 38,
+ lower_margin: 1,
+ hsync_len: 112,
+ vsync_len: 3,
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+#endif
+
+static struct fb_var_screeninfo *neofb_var = NULL;
+
+
+static int __devinit neo_map_mmio (struct neofb_info *info)
+{
+ DBG("neo_map_mmio");
+
+ info->mmio.pbase = pci_resource_start (info->pcidev, 1);
+ info->mmio.len = MMIO_SIZE;
+
+ if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
+ {
+ printk ("neofb: memory mapped IO in use\n");
+ return -EBUSY;
+ }
+
+ info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
+ if (!info->mmio.vbase)
+ {
+ printk ("neofb: unable to map memory mapped IO\n");
+ release_mem_region (info->mmio.pbase, info->mmio.len);
+ return -ENOMEM;
+ }
+ else
+ printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+
+ info->fb.fix.mmio_start = info->mmio.pbase;
+ info->fb.fix.mmio_len = info->mmio.len;
+
+ return 0;
+}
+
+static void __devinit neo_unmap_mmio (struct neofb_info *info)
+{
+ DBG("neo_unmap_mmio");
+
+ if (info->mmio.vbase)
+ {
+ iounmap (info->mmio.vbase);
+ info->mmio.vbase = NULL;
+
+ release_mem_region (info->mmio.pbase, info->mmio.len);
+ }
+}
+
+static int __devinit neo_map_video (struct neofb_info *info, int video_len)
+{
+ DBG("neo_map_video");
+
+ info->video.pbase = pci_resource_start (info->pcidev, 0);
+ info->video.len = video_len;
+
+ if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
+ {
+ printk ("neofb: frame buffer in use\n");
+ return -EBUSY;
+ }
+
+ info->video.vbase = ioremap (info->video.pbase, info->video.len);
+ if (!info->video.vbase)
+ {
+ printk ("neofb: unable to map screen memory\n");
+ release_mem_region (info->video.pbase, info->video.len);
+ return -ENOMEM;
+ }
+ else
+ printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+
+ info->fb.fix.smem_start = info->video.pbase;
+ info->fb.fix.smem_len = info->video.len;
+ info->fb.screen_base = info->video.vbase;
+
+#ifdef CONFIG_MTRR
+ info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+#endif
+
+ /* Clear framebuffer, it's all white in memory after boot */
+ memset (info->video.vbase, 0, info->video.len);
+
+ return 0;
+}
+
+static void __devinit neo_unmap_video (struct neofb_info *info)
+{
+ DBG("neo_unmap_video");
+
+ if (info->video.vbase)
+ {
+#ifdef CONFIG_MTRR
+ mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
+#endif
+
+ iounmap (info->video.vbase);
+ info->video.vbase = NULL;
+ info->fb.screen_base = NULL;
+
+ release_mem_region (info->video.pbase, info->video.len);
+ }
+}
+
+static int __devinit neo_init_hw (struct neofb_info *info)
+{
+ int videoRam = 896;
+ int maxClock = 65000;
+ int CursorMem = 1024;
+ int CursorOff = 0x100;
+ int linearSize = 1024;
+ int maxWidth = 1024;
+ int maxHeight = 1024;
+ unsigned char type, display;
+ int w;
+
+ DBG("neo_init_hw");
+
+ neoUnlock();
+
+#if 0
+ printk (KERN_DEBUG "--- Neo extended register dump ---\n");
+ for (w=0; w<0x85; w++)
+ printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
+ for (w=0; w<0xC7; w++)
+ printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
+#endif
+
+ /* Determine the panel type */
+ VGAwGR(0x09,0x26);
+ type = VGArGR(0x21);
+ display = VGArGR(0x20);
+
+ /* Determine panel width -- used in NeoValidMode. */
+ w = VGArGR(0x20);
+ VGAwGR(0x09,0x00);
+ switch ((w & 0x18) >> 3)
+ {
+ case 0x00:
+ info->NeoPanelWidth = 640;
+ info->NeoPanelHeight = 480;
+ neofb_var = &neofb_var640x480x8;
+ break;
+ case 0x01:
+ info->NeoPanelWidth = 800;
+ info->NeoPanelHeight = 600;
+ neofb_var = &neofb_var800x600x8;
+ break;
+ case 0x02:
+ info->NeoPanelWidth = 1024;
+ info->NeoPanelHeight = 768;
+ neofb_var = &neofb_var1024x768x8;
+ break;
+ case 0x03:
+ /* 1280x1024 panel support needs to be added */
+#ifdef NOT_DONE
+ info->NeoPanelWidth = 1280;
+ info->NeoPanelHeight = 1024;
+ neofb_var = &neofb_var1280x1024x8;
+ break;
+#else
+ printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+ return -1;
+#endif
+ default:
+ info->NeoPanelWidth = 640;
+ info->NeoPanelHeight = 480;
+ neofb_var = &neofb_var640x480x8;
+ break;
+ }
+
+ printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
+ info->NeoPanelWidth,
+ info->NeoPanelHeight,
+ (type & 0x02) ? "color" : "monochrome",
+ (type & 0x10) ? "TFT" : "dual scan");
+
+ switch (info->accel)
+ {
+ case FB_ACCEL_NEOMAGIC_NM2070:
+ videoRam = 896;
+ maxClock = 65000;
+ CursorMem = 2048;
+ CursorOff = 0x100;
+ linearSize = 1024;
+ maxWidth = 1024;
+ maxHeight = 1024;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2090:
+ case FB_ACCEL_NEOMAGIC_NM2093:
+ videoRam = 1152;
+ maxClock = 80000;
+ CursorMem = 2048;
+ CursorOff = 0x100;
+ linearSize = 2048;
+ maxWidth = 1024;
+ maxHeight = 1024;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2097:
+ videoRam = 1152;
+ maxClock = 80000;
+ CursorMem = 1024;
+ CursorOff = 0x100;
+ linearSize = 2048;
+ maxWidth = 1024;
+ maxHeight = 1024;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2160:
+ videoRam = 2048;
+ maxClock = 90000;
+ CursorMem = 1024;
+ CursorOff = 0x100;
+ linearSize = 2048;
+ maxWidth = 1024;
+ maxHeight = 1024;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2200:
+ videoRam = 2560;
+ maxClock = 110000;
+ CursorMem = 1024;
+ CursorOff = 0x1000;
+ linearSize = 4096;
+ maxWidth = 1280;
+ maxHeight = 1024; /* ???? */
+
+ info->neo2200 = (Neo2200*) info->mmio.vbase;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2230:
+ videoRam = 3008;
+ maxClock = 110000;
+ CursorMem = 1024;
+ CursorOff = 0x1000;
+ linearSize = 4096;
+ maxWidth = 1280;
+ maxHeight = 1024; /* ???? */
+
+ info->neo2200 = (Neo2200*) info->mmio.vbase;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2360:
+ videoRam = 4096;
+ maxClock = 110000;
+ CursorMem = 1024;
+ CursorOff = 0x1000;
+ linearSize = 4096;
+ maxWidth = 1280;
+ maxHeight = 1024; /* ???? */
+
+ info->neo2200 = (Neo2200*) info->mmio.vbase;
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2380:
+ videoRam = 6144;
+ maxClock = 110000;
+ CursorMem = 1024;
+ CursorOff = 0x1000;
+ linearSize = 8192;
+ maxWidth = 1280;
+ maxHeight = 1024; /* ???? */
+
+ info->neo2200 = (Neo2200*) info->mmio.vbase;
+ break;
+ }
+
+ info->maxClock = maxClock;
+
+ return videoRam * 1024;
+}
+
+
+static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct neofb_info *info;
+
+ info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
+ sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!info)
+ return NULL;
+
+ memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
+
+ info->currcon = -1;
+ info->pcidev = dev;
+ info->accel = id->driver_data;
+
+ info->pci_burst = !nopciburst;
+ info->lcd_stretch = !nostretch;
+
+ if (!internal && !external)
+ {
+ info->internal_display = 1;
+ info->external_display = 0;
+ }
+ else
+ {
+ info->internal_display = internal;
+ info->external_display = external;
+ }
+
+ switch (info->accel)
+ {
+ case FB_ACCEL_NEOMAGIC_NM2070:
+ sprintf (info->fb.fix.id, "MagicGraph 128");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2090:
+ sprintf (info->fb.fix.id, "MagicGraph 128V");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2093:
+ sprintf (info->fb.fix.id, "MagicGraph 128ZV");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2097:
+ sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2160:
+ sprintf (info->fb.fix.id, "MagicGraph 128XD");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2200:
+ sprintf (info->fb.fix.id, "MagicGraph 256AV");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2230:
+ sprintf (info->fb.fix.id, "MagicGraph 256AV+");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2360:
+ sprintf (info->fb.fix.id, "MagicGraph 256ZX");
+ break;
+ case FB_ACCEL_NEOMAGIC_NM2380:
+ sprintf (info->fb.fix.id, "MagicGraph 256XL+");
+ break;
+ }
+
+ info->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fb.fix.type_aux = 0;
+ info->fb.fix.xpanstep = 0;
+ info->fb.fix.ypanstep = 4;
+ info->fb.fix.ywrapstep = 0;
+ info->fb.fix.accel = id->driver_data;
+
+ info->fb.var.nonstd = 0;
+ info->fb.var.activate = FB_ACTIVATE_NOW;
+ info->fb.var.height = -1;
+ info->fb.var.width = -1;
+ info->fb.var.accel_flags = 0;
+
+ strcpy (info->fb.modename, info->fb.fix.id);
+
+ info->fb.fbops = &neofb_ops;
+ info->fb.changevar = NULL;
+ info->fb.switch_con = neofb_switch;
+ info->fb.updatevar = neofb_updatevar;
+ info->fb.blank = neofb_blank;
+ info->fb.flags = FBINFO_FLAG_DEFAULT;
+ info->fb.disp = (struct display *)(info + 1);
+ info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
+
+ fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
+
+ return info;
+}
+
+static void __devinit neo_free_fb_info (struct neofb_info *info)
+{
+ if (info)
+ {
+ /*
+ * Free the colourmap
+ */
+ fb_alloc_cmap (&info->fb.cmap, 0, 0);
+
+ kfree (info);
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+{
+ struct neofb_info *info;
+ u_int h_sync, v_sync;
+ int err;
+ int video_len;
+
+ DBG("neofb_probe");
+
+ err = pci_enable_device (dev);
+ if (err)
+ return err;
+
+ err = -ENOMEM;
+ info = neo_alloc_fb_info (dev, id);
+ if (!info)
+ goto failed;
+
+ err = neo_map_mmio (info);
+ if (err)
+ goto failed;
+
+ video_len = neo_init_hw (info);
+ if (video_len < 0)
+ {
+ err = video_len;
+ goto failed;
+ }
+
+ err = neo_map_video (info, video_len);
+ if (err)
+ goto failed;
+
+ neofb_set_var (neofb_var, -1, &info->fb);
+
+ /*
+ * Calculate the hsync and vsync frequencies. Note that
+ * we split the 1e12 constant up so that we can preserve
+ * the precision and fit the results into 32-bit registers.
+ * (1953125000 * 512 = 1e12)
+ */
+ h_sync = 1953125000 / info->fb.var.pixclock;
+ h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
+ info->fb.var.right_margin + info->fb.var.hsync_len);
+ v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
+ info->fb.var.lower_margin + info->fb.var.vsync_len);
+
+ printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ info->fb.fix.smem_len >> 10,
+ info->fb.var.xres, info->fb.var.yres,
+ h_sync / 1000, h_sync % 1000, v_sync);
+
+
+ err = register_framebuffer (&info->fb);
+ if (err < 0)
+ goto failed;
+
+ printk (KERN_INFO "fb%d: %s frame buffer device\n",
+ GET_FB_IDX(info->fb.node), info->fb.modename);
+
+ /*
+ * Our driver data
+ */
+ dev->driver_data = info;
+
+ return 0;
+
+failed:
+ neo_unmap_video (info);
+ neo_unmap_mmio (info);
+ neo_free_fb_info (info);
+
+ return err;
+}
+
+static void __devexit neofb_remove (struct pci_dev *dev)
+{
+ struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+
+ DBG("neofb_remove");
+
+ if (info)
+ {
+ /*
+ * If unregister_framebuffer fails, then
+ * we will be leaving hooks that could cause
+ * oopsen laying around.
+ */
+ if (unregister_framebuffer (&info->fb))
+ printk (KERN_WARNING "neofb: danger danger! Oopsen imminent!\n");
+
+ neo_unmap_video (info);
+ neo_unmap_mmio (info);
+ neo_free_fb_info (info);
+
+ /*
+ * Ensure that the driver data is no longer
+ * valid.
+ */
+ dev->driver_data = NULL;
+ }
+}
+
+static struct pci_device_id neofb_devices[] __devinitdata = {
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+ {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+ name: "neofb",
+ id_table: neofb_devices,
+ probe: neofb_probe,
+ remove: neofb_remove
+};
+
+/* **************************** init-time only **************************** */
+
+static void __init neo_init (void)
+{
+ DBG("neo_init");
+ pci_register_driver (&neofb_driver);
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit neo_done (void)
+{
+ DBG("neo_done");
+ pci_unregister_driver (&neofb_driver);
+}
+
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init neofb_setup (char *options)
+{
+ char *this_opt;
+
+ DBG("neofb_setup");
+
+ if (!options || !*options)
+ return 0;
+
+ for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
+ {
+ if (!*this_opt) continue;
+
+ if (!strncmp(this_opt, "disabled", 8))
+ disabled = 1;
+ if (!strncmp(this_opt, "internal", 8))
+ internal = 1;
+ if (!strncmp(this_opt, "external", 8))
+ external = 1;
+ if (!strncmp(this_opt, "nostretch", 9))
+ nostretch = 1;
+ if (!strncmp(this_opt, "nopciburst", 10))
+ nopciburst = 1;
+ }
+
+ return 0;
+}
+
+static int __init initialized = 0;
+
+int __init neofb_init(void)
+{
+ DBG("neofb_init");
+
+ if (disabled)
+ return -ENXIO;
+
+ if (!initialized)
+ {
+ initialized = 1;
+ neo_init();
+ }
+
+ /* never return failure, user can hotplug card later... */
+ return 0;
+}
+
+#else
+
+/* *************************** init module code **************************** */
+
+int __init init_module(void)
+{
+ DBG("init_module");
+
+ if (disabled)
+ return -ENXIO;
+
+ neo_init();
+
+ /* never return failure; user can hotplug card later... */
+ return 0;
+}
+
+#endif /* MODULE */
+
+module_exit(neo_done);
--- /dev/null
+/*
+ * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+
+#ifdef NEOFB_DEBUG
+# define DBG(x) printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+ unsigned int pixclock;
+ unsigned int HDisplay;
+ unsigned int HSyncStart;
+ unsigned int HSyncEnd;
+ unsigned int HTotal;
+ unsigned int VDisplay;
+ unsigned int VSyncStart;
+ unsigned int VSyncEnd;
+ unsigned int VTotal;
+ unsigned int sync;
+ int dblscan;
+ int interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+ __u32 bltStat;
+ __u32 bltCntl;
+ __u32 xpColor;
+ __u32 fgColor;
+ __u32 bgColor;
+ __u32 pitch;
+ __u32 clipLT;
+ __u32 clipRB;
+ __u32 srcBitOffset;
+ __u32 srcStart;
+ __u32 reserved0;
+ __u32 dstStart;
+ __u32 xyExt;
+
+ __u32 reserved1[19];
+
+ __u32 pageCntl;
+ __u32 pageBase;
+ __u32 postBase;
+ __u32 postPtr;
+ __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE 256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+
+ int depth;
+
+ unsigned char MiscOutReg; /* Misc */
+ unsigned char CRTC[25]; /* Crtc Controller */
+ unsigned char Sequencer[5]; /* Video Sequencer */
+ unsigned char Graphics[9]; /* Video Graphics */
+ unsigned char Attribute[21]; /* Video Atribute */
+
+ unsigned char GeneralLockReg;
+ unsigned char ExtCRTDispAddr;
+ unsigned char ExtCRTOffset;
+ unsigned char SysIfaceCntl1;
+ unsigned char SysIfaceCntl2;
+ unsigned char ExtColorModeSelect;
+ unsigned char biosMode;
+
+ unsigned char PanelDispCntlReg1;
+ unsigned char PanelDispCntlReg2;
+ unsigned char PanelDispCntlReg3;
+ unsigned char PanelVertCenterReg1;
+ unsigned char PanelVertCenterReg2;
+ unsigned char PanelVertCenterReg3;
+ unsigned char PanelVertCenterReg4;
+ unsigned char PanelVertCenterReg5;
+ unsigned char PanelHorizCenterReg1;
+ unsigned char PanelHorizCenterReg2;
+ unsigned char PanelHorizCenterReg3;
+ unsigned char PanelHorizCenterReg4;
+ unsigned char PanelHorizCenterReg5;
+
+ int ProgramVCLK;
+ unsigned char VCLK3NumeratorLow;
+ unsigned char VCLK3NumeratorHigh;
+ unsigned char VCLK3Denominator;
+ unsigned char VerticalExt;
+};
+
+struct neofb_info {
+
+ struct fb_info fb;
+ struct display_switch *dispsw;
+
+ struct pci_dev *pcidev;
+
+ int currcon;
+
+ int accel;
+ char *name;
+
+ struct {
+ u8 *vbase;
+ u32 pbase;
+ u32 len;
+#ifdef CONFIG_MTRR
+ int mtrr;
+#endif
+ } video;
+
+ struct {
+ u8 *vbase;
+ u32 pbase;
+ u32 len;
+ } mmio;
+
+ Neo2200 *neo2200;
+
+ /* Panels size */
+ int NeoPanelWidth;
+ int NeoPanelHeight;
+
+ int maxClock;
+
+ int pci_burst;
+ int lcd_stretch;
+ int internal_display;
+ int external_display;
+
+ struct {
+ u16 red, green, blue, transp;
+ } palette[NR_PALETTE];
+};
+
+
+typedef struct {
+ int x_res;
+ int y_res;
+ int mode;
+} biosMode;
+
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+ outb (index, 0x3d4);
+ return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+ outb (index, 0x3d4);
+ outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+ outb (index, 0x3ce);
+ return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+ outb (index, 0x3ce);
+ outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+ outb (index, 0x3c4);
+ return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+ outb (index, 0x3c4);
+ outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+ u8 tmp;
+
+ tmp = inb (0x3da);
+ outb (0x00, 0x3c0);
+ paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+ u8 tmp;
+
+ tmp = inb (0x3da);
+ outb (0x20, 0x3c0);
+ paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+ u8 tmp;
+
+ if (paletteEnabled)
+ index &= ~0x20;
+ else
+ index |= 0x20;
+
+ tmp = inb (0x3da);
+ outb (index, 0x3c0);
+ outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+ outb (value, 0x3c2);
+}
+
+
+#define NEO_BS0_BLT_BUSY 0x00000001
+#define NEO_BS0_FIFO_AVAIL 0x00000002
+#define NEO_BS0_FIFO_PEND 0x00000004
+
+#define NEO_BC0_DST_Y_DEC 0x00000001
+#define NEO_BC0_X_DEC 0x00000002
+#define NEO_BC0_SRC_TRANS 0x00000004
+#define NEO_BC0_SRC_IS_FG 0x00000008
+#define NEO_BC0_SRC_Y_DEC 0x00000010
+#define NEO_BC0_FILL_PAT 0x00000020
+#define NEO_BC0_SRC_MONO 0x00000040
+#define NEO_BC0_SYS_TO_VID 0x00000080
+
+#define NEO_BC1_DEPTH8 0x00000100
+#define NEO_BC1_DEPTH16 0x00000200
+#define NEO_BC1_X_320 0x00000400
+#define NEO_BC1_X_640 0x00000800
+#define NEO_BC1_X_800 0x00000c00
+#define NEO_BC1_X_1024 0x00001000
+#define NEO_BC1_X_1152 0x00001400
+#define NEO_BC1_X_1280 0x00001800
+#define NEO_BC1_X_1600 0x00001c00
+#define NEO_BC1_DST_TRANS 0x00002000
+#define NEO_BC1_MSTR_BLT 0x00004000
+#define NEO_BC1_FILTER_Z 0x00008000
+
+#define NEO_BC2_WR_TR_DST 0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR 0x01000000
+#define NEO_BC3_DST_XY_ADDR 0x02000000
+#define NEO_BC3_CLIP_ON 0x04000000
+#define NEO_BC3_FIFO_EN 0x08000000
+#define NEO_BC3_BLT_ON_ADDR 0x10000000
+#define NEO_BC3_SKIP_MAPPING 0x80000000
+
+#define NEO_MODE1_DEPTH8 0x0100
+#define NEO_MODE1_DEPTH16 0x0200
+#define NEO_MODE1_DEPTH24 0x0300
+#define NEO_MODE1_X_320 0x0400
+#define NEO_MODE1_X_640 0x0800
+#define NEO_MODE1_X_800 0x0c00
+#define NEO_MODE1_X_1024 0x1000
+#define NEO_MODE1_X_1152 0x1400
+#define NEO_MODE1_X_1280 0x1800
+#define NEO_MODE1_X_1600 0x1c00
+#define NEO_MODE1_BLT_ON_ADDR 0x2000
strcpy(info->info.modename, "OFfb ");
strncat(info->info.modename, full_name, sizeof(info->info.modename));
- info->info.node = -1;
+ info->info.node = NODEV;
info->info.fbops = &offb_ops;
info->info.disp = disp;
info->info.fontname[0] = '\0';
disp = &info->disp;
strcpy(info->fb_info.modename, "platinum");
- info->fb_info.node = -1;
+ info->fb_info.node = NODEV;
info->fb_info.fbops = &platinumfb_ops;
info->fb_info.disp = disp;
strcpy(info->fb_info.fontname, fontname);
*/
strcpy(ip->info.modename, "PMAG-BA");
ip->info.changevar = NULL;
- ip->info.node = -1;
+ ip->info.node = NODEV;
ip->info.fbops = &pmagbafb_ops;
ip->info.disp = &disp;
ip->info.switch_con = &pmagbafb_switch;
*/
strcpy(ip->info.modename, "PMAGB-BA");
ip->info.changevar = NULL;
- ip->info.node = -1;
+ ip->info.node = NODEV;
ip->info.fbops = &pmagbbfb_ops;
ip->info.disp = &disp;
ip->info.switch_con = &pmagbbfb_switch;
strcpy(fb_info.modename, pvr2fb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &pvr2fb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &pvr2fbcon_switch;
fb_info.switch_con=&q40con_switch;
fb_info.updatevar=&q40con_updatevar;
fb_info.blank=&q40con_blank;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &q40fb_ops;
fb_info.flags = FBINFO_FLAG_DEFAULT; /* not as module for now */
info = &rinfo->info;
strcpy (info->modename, rinfo->name);
- info->node = -1;
+ info->node = NODEV;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &radeon_fb_ops;
info->display_fg = NULL;
strcpy(fb_info->modename, retz3fb_name);
fb_info->changevar = NULL;
- fb_info->node = -1;
+ fb_info->node = NODEV;
fb_info->fbops = &retz3fb_ops;
fb_info->disp = &zinfo->disp;
fb_info->switch_con = &z3fb_switch;
strcpy(fb_info.modename, sgivwfb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &sgivwfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &sgivwfbcon_switch;
fb_info.gen.fbhw->detect();
strcpy(fb_info.gen.info.modename, "XXX");
fb_info.gen.info.changevar = NULL;
- fb_info.gen.info.node = -1;
+ fb_info.gen.info.node = NODEV;
fb_info.gen.info.fbops = &xxxfb_ops;
fb_info.gen.info.disp = &disp;
fb_info.gen.info.switch_con = &xxxfb_switch;
f_ddprintk("membase_phys: %#lx\n", fb_info.video.base);
f_ddprintk("fbbase_virt: %#lx\n", fb_info.video.vbase);
- fb_info.info.node = -1 ;
+ fb_info.info.node = NODEV;
fb_info.info.flags = FBINFO_FLAG_DEFAULT;
fb_info.info.fbops = &sstfb_ops;
fb_info.info.disp = &disp;
if ((fb_info.sti = sti_init_roms()) == NULL)
return -ENXIO;
- fb_info.gen.info.node = -1;
+ fb_info.gen.info.node = NODEV;
fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
fb_info.gen.info.fbops = &stifb_ops;
fb_info.gen.info.disp = &disp;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->visual = FB_VISUAL_PSEUDOCOLOR;
- fb->info.node = -1;
+ fb->info.node = NODEV;
fb->info.fbops = &sun3fb_ops;
fb->info.disp = disp;
strcpy(fb->info.fontname, fontname);
strcpy(fb_info.fb_info.modename, "3Dfx ");
strcat(fb_info.fb_info.modename, name);
fb_info.fb_info.changevar = NULL;
- fb_info.fb_info.node = -1;
+ fb_info.fb_info.node = NODEV;
fb_info.fb_info.fbops = &tdfxfb_ops;
fb_info.fb_info.disp = &fb_info.disp;
strcpy(fb_info.fb_info.fontname, fontname);
/* setup framebuffer */
- fb_info.gen.info.node = -1;
+ fb_info.gen.info.node = NODEV;
fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
fb_info.gen.info.fbops = &tgafb_ops;
fb_info.gen.info.disp = &disp;
strcpy(fb_info.modename, TX3912FB_NAME);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &tx3912fb_ops;
fb_info.disp = &global_disp;
fb_info.switch_con = &tx3912fbcon_switch;
static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
{
strcpy(info->modename, p->fix.id);
- info->node = -1; /* ??? danj */
+ info->node = NODEV;
info->fbops = &valkyriefb_ops;
info->disp = &p->disp;
strcpy(info->fontname, fontname);
strcpy(fb_info.modename, vfb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &vfb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &vfbcon_switch;
/* name should not depend on EGA/VGA */
strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
vga16fb.fb_info.changevar = NULL;
- vga16fb.fb_info.node = -1;
+ vga16fb.fb_info.node = NODEV;
vga16fb.fb_info.fbops = &vga16fb_ops;
vga16fb.fb_info.disp=&disp;
vga16fb.fb_info.switch_con=&vga16fb_switch;
strcpy(fb_info.modename, virgefb_name);
fb_info.changevar = NULL;
- fb_info.node = -1;
+ fb_info.node = NODEV;
fb_info.fbops = &virgefb_ops;
fb_info.disp = &disp;
fb_info.switch_con = &Cyberfb_switch;
m68k_memory[i].addr+m68k_memory[i].size, 0);
}
+subsys_initcall(zorro_init);
EXPORT_SYMBOL(zorro_find_device);
EXPORT_SYMBOL(zorro_unused_z2ram);
# msdos file systems
tristate 'DOS FAT fs support' CONFIG_FAT_FS
dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+#dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+# UMSDOS is temprory broken
+define_bool CONFIG_UMSDOS_FS n
+
dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
dep_tristate 'Journalling Flash File System (JFFS) support' CONFIG_JFFS_FS $CONFIG_MTD
{
struct coda_inode_info *ei;
ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
memset(&ei->c_fid, 0, sizeof(struct ViceFid));
ei->c_flags = 0;
INIT_LIST_HEAD(&ei->c_cilist);
ei->c_contcount = 0;
memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
ei->c_cached_perm = 0;
- if (!ei)
- return NULL;
return &ei->vfs_inode;
}
#include <linux/dcache.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/driverfs_fs.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
struct driver_file_entry * entry;
unsigned char *page;
ssize_t retval = 0;
+ struct device * dev;
entry = (struct driver_file_entry *)file->private_data;
if (!entry) {
return -ENOENT;
}
- if (!entry->ops || !entry->ops->read) {
- DBG("%s: no read callback\n",__FUNCTION__);
- return -ENOENT;
- }
+ dev = list_entry(entry->parent,struct device, dir);
+
+ if (!valid_device(dev))
+ return -EFAULT;
+
+ if (!entry->show)
+ goto done;
page = (unsigned char*)__get_free_page(GFP_KERNEL);
if (!page) {
while (count > 0) {
ssize_t len;
- len = entry->ops->read(page,count,*ppos,entry->data);
+ len = entry->show(dev,page,count,*ppos);
if (len <= 0) {
if (len < 0)
free_page((unsigned long)page);
done:
+ put_device(dev);
return retval;
}
driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
struct driver_file_entry * entry;
+ struct device * dev;
ssize_t retval = 0;
entry = (struct driver_file_entry *)file->private_data;
return -ENOENT;
}
- if (!entry->ops || !entry->ops->write) {
- DBG("%s: no write callback\n",__FUNCTION__);
- retval = -ENOENT;
+ dev = list_entry(entry->parent,struct device, dir);
+
+ if (!valid_device(dev))
+ return -EFAULT;
+
+ if (!entry->store)
goto done;
- }
while (count > 0) {
ssize_t len;
- len = entry->ops->write(buf,count,*ppos,entry->data);
+ len = entry->store(dev,buf,count,*ppos);
if (len <= 0) {
if (len < 0)
*ppos += len;
buf += len;
}
-
done:
+ put_device(dev);
return retval;
}
return 0;
}
-/* Similar to above - if this dentry goes away, free the
- * driver_dir_entry associated with it..
- */
-static int driverfs_d_delete_dir (struct dentry * dentry)
-{
- struct driver_dir_entry * entry;
- entry = (struct driver_dir_entry *)dentry->d_fsdata;
- if (entry)
- kfree(entry);
- return 0;
-}
-
static struct address_space_operations driverfs_aops = {
};
d_delete: driverfs_d_delete_file,
};
-static struct dentry_operations driverfs_dentry_dir_ops = {
- d_delete: driverfs_d_delete_dir,
-};
-
static struct super_operations driverfs_ops = {
statfs: driverfs_statfs,
put_inode: force_delete,
MODULE_DESCRIPTION("The device driver filesystem");
MODULE_LICENSE("GPL");
-/**
- * driverfs_create_dir_entry - allocate and initialise directory entry
- * @name: name of the directory
- * @mode: permissions of the dir
- */
-struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode)
-{
- struct driver_dir_entry * entry;
- int size = sizeof(struct driver_dir_entry) + strlen(name) + 1;
-
-
- entry = kmalloc(size, GFP_KERNEL);
- if (!entry)
- return NULL;
-
- memset(entry, 0, size);
- strcpy((char *)entry + sizeof(struct driver_dir_entry), name);
-
- entry->name = (char *)entry + sizeof(struct driver_dir_entry);
-
- INIT_LIST_HEAD(&entry->files);
- entry->mode = mode;
-
- return entry;
-}
-
/**
* driverfs_create_dir - create a directory in the filesystem
* @entry: directory entry
dentry->d_inode->u.generic_ip = (void *)entry;
entry->dentry = dentry;
+ entry->parent = parent;
list_add_tail(&entry->node,&parent->files);
}
done:
put_mount();
}
-
-/**
- * driverfs_create_entry - allocate and initialise a struct driver_file_entry
- * @name: name of the file
- * @mode: permissions of the file
- * @ops: Operations for the file
- * @data: data that will be passed back to the callback
- *
- */
-struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data)
-{
- struct driver_file_entry * entry;
- int size;
-
- size = sizeof(struct driver_file_entry) + strlen(name) + 1;
-
- entry = kmalloc(size,GFP_KERNEL);
- if (!entry)
- return NULL;
-
- memset(entry, 0, size);
- strcpy((char *)entry + sizeof(struct driver_file_entry), name);
-
- entry->name = (char *)entry + sizeof(struct driver_file_entry);
-
- INIT_LIST_HEAD(&entry->node);
-
- entry->mode = mode;
- entry->ops = ops;
- entry->data = data;
-
- return entry;
-}
-
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
+ memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
insert_inode_hash(inode);
mark_inode_dirty(inode);
return;
}
+static kmem_cache_t * minix_inode_cachep;
+
+static struct inode *minix_alloc_inode(struct super_block *sb)
+{
+ struct minix_inode_info *ei;
+ ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void minix_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(minix_inode_cachep, minix_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct minix_inode_info *ei = (struct minix_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ minix_inode_cachep = kmem_cache_create("minix_inode_cache",
+ sizeof(struct minix_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (minix_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(minix_inode_cachep))
+ printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations minix_sops = {
+ alloc_inode: minix_alloc_inode,
+ destroy_inode: minix_destroy_inode,
read_inode: minix_read_inode,
write_inode: minix_write_inode,
delete_inode: minix_delete_inode,
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
+ struct minix_inode_info *minix_inode = minix_i(inode);
int i;
raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
inode->i_blocks = inode->i_blksize = 0;
for (i = 0; i < 9; i++)
- inode->u.minix_i.u.i1_data[i] = raw_inode->i_zone[i];
+ minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, raw_inode->i_zone[0]);
brelse(bh);
}
{
struct buffer_head * bh;
struct minix2_inode * raw_inode;
+ struct minix_inode_info *minix_inode = minix_i(inode);
int i;
raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
inode->i_ctime = raw_inode->i_ctime;
inode->i_blocks = inode->i_blksize = 0;
for (i = 0; i < 10; i++)
- inode->u.minix_i.u.i2_data[i] = raw_inode->i_zone[i];
+ minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, raw_inode->i_zone[0]);
brelse(bh);
}
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
+ struct minix_inode_info *minix_inode = minix_i(inode);
int i;
raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (i = 0; i < 9; i++)
- raw_inode->i_zone[i] = inode->u.minix_i.u.i1_data[i];
+ raw_inode->i_zone[i] = minix_inode->u.i1_data[i];
mark_buffer_dirty(bh);
return bh;
}
{
struct buffer_head * bh;
struct minix2_inode * raw_inode;
+ struct minix_inode_info *minix_inode = minix_i(inode);
int i;
raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (i = 0; i < 10; i++)
- raw_inode->i_zone[i] = inode->u.minix_i.u.i2_data[i];
+ raw_inode->i_zone[i] = minix_inode->u.i2_data[i];
mark_buffer_dirty(bh);
return bh;
}
static int __init init_minix_fs(void)
{
- return register_filesystem(&minix_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&minix_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_minix_fs(void)
{
unregister_filesystem(&minix_fs_type);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
static inline block_t *i_data(struct inode *inode)
{
- return (block_t *)inode->u.minix_i.u.i1_data;
+ return (block_t *)minix_i(inode)->u.i1_data;
}
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
static inline block_t *i_data(struct inode *inode)
{
- return (block_t *)inode->u.minix_i.u.i2_data;
+ return (block_t *)minix_i(inode)->u.i2_data;
}
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
return tmp & hash_mask;
}
-struct vfsmount *alloc_vfsmnt(void)
+struct vfsmount *alloc_vfsmnt(char *name)
{
struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL);
if (mnt) {
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
+ if (name) {
+ int size = strlen(name)+1;
+ char * newname = kmalloc(size, GFP_KERNEL);
+ if (newname) {
+ memcpy(newname, name, size);
+ mnt->mnt_devname = newname;
+ }
+ }
}
return mnt;
}
kmem_cache_free(mnt_cache, mnt);
}
-void set_devname(struct vfsmount *mnt, const char *name)
-{
- if (name) {
- int size = strlen(name)+1;
- char * newname = kmalloc(size, GFP_KERNEL);
- if (newname) {
- memcpy(newname, name, size);
- mnt->mnt_devname = newname;
- }
- }
-}
-
struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
{
struct list_head * head = mount_hashtable + hash(mnt, dentry);
clone_mnt(struct vfsmount *old, struct dentry *root)
{
struct super_block *sb = old->mnt_sb;
- struct vfsmount *mnt = alloc_vfsmnt();
+ struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
if (mnt) {
mnt->mnt_flags = old->mnt_flags;
- set_devname(mnt, old->mnt_devname);
atomic_inc(&sb->s_active);
mnt->mnt_sb = sb;
mnt->mnt_root = dget(root);
static void ncp_put_super(struct super_block *);
static int ncp_statfs(struct super_block *, struct statfs *);
+static kmem_cache_t * ncp_inode_cachep;
+
+static struct inode *ncp_alloc_inode(struct super_block *sb)
+{
+ struct ncp_inode_info *ei;
+ ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void ncp_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ init_MUTEX(&ei->open_sem);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
+ sizeof(struct ncp_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (ncp_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(ncp_inode_cachep))
+ printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations ncp_sops =
{
+ alloc_inode: ncp_alloc_inode,
+ destroy_inode: ncp_destroy_inode,
put_inode: force_delete,
delete_inode: ncp_delete_inode,
put_super: ncp_put_super,
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#else
+ NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
#endif
NCP_FINFO(inode)->access = nwinfo->access;
NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
inode = new_inode(sb);
if (inode) {
- init_MUTEX(&NCP_FINFO(inode)->open_sem);
atomic_set(&NCP_FINFO(inode)->opened, info->opened);
inode->i_ino = info->ino;
static int __init init_ncp_fs(void)
{
+ int err;
DPRINTK("ncpfs: init_module called\n");
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
ncp_current_malloced = 0;
#endif
- return register_filesystem(&ncp_fs_type);
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ncp_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_ncp_fs(void)
{
DPRINTK("ncpfs: cleanup_module called\n");
unregister_filesystem(&ncp_fs_type);
+ destroy_inodecache();
#ifdef DEBUG_NCP_MALLOC
PRINTK("ncp_malloced: %d\n", ncp_malloced);
PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
if (error < 0)
goto failure;
#endif
- get_fast_time(&nfssvc_boot); /* record boot time */
+ do_gettimeofday(&nfssvc_boot); /* record boot time */
} else
nfsd_serv->sv_nrthreads++;
nrservs -= (nfsd_serv->sv_nrthreads-1);
unsigned long * free_blocknrs,
unsigned long search_start)
{
+ struct reiserfs_inode_info *ei = REISERFS_I(p_s_inode);
int ret=0, blks_gotten=0;
unsigned long border = 0;
unsigned long bstart = 0;
}
/* take a block off the prealloc list and return it -Hans */
- if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
- p_s_inode->u.reiserfs_i.i_prealloc_count--;
- *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
+ if (ei->i_prealloc_count > 0) {
+ ei->i_prealloc_count--;
+ *free_blocknrs = ei->i_prealloc_block++;
/* if no more preallocated blocks, remove inode from list */
- if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
- list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+ if (! ei->i_prealloc_count) {
+ list_del_init(&ei->i_prealloc_list);
}
return ret;
/* this uses the last preallocated block as the search_start. discard
** prealloc does not zero out this number.
*/
- if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
- search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
+ if (search_start <= ei->i_prealloc_block) {
+ search_start = ei->i_prealloc_block;
}
/* doing the compare again forces search_start to be >= the border,
}
#endif
if (blks_gotten==0) {
- p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+ ei->i_prealloc_block = *free_blocknrs;
}
search_start = *free_blocknrs;
*free_blocknrs = 0;
}
- p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
- *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
- p_s_inode->u.reiserfs_i.i_prealloc_block++;
+ ei->i_prealloc_count = blks;
+ *free_blocknrs = ei->i_prealloc_block;
+ ei->i_prealloc_block++;
/* if inode has preallocated blocks, link him to list */
- if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
- list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
+ if (ei->i_prealloc_count) {
+ list_add(&ei->i_prealloc_list,
&SB_JOURNAL(th->t_super)->j_prealloc_list);
}
/* we did actually manage to get 1 block */
// analog. You should be able to tell which portion by looking at the
// ext2 code and comparing.
static void __discard_prealloc (struct reiserfs_transaction_handle * th,
- struct inode * inode)
+ struct reiserfs_inode_info *ei)
{
- while (inode->u.reiserfs_i.i_prealloc_count > 0) {
- reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
- inode->u.reiserfs_i.i_prealloc_block++;
- inode->u.reiserfs_i.i_prealloc_count --;
+ while (ei->i_prealloc_count > 0) {
+ reiserfs_free_block(th,ei->i_prealloc_block);
+ ei->i_prealloc_block++;
+ ei->i_prealloc_count --;
}
- list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+ list_del_init(&(ei->i_prealloc_list));
}
void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode * inode)
{
+ struct reiserfs_inode_info *ei = REISERFS_I(inode);
#ifdef CONFIG_REISERFS_CHECK
- if (inode->u.reiserfs_i.i_prealloc_count < 0)
+ if (ei->i_prealloc_count < 0)
reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
#endif
- if (inode->u.reiserfs_i.i_prealloc_count > 0) {
- __discard_prealloc(th, inode);
+ if (ei->i_prealloc_count > 0) {
+ __discard_prealloc(th, ei);
}
}
void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
{
struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
- struct inode * inode;
while (!list_empty(plist)) {
- inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+ struct reiserfs_inode_info *ei;
+ ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
#ifdef CONFIG_REISERFS_CHECK
- if (!inode->u.reiserfs_i.i_prealloc_count) {
- reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
- }
-#endif
- __discard_prealloc(th, inode);
+ if (!ei->i_prealloc_count) {
+ reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+ }
+#endif
+ __discard_prealloc(th, ei);
}
}
#endif
copy_key(&unf_key_to_search,p_s_key_to_search);
unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
- unf_key_to_search.k_offset = p_s_inode->u.reiserfs_i.i_first_direct_byte - 1;
+ unf_key_to_search.k_offset = REISERFS_I(p_s_inode)->i_first_direct_byte - 1;
/* p_s_key_to_search->k_offset - MAX_ITEM_LEN(p_s_sb->s_blocksize); */
if (search_for_position_by_key (p_s_sb, &unf_key_to_search, p_unf_search_path, &n_pos_in_item) == POSITION_FOUND)
unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
if (
- (p_s_inode->u.reiserfs_i.i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
+ (REISERFS_I(p_s_inode)->i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
crap other than what the name indicates, thus
testing to see if it is 0 is not enough */
- && (p_s_inode->u.reiserfs_i.i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
+ && (REISERFS_I(p_s_inode)->i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
i_first_direct_byte = MAX_KEY_OFFSET */
)
{
/* actually, we don't want the last unformatted node, we want the last unformatted node
which is before the current file offset */
- unf_key_to_search.k_offset = ((p_s_inode->u.reiserfs_i.i_first_direct_byte -1) < unf_key_to_search.k_offset) ? p_s_inode->u.reiserfs_i.i_first_direct_byte -1 : unf_key_to_search.k_offset;
+ unf_key_to_search.k_offset = ((REISERFS_I(p_s_inode)->i_first_direct_byte -1) < unf_key_to_search.k_offset) ? REISERFS_I(p_s_inode)->i_first_direct_byte -1 : unf_key_to_search.k_offset;
while (unf_key_to_search.k_offset > -1)
{
/* fast out for when nothing needs to be done */
if ((atomic_read(&inode->i_count) > 1 ||
- !inode->u.reiserfs_i.i_pack_on_close ||
+ REISERFS_I(inode)->i_pack_on_close ||
!tail_has_to_be_packed(inode)) &&
- inode->u.reiserfs_i.i_prealloc_count <= 0) {
+ REISERFS_I(inode)->i_prealloc_count <= 0) {
return 0;
}
journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
if (atomic_read(&inode->i_count) <= 1 &&
- inode->u.reiserfs_i.i_pack_on_close &&
+ REISERFS_I(inode)->i_pack_on_close &&
tail_has_to_be_packed (inode)) {
/* if regular file is released by last holder and it has been
appended (we append by unformatted node only) or its direct
/* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
offset and type of key */
-void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * key, struct inode * inode, loff_t offset,
int type, int length )
{
_make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
return ret;
}
- inode->u.reiserfs_i.i_pack_on_close = 1 ;
+ REISERFS_I(inode)->i_pack_on_close = 1 ;
windex = push_journal_writer("reiserfs_get_block") ;
copy_key (INODE_PKEY (inode), &(ih->ih_key));
inode->i_blksize = PAGE_SIZE;
- INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
if (stat_data_v1 (ih)) {
struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
unsigned long blocks;
}
rdev = sd_v1_rdev(sd);
- inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
+ REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
} else {
// new stat data found, but object may have old items
// (directories and symlinks)
inode_items_version (inode) = ITEM_VERSION_1;
else
inode_items_version (inode) = ITEM_VERSION_2;
+ REISERFS_I(inode)->i_first_direct_byte = 0;
}
-
+ REISERFS_I(inode)->i_pack_on_close = 0;
+ REISERFS_I(inode)->i_prealloc_block = 0;
+ REISERFS_I(inode)->i_prealloc_count = 0;
+ REISERFS_I(inode)->i_trans_id = 0;
+ REISERFS_I(inode)->i_trans_index = 0;
/* nopack = 0, by default */
- inode->u.reiserfs_i.nopack = 0;
+ REISERFS_I(inode)->nopack = 0;
pathrelse (path);
if (S_ISREG (inode->i_mode)) {
set_sd_v1_blocks(sd_v1, inode->i_blocks );
// Sigh. i_first_direct_byte is back
- set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);
+ set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
}
containing "." and ".." entries */
static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
struct item_head * ih, struct path * path,
- const struct inode * dir)
+ struct inode * dir)
{
struct super_block * sb = th->t_super;
char empty_dir [EMPTY_DIR_SIZE];
directory) or reiserfs_new_symlink (to insert symlink body if new
object is symlink) or nothing (if new object is regular file) */
struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
- const struct inode * dir, int mode,
+ struct inode * dir, int mode,
const char * symname,
int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
strlen (symname) for symlinks)*/
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_size = i_size;
inode->i_blocks = (inode->i_size + 511) >> 9;
- inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 :
+ REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 :
U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
- INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+ REISERFS_I(inode)->i_pack_on_close = 0;
+ REISERFS_I(inode)->i_prealloc_block = 0;
+ REISERFS_I(inode)->i_prealloc_count = 0;
+ REISERFS_I(inode)->nopack = 0;
+ REISERFS_I(inode)->i_trans_id = 0;
+ REISERFS_I(inode)->i_trans_index = 0;
if (old_format_only (sb))
inode2sd_v1 (&sd, inode);
return -EINVAL ;
}
/* ioctl already done */
- if (inode->u.reiserfs_i.nopack) {
+ if (REISERFS_I(inode)->nopack) {
return 0 ;
}
lock_kernel();
write_from = inode->i_size & (blocksize - 1) ;
/* if we are on a block boundary, we are already unpacked. */
if ( write_from == 0) {
- inode->u.reiserfs_i.nopack = 1;
+ REISERFS_I(inode)->nopack = 1;
goto out ;
}
/* conversion can change page contents, must flush */
flush_dcache_page(page) ;
- inode->u.reiserfs_i.nopack = 1;
+ REISERFS_I(inode)->nopack = 1;
kunmap(page) ; /* mapped by prepare_write */
out_unlock:
void reiserfs_update_inode_transaction(struct inode *inode) {
- inode->u.reiserfs_i.i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+ REISERFS_I(inode)->i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
- inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+ REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
}
static int reiserfs_inode_in_this_transaction(struct inode *inode) {
- if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id ||
- inode->u.reiserfs_i.i_trans_id == 0) {
+ if (REISERFS_I(inode)->i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id ||
+ REISERFS_I(inode)->i_trans_id == 0) {
return 1;
}
return 0 ;
struct reiserfs_transaction_handle th ;
struct super_block *sb = inode->i_sb ;
- jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
+ jl = SB_JOURNAL_LIST(sb) + REISERFS_I(inode)->i_trans_index ;
/* is it from the current transaction, or from an unknown transaction? */
if (reiserfs_inode_in_this_transaction(inode)) {
journal_join(&th, sb, 1) ;
reiserfs_update_inode_transaction(inode) ;
journal_end_sync(&th, sb, 1) ;
- } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
+ } else if (jl->j_trans_id == REISERFS_I(inode)->i_trans_id) {
flush_commit_list(sb, jl, 1) ;
}
/* if the transaction id does not match, this list is long since flushed
*/
if (atomic_read(&p_s_inode->i_count) > 1 ||
!tail_has_to_be_packed (p_s_inode) ||
- !page || p_s_inode->u.reiserfs_i.nopack) {
+ !page || REISERFS_I(p_s_inode)->nopack) {
// leave tail in an unformatted node
*p_c_mode = M_SKIP_BALANCING;
cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
/* we delete first part of tail which was stored in direct
item(s) */
// FIXME: this is to keep 3.5 happy
- p_s_inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+ REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512;
}
}
** be flushed before the transaction commits, so we don't need to
** deal with it here.
*/
- p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ;
+ REISERFS_I(p_s_inode)->i_pack_on_close = 0 ;
}
return n_ret_value;
}
return;
}
+static kmem_cache_t * reiserfs_inode_cachep;
+
+static struct inode *reiserfs_alloc_inode(struct super_block *sb)
+{
+ struct reiserfs_inode_info *ei;
+ ei = (struct reiserfs_inode_info *)kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void reiserfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_LIST_HEAD(&ei->i_prealloc_list) ;
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ reiserfs_inode_cachep = kmem_cache_create("reiserfs_inode_cache",
+ sizeof(struct reiserfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (reiserfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(reiserfs_inode_cachep))
+ printk(KERN_INFO "reiserfs_inode_cache: not all structures were freed\n");
+}
+
struct super_operations reiserfs_sops =
{
+ alloc_inode: reiserfs_alloc_inode,
+ destroy_inode: reiserfs_destroy_inode,
read_inode: reiserfs_read_inode,
read_inode2: reiserfs_read_inode2,
write_inode: reiserfs_write_inode,
bh = sb_bread (s, offset / s->s_blocksize);
if (!bh) {
printk ("read_super_block: "
- "bread failed (dev %s, block %d, size %d)\n",
+ "bread failed (dev %s, block %ld, size %ld)\n",
s->s_id, offset / s->s_blocksize, s->s_blocksize);
return 1;
}
rs = (struct reiserfs_super_block *)bh->b_data;
if (!is_reiserfs_magic_string (rs)) {
printk ("read_super_block: "
- "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+ "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
s->s_id, bh->b_blocknr, s->s_blocksize);
brelse (bh);
return 1;
bh = reiserfs_bread (s, offset / s->s_blocksize);
if (!bh) {
printk("read_super_block: "
- "bread failed (dev %s, block %d, size %d)\n",
+ "bread failed (dev %s, block %ld, size %ld)\n",
s->s_id, offset / s->s_blocksize, s->s_blocksize);
return 1;
}
rs = (struct reiserfs_super_block *)bh->b_data;
if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) {
printk ("read_super_block: "
- "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+ "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
s->s_id, bh->b_blocknr, s->s_blocksize);
brelse (bh);
printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", s->s_id);
//
static int __init init_reiserfs_fs (void)
{
+ int err = init_inodecache();
+ if (err)
+ goto out1;
reiserfs_proc_info_global_init();
reiserfs_proc_register_global( "version",
reiserfs_global_version_in_proc );
- return register_filesystem(&reiserfs_fs_type);
+ err = register_filesystem(&reiserfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ reiserfs_proc_unregister_global( "version" );
+ reiserfs_proc_info_global_done();
+ destroy_inodecache();
+out1:
+ return err;
}
MODULE_DESCRIPTION("ReiserFS journaled filesystem");
reiserfs_proc_unregister_global( "version" );
reiserfs_proc_info_global_done();
unregister_filesystem(&reiserfs_fs_type);
+ destroy_inodecache();
}
module_init(init_reiserfs_fs) ;
memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
}
- inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+ REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
return 0;
}
/* we store position of first direct item in the in-core inode */
//mark_file_with_tail (p_s_inode, pos1 + 1);
- p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;
+ REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
return n_block_size - round_tail_len;
}
put_anon_dev(dev);
}
-struct vfsmount *alloc_vfsmnt(void);
+struct vfsmount *alloc_vfsmnt(char *name);
void free_vfsmnt(struct vfsmount *mnt);
-void set_devname(struct vfsmount *mnt, const char *name);
static inline struct super_block * find_super(kdev_t dev)
{
if (!type)
return ERR_PTR(-ENODEV);
- mnt = alloc_vfsmnt();
+ mnt = alloc_vfsmnt(name);
if (!mnt)
goto out;
- set_devname(mnt, name);
if (type->fs_flags & FS_REQUIRES_DEV)
sb = get_sb_bdev(type, flags, name, data);
else if (type->fs_flags & FS_SINGLE)
+Mon Jan 21 2001 Alexander Viro <viro@math.psu.edu>
+ * ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
+ * i_vnode renamed to vfs_inode. Sorry, but let's keep that
+ consistent.
+
+Sat Jan 19 2001 Christoph Hellwig <hch@infradead.org>
+
+ * include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
+ list_entry() instead of inode->u.
+ * include/linux/sysv_fs_i.h: Add 'struct inode i_vnode' field to
+ sysv_inode_info structure.
+ * inode.c: Include <linux/slab.h>, implement alloc_inode/destroy_inode
+ sop methods, add infrastructure for per-fs inode slab cache.
+ * super.c (init_sysv_fs): Initialize inode cache, recover properly
+ in the case of failed register_filesystem for V7.
+ (exit_sysv_fs): Destroy inode cache.
+
+Sat Jan 19 2001 Christoph Hellwig <hch@infradead.org>
+
+ * include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
+ * dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
+ access fs-private inode data.
+ * ialloc.c (sysv_new_inode): Likewise.
+ * inode.c (sysv_read_inode): Likewise.
+ (sysv_update_inode): Likewise.
+ * itree.c (get_branch): Likewise.
+ (sysv_truncate): Likewise.
+ * symlink.c (sysv_readlink): Likewise.
+ (sysv_follow_link): Likewise.
+
Fri Jan 4 2001 Alexander Viro <viro@math.psu.edu>
* ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
*res_page = NULL;
- start = dir->u.sysv_i.i_dir_start_lookup;
+ start = SYSV_I(dir)->i_dir_start_lookup;
if (start >= npages)
start = 0;
n = start;
return NULL;
found:
- dir->u.sysv_i.i_dir_start_lookup = n;
+ SYSV_I(dir)->i_dir_start_lookup = n;
*res_page = page;
return de;
}
inode->i_ino = fs16_to_cpu(sb, ino);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
- inode->u.sysv_i.i_dir_start_lookup = 0;
+ memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
+ SYSV_I(inode)->i_dir_start_lookup = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
#include <linux/locks.h>
#include <linux/smp_lock.h>
#include <linux/highuid.h>
+#include <linux/slab.h>
#include <asm/byteorder.h>
/* This is only called on sync() and umount(), when s_dirt=1. */
struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
struct sysv_inode * raw_inode;
+ struct sysv_inode_info * si;
unsigned int block, ino;
dev_t rdev = 0;
inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime);
inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime);
inode->i_blocks = inode->i_blksize = 0;
+
+ si = SYSV_I(inode);
for (block = 0; block < 10+1+1+1; block++)
read3byte(sb, &raw_inode->i_a.i_addb[3*block],
- (unsigned char*)&inode->u.sysv_i.i_data[block]);
+ (unsigned char*)&si->i_data[block]);
brelse(bh);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]);
- inode->u.sysv_i.i_dir_start_lookup = 0;
+ rdev = (u16)fs32_to_cpu(sb, si->i_data[0]);
+ si->i_dir_start_lookup = 0;
sysv_set_inode(inode, rdev);
return;
struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
struct sysv_inode * raw_inode;
+ struct sysv_inode_info * si;
unsigned int ino, block;
ino = inode->i_ino;
raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime);
raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime);
raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime);
+
+ si = SYSV_I(inode);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- inode->u.sysv_i.i_data[0] =
- cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
+ si->i_data[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
for (block = 0; block < 10+1+1+1; block++)
- write3byte(sb, (unsigned char*)&inode->u.sysv_i.i_data[block],
+ write3byte(sb, (unsigned char*)&si->i_data[block],
&raw_inode->i_a.i_addb[3*block]);
mark_buffer_dirty(bh);
return bh;
unlock_kernel();
}
+static kmem_cache_t *sysv_inode_cachep;
+
+static struct inode *sysv_alloc_inode(struct super_block *sb)
+{
+ struct sysv_inode_info *si;
+
+ si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL);
+ if (!si)
+ return NULL;
+ return &si->vfs_inode;
+}
+
+static void sysv_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct sysv_inode_info *si = (struct sysv_inode_info *)p;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&si->vfs_inode);
+}
+
struct super_operations sysv_sops = {
+ alloc_inode: sysv_alloc_inode,
+ destroy_inode: sysv_destroy_inode,
read_inode: sysv_read_inode,
write_inode: sysv_write_inode,
delete_inode: sysv_delete_inode,
write_super: sysv_write_super,
statfs: sysv_statfs,
};
+
+int __init sysv_init_icache(void)
+{
+ sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
+ sizeof(struct sysv_inode_info), 0,
+ SLAB_HWCACHE_ALIGN, init_once, NULL);
+ if (!sysv_inode_cachep)
+ return -ENOMEM;
+ return 0;
+}
+
+void sysv_destroy_icache(void)
+{
+ kmem_cache_destroy(sysv_inode_cachep);
+}
struct buffer_head *bh;
*err = 0;
- add_chain (chain, NULL, inode->u.sysv_i.i_data + *offsets);
+ add_chain (chain, NULL, SYSV_I(inode)->i_data + *offsets);
if (!p->key)
goto no_block;
while (--depth) {
void sysv_truncate (struct inode * inode)
{
- u32 *i_data = inode->u.sysv_i.i_data;
+ u32 *i_data = SYSV_I(inode)->i_data;
int offsets[DEPTH];
Indirect chain[DEPTH];
Indirect *partial;
static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super);
+extern int sysv_init_icache(void) __init;
+extern void sysv_destroy_icache(void);
+
static int __init init_sysv_fs(void)
{
- int err = register_filesystem(&sysv_fs_type);
- if (!err)
- err = register_filesystem(&v7_fs_type);
- return err;
+ int error;
+
+ error = sysv_init_icache();
+ if (error)
+ goto out;
+ error = register_filesystem(&sysv_fs_type);
+ if (error)
+ goto destroy_icache;
+ error = register_filesystem(&v7_fs_type);
+ if (error)
+ goto unregister;
+ return 0;
+
+unregister:
+ unregister_filesystem(&sysv_fs_type);
+destroy_icache:
+ sysv_destroy_icache();
+out:
+ return error;
}
static void __exit exit_sysv_fs(void)
{
unregister_filesystem(&sysv_fs_type);
unregister_filesystem(&v7_fs_type);
+ sysv_destroy_icache();
}
EXPORT_NO_SYMBOLS;
*/
#include <linux/fs.h>
+#include <linux/sysv_fs.h>
static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+ char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
return vfs_readlink(dentry, buffer, buflen, s);
}
static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+ char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
return vfs_follow_link(nd, s);
}
}
lock_super(sb);
+ UDF_I_UNIQUE(inode) = 0;
+ UDF_I_LENEXTENTS(inode) = 0;
+ UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+ UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+ UDF_I_STRAT4096(inode) = 0;
if (UDF_SB_LVIDBH(sb))
{
struct LogicalVolHeaderDesc *lvhd;
* i_nlink = 1
* i_op = NULL;
*/
-
inode->i_blksize = PAGE_SIZE;
bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
UDF_I_STRAT4096(inode) = 1;
UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+ UDF_I_UMTIME(inode) = 0;
+ UDF_I_UCTIME(inode) = 0;
+ UDF_I_CRTIME(inode) = 0;
+ UDF_I_UCRTIME(inode) = 0;
+ UDF_I_UNIQUE(inode) = 0;
+ UDF_I_LENEATTR(inode) = 0;
+ UDF_I_LENEXTENTS(inode) = 0;
+ UDF_I_LENALLOC(inode) = 0;
+ UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+ UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
UDF_I_EXTENDED_FE(inode) = 1;
else if (fe->descTag.tagIdent == TID_FILE_ENTRY)
inode->i_mode = udf_convert_permissions(fe);
inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
- UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
- UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
-
if (UDF_I_EXTENDED_FE(inode) == 0)
{
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
/* UDF filesystem type */
static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
+static kmem_cache_t * udf_inode_cachep;
+
+static struct inode *udf_alloc_inode(struct super_block *sb)
+{
+ struct udf_inode_info *ei;
+ ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void udf_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(udf_inode_cachep, UDF_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ udf_inode_cachep = kmem_cache_create("udf_inode_cache",
+ sizeof(struct udf_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (udf_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(udf_inode_cachep))
+ printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+}
+
/* Superblock operations */
static struct super_operations udf_sb_ops = {
+ alloc_inode: udf_alloc_inode,
+ destroy_inode: udf_destroy_inode,
read_inode: udf_read_inode,
write_inode: udf_write_inode,
put_inode: udf_put_inode,
static int __init init_udf_fs(void)
{
+ int err;
printk(KERN_NOTICE "udf: registering filesystem\n");
- return register_filesystem(&udf_fstype);
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&udf_fstype);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_udf_fs(void)
{
printk(KERN_NOTICE "udf: unregistering filesystem\n");
unregister_filesystem(&udf_fstype);
+ destroy_inodecache();
}
EXPORT_NO_SYMBOLS;
#ifndef __LINUX_UDF_I_H
#define __LINUX_UDF_I_H
-#define UDF_I(X) (&((X)->u.udf_i))
+#include <linux/udf_fs_i.h>
+static inline struct udf_inode_info *UDF_I(struct inode *inode)
+{
+ return list_entry(inode, struct udf_inode_info, vfs_inode);
+}
#define UDF_I_LOCATION(X) ( UDF_I(X)->i_location )
#define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr )
-/* $Id: ide.h,v 1.6 2000/05/27 00:49:37 davem Exp $
+/* $Id: ide.h,v 1.7 2002/01/16 20:58:40 davem Exp $
* ide.h: SPARC PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
unsigned int reserved456: 3;
unsigned bit3 : 1; /* ATA-2 thingy */
unsigned int SRST : 1; /* host soft reset bit */
- unsigned int nIEN : 1; /* device INTRQ to host *
+ unsigned int nIEN : 1; /* device INTRQ to host */
unsigned int bit0 : 1;
} b;
} control_t;
-/* $Id: ide.h,v 1.21 2001/09/25 20:21:48 kanoj Exp $
+/* $Id: ide.h,v 1.22 2002/01/16 20:58:40 davem Exp $
* ide.h: Ultra/PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
unsigned int reserved456: 3;
unsigned bit3 : 1; /* ATA-2 thingy */
unsigned int SRST : 1; /* host soft reset bit */
- unsigned int nIEN : 1; /* device INTRQ to host *
+ unsigned int nIEN : 1; /* device INTRQ to host */
unsigned int bit0 : 1;
} b;
} control_t;
-/* $Id: irq.h,v 1.20 2001/03/09 01:31:40 davem Exp $
+/* $Id: irq.h,v 1.21 2002/01/23 11:27:36 davem Exp $
* irq.h: IRQ registers on the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-
-struct devid_cookie {
- int dummy;
-};
+#include <asm/pil.h>
/* You should not mess with this directly. That's the job of irq.c.
*
--- /dev/null
+/* $Id: pil.h,v 1.1 2002/01/23 11:27:36 davem Exp $ */
+#ifndef _SPARC64_PIL_H
+#define _SPARC64_PIL_H
+
+/* To avoid some locking problems, we hard allocate certain PILs
+ * for SMP cross call messages. cli() does not block the cross
+ * call delivery, so when SMP locking is an issue we reschedule
+ * the event into a PIL interrupt which is blocked by cli().
+ *
+ * XXX In fact the whole set of PILs used for hardware interrupts
+ * XXX may be allocated in this manner. All of the devices can
+ * XXX happily sit at the same PIL. We would then need only two
+ * XXX PILs, one for devices and one for the CPU local timer tick.
+ */
+#define PIL_MIGRATE 1
+
+#ifndef __ASSEMBLY__
+#define PIL_RESERVED(PIL) ((PIL) == PIL_MIGRATE)
+#endif
+
+#endif /* !(_SPARC64_PIL_H) */
atomic_t refcount; /* refcount to make sure the device
* persists for the right amount of time */
- struct driver_dir_entry * dir;
+ struct driver_dir_entry dir;
struct device_driver *driver; /* which driver has allocated this
device */
struct list_head devices; /* children devices */
struct device *self; /* pointer to controlling device */
- struct driver_dir_entry * dir; /* driverfs directory */
+ struct driver_dir_entry dir; /* driverfs directory */
char name[DEVICE_NAME_SIZE];
char bus_id[BUS_ID_SIZE];
extern struct iobus * iobus_alloc(void);
extern void iobus_init(struct iobus * iobus);
-extern int device_create_file(struct device *device, const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data);
+extern int device_create_file(struct device *device, struct driver_file_entry * entry);
extern void device_remove_file(struct device * dev, const char * name);
-extern int iobus_create_file(struct iobus *bus, const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data);
-extern void iobus_remove_file(struct iobus * iobus, const char * name);
-
-
/*
* Platform "fixup" functions - allow the platform to have their say
* about devices and actions that the general device layer doesn't
#ifndef _DRIVER_FS_H_
#define _DRIVER_FS_H_
-struct driverfs_operations {
- ssize_t (*read) (char *, size_t, loff_t, void *);
- ssize_t (*write)(const char *, size_t, loff_t, void*);
-};
-
struct driver_dir_entry {
char * name;
struct dentry * dentry;
struct list_head files;
};
+struct device;
+
struct driver_file_entry {
struct driver_dir_entry * parent;
struct list_head node;
mode_t mode;
struct dentry * dentry;
void * data;
- struct driverfs_operations * ops;
-};
-extern struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode);
+ ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
+ ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+};
extern int
driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
extern void
driverfs_remove_dir(struct driver_dir_entry * entry);
-extern struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data);
-
extern int
driverfs_create_file(struct driver_file_entry * entry,
struct driver_dir_entry * parent);
#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */
#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */
+
+#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */
+#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */
+#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */
+#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */
+#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */
+#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */
+#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */
+#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */
+#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */
+
+
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
#include <linux/pipe_fs_i.h>
-#include <linux/minix_fs_i.h>
#include <linux/ntfs_fs_i.h>
#include <linux/msdos_fs_i.h>
-#include <linux/umsdos_fs_i.h>
+/* #include <linux/umsdos_fs_i.h> */
#include <linux/iso_fs_i.h>
-#include <linux/sysv_fs_i.h>
#include <linux/romfs_fs_i.h>
#include <linux/smb_fs_i.h>
#include <linux/hfs_fs_i.h>
#include <linux/adfs_fs_i.h>
-#include <linux/reiserfs_fs_i.h>
#include <linux/bfs_fs_i.h>
-#include <linux/udf_fs_i.h>
-#include <linux/ncp_fs_i.h>
#include <linux/proc_fs_i.h>
#include <linux/jffs2_fs_i.h>
#include <linux/cramfs_fs_sb.h>
unsigned int i_attr_flags;
__u32 i_generation;
union {
- struct minix_inode_info minix_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_info msdos_i;
- struct umsdos_inode_info umsdos_i;
+ /* struct umsdos_inode_info umsdos_i; */
struct iso_inode_info isofs_i;
- struct sysv_inode_info sysv_i;
struct romfs_inode_info romfs_i;
struct smb_inode_info smbfs_i;
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
- struct reiserfs_inode_info reiserfs_i;
struct bfs_inode_info bfs_i;
- struct udf_inode_info udf_i;
- struct ncp_inode_info ncpfs_i;
struct proc_inode_info proc_i;
struct socket socket_i;
struct jffs2_inode_info jffs2_i;
extern initcall_t __initcall_start, __initcall_end;
-#define __initcall(fn) \
- static initcall_t __initcall_##fn __init_call = fn
+/* initcalls are now grouped by functionality into separate
+ * subsections. Ordering inside the subsections is determined
+ * by link order.
+ * For backwards compatability, initcall() puts the call in
+ * the device init subsection.
+ */
+
+#define __define_initcall(level,fn) \
+ static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
+
+#define early_arch_initcall(fn) __define_initcall("1",fn)
+#define mem_initcall(fn) __define_initcall("2",fn)
+#define subsys_initcall(fn) __define_initcall("3",fn)
+#define arch_initcall(fn) __define_initcall("4",fn)
+#define fs_initcall(fn) __define_initcall("5",fn)
+#define device_initcall(fn) __define_initcall("6",fn)
+#define late_initcall(fn) __define_initcall("7",fn)
+
+#define __initcall(fn) device_initcall(fn)
+
#define __exitcall(fn) \
static exitcall_t __exitcall_##fn __exit_call = fn
#define __initdata __attribute__ ((__section__ (".data.init")))
#define __exitdata __attribute__ ((unused, __section__ (".data.exit")))
#define __initsetup __attribute__ ((unused,__section__ (".setup.init")))
-#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
+#define __init_call(level) __attribute__ ((unused,__section__ (".initcall" level ".init")))
#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
/* For assembly routines */
#define __setup(str,func) /* nothing */
+#define early_arch_initcall(fn) module_init(fn)
+#define mem_initcall(fn) module_init(fn)
+#define subsys_initcall(fn) module_init(fn)
+#define arch_initcall(fn) module_init(fn)
+#define fs_initcall(fn) module_init(fn)
+#define device_initcall(fn) module_init(fn)
+#define late_initcall(fn) module_init(fn)
+
#endif
#ifdef CONFIG_HOTPLUG
#ifdef __KERNEL__
+#include <linux/minix_fs_i.h>
+
/*
* change the define below to 0 if you want names > info->s_namelen chars to be
* truncated. Else they will be disallowed (ENAMETOOLONG).
extern struct file_operations minix_dir_operations;
extern struct dentry_operations minix_dentry_operations;
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+ return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
+
#endif /* __KERNEL__ */
#endif
__u16 i1_data[16];
__u32 i2_data[16];
} u;
+ struct inode vfs_inode;
};
#endif
#include <linux/in.h>
#include <linux/types.h>
+#include <linux/ncp_fs_i.h>
#include <linux/ipx.h>
#include <linux/ncp_no.h>
#define NCP_SBP(sb) (&((sb)->u.ncpfs_sb))
#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
-#define NCP_FINFO(inode) (&((inode)->u.ncpfs_i))
+static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode)
+{
+ return list_entry(inode, struct ncp_inode_info, vfs_inode);
+}
#ifdef DEBUG_NCP_MALLOC
* all the information we need to work with an inode after creation.
*/
struct ncp_inode_info {
- __u32 dirEntNum __attribute__((packed));
- __u32 DosDirNum __attribute__((packed));
- __u32 volNumber __attribute__((packed));
+ __u32 dirEntNum;
+ __u32 DosDirNum;
+ __u32 volNumber;
__u32 nwattr;
struct semaphore open_sem;
atomic_t opened;
int access;
- __u32 server_file_handle __attribute__((packed));
- __u8 open_create_action __attribute__((packed));
- __u8 file_handle[6] __attribute__((packed));
+ __u32 server_file_handle;
+ __u8 file_handle[6];
+ struct inode vfs_inode;
};
#endif /* __KERNEL__ */
/* Man behind the curtain... */
struct ipt_table_info *private;
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ struct module *me;
};
extern int ipt_register_table(struct ipt_table *table);
--- /dev/null
+/* Header file for IP tables userspace logging, Version 1.8
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Distributed under the terms of GNU GPL */
+
+#ifndef _IPT_ULOG_H
+#define _IPT_ULOG_H
+
+#ifndef NETLINK_NFLOG
+#define NETLINK_NFLOG 5
+#endif
+
+#define ULOG_MAC_LEN 80
+#define ULOG_PREFIX_LEN 32
+
+#define ULOG_MAX_QLEN 50
+/* Why 50? Well... there is a limit imposed by the slab cache 131000
+ * bytes. So the multipart netlink-message has to be < 131000 bytes.
+ * Assuming a standard ethernet-mtu of 1500, we could define this up
+ * to 80... but even 50 seems to be big enough. */
+
+/* private data structure for each rule with a ULOG target */
+struct ipt_ulog_info {
+ unsigned int nl_group;
+ size_t copy_range;
+ size_t qthreshold;
+ char prefix[ULOG_PREFIX_LEN];
+};
+
+/* Format of the ULOG packets passed through netlink */
+typedef struct ulog_packet_msg {
+ unsigned long mark;
+ long timestamp_sec;
+ long timestamp_usec;
+ unsigned int hook;
+ char indev_name[IFNAMSIZ];
+ char outdev_name[IFNAMSIZ];
+ size_t data_len;
+ char prefix[ULOG_PREFIX_LEN];
+ unsigned char mac_len;
+ unsigned char mac[ULOG_MAC_LEN];
+ unsigned char payload[0];
+} ulog_packet_msg_t;
+
+#endif /*_IPT_ULOG_H*/
--- /dev/null
+#ifndef _IPT_AH_H
+#define _IPT_AH_H
+
+struct ipt_ah
+{
+ u_int32_t spis[2]; /* Security Parameter Index */
+ u_int8_t invflags; /* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_ah. */
+#define IPT_AH_INV_SPI 0x01 /* Invert the sense of spi. */
+#define IPT_AH_INV_MASK 0x01 /* All possible flags. */
+
+#endif /*_IPT_AH_H*/
--- /dev/null
+#ifndef _IPT_ESP_H
+#define _IPT_ESP_H
+
+struct ipt_esp
+{
+ u_int32_t spis[2]; /* Security Parameter Index */
+ u_int8_t invflags; /* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_esp. */
+#define IPT_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
+#define IPT_ESP_INV_MASK 0x01 /* All possible flags. */
+
+#endif /*_IPT_ESP_H*/
/* Man behind the curtain... */
struct ip6t_table_info *private;
+
+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+ struct module *me;
};
extern int ip6t_register_table(struct ip6t_table *table);
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_ARPD 8
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
#define NETLINK_IP6_FW 13
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/errno.h>
+#include <linux/device.h>
/* File state for mmap()s on /proc/bus/pci/X/Y */
enum pci_mmap_state {
this is D0-D3, D0 being fully functional,
and D3 being off. */
+ struct device dev; /* Generic device interface */
+
/* device is compatible with these IDs */
unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
unsigned char productver; /* product version */
unsigned char checksum; /* if zero - checksum passed */
unsigned char pad1;
+
+ struct iobus iobus; /* Generic device interface */
};
#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
/* Generic PCI functions used internally */
-void pci_init(void);
int pci_bus_exists(const struct list_head *list, int nr);
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
struct pci_bus *pci_alloc_primary_bus(int bus);
#include <asm/unaligned.h>
#include <linux/bitops.h>
#include <linux/proc_fs.h>
+#include <linux/reiserfs_fs_i.h>
#endif
/*
*/
#define MIN_PACK_ON_CLOSE 512
+static inline struct reiserfs_inode_info *REISERFS_I(struct inode *inode)
+{
+ return list_entry(inode, struct reiserfs_inode_info, vfs_inode);
+}
// this says about version of all items (but stat data) the object
// consists of
-#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version)
+#define inode_items_version(inode) (REISERFS_I(inode)->i_version)
/* This is an aggressive tail suppression policy, I am hoping it
#define UNFM_P_SIZE (sizeof(unp_t))
// in in-core inode key is stored on le form
-#define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
-//#define mark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted),1))
-//#define unmark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted), 0))
-//#define is_tail_converted(inode) (atomic_read(&((inode)->u.reiserfs_i.i_converted)))
+#define INODE_PKEY(inode) ((struct key *)(REISERFS_I(inode)->i_key))
+//#define mark_tail_converted(inode) (atomic_set(&(REISERFS_I(inode)->i_converted),1))
+//#define unmark_tail_converted(inode) (REISERFS_I(inode)->i_converted), 0))
+//#define is_tail_converted(inode) (REISERFS_I(inode)->i_converted)))
// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
#define U32_MAX (~(__u32)0)
-static inline loff_t max_reiserfs_offset (const struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
{
if (inode_items_version (inode) == ITEM_VERSION_1)
return (loff_t)U32_MAX;
int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
-void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
int type, int key_length);
void make_le_item_head (struct item_head * ih, const struct cpu_key * key,
int version,
void reiserfs_dirty_inode (struct inode * inode) ;
struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
- const struct inode * dir, int mode,
+ struct inode * dir, int mode,
const char * symname, int item_len,
struct dentry *dentry, struct inode *inode, int * err);
int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
*/
unsigned long i_trans_id ;
unsigned long i_trans_index ;
+ struct inode vfs_inode;
};
extern void rtnetlink_init(void);
#define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0) { up(&rtnl_sem); \
-printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \
+printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
} while(0);
-#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
#endif /* __KERNEL__ */
#include <linux/sched.h> /* declares wake_up() */
#include <linux/sysv_fs_sb.h> /* defines the sv_... shortcuts */
+/* temporary hack. */
+#include <linux/sysv_fs_i.h>
+static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
+{
+ /* I think list_entry should have a more descriptive name.. --hch */
+ return list_entry(inode, struct sysv_inode_info, vfs_inode);
+}
+/* end temporary hack. */
+
/* Layout on disk */
/* ============== */
* then 1 triple indirection block.
*/
u32 i_dir_start_lookup;
+ struct inode vfs_inode;
};
#endif
#ifdef __KERNEL__
extern void do_gettimeofday(struct timeval *tv);
extern void do_settimeofday(struct timeval *tv);
-extern void get_fast_time(struct timeval *tv);
-extern void (*do_get_fast_time)(struct timeval *);
#endif
#define FD_SETSIZE __FD_SETSIZE
unsigned i_strat_4096 : 1;
unsigned i_new_inode : 1;
unsigned reserved : 26;
+ struct inode vfs_inode;
};
#endif
#include <asm/ccwcache.h>
#endif
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#ifdef CONFIG_DIO
-#include <linux/dio.h>
-#endif
-
-#ifdef CONFIG_ZORRO
-#include <linux/zorro.h>
-#endif
-
#ifdef CONFIG_MTRR
# include <asm/mtrr.h>
#endif
-#ifdef CONFIG_NUBUS
-#include <linux/nubus.h>
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-#endif
-
-#ifdef CONFIG_IRDA
-extern int irda_proto_init(void);
-extern int irda_device_init(void);
-#endif
-
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif
extern void fork_init(unsigned long);
extern void mca_init(void);
extern void sbus_init(void);
-extern void ppc_init(void);
extern void sysctl_init(void);
extern void signals_init(void);
-extern int init_pcmcia_ds(void);
extern void free_initmem(void);
extern void tc_init(void);
#endif
-extern void ecard_init(void);
-
#if defined(CONFIG_SYSVIPC)
extern void ipc_init(void);
#endif
/* bring up the device tree */
device_driver_init();
-#ifdef CONFIG_PCI
- pci_init();
-#endif
-#ifdef CONFIG_SBUS
- sbus_init();
-#endif
-#if defined(CONFIG_PPC)
- ppc_init();
-#endif
-#ifdef CONFIG_MCA
- mca_init();
-#endif
-#ifdef CONFIG_ARCH_ACORN
- ecard_init();
-#endif
-#ifdef CONFIG_ZORRO
- zorro_init();
-#endif
-#ifdef CONFIG_DIO
- dio_init();
-#endif
-#ifdef CONFIG_NUBUS
- nubus_init();
-#endif
-#ifdef CONFIG_ISAPNP
- isapnp_init();
-#endif
-#ifdef CONFIG_TC
- tc_init();
-#endif
-
/* Networking initialization needs a process context */
sock_init();
start_context_thread();
do_initcalls();
-
-#ifdef CONFIG_IRDA
- irda_proto_init();
- irda_device_init(); /* Must be done after protocol initialization */
-#endif
-#ifdef CONFIG_PCMCIA
- init_pcmcia_ds(); /* Do this last */
-#endif
}
extern void prepare_namespace(void);
static spinlock_t device_lock;
-static ssize_t device_read_status(char *, size_t, loff_t, void *);
-static ssize_t device_write_status(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_status_ops = {
- read: device_read_status,
- write: device_write_status,
-};
-
-static ssize_t device_read_power(char *, size_t, loff_t, void *);
-static ssize_t device_write_power(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_power_ops = {
- read: device_read_power,
- write: device_write_power,
+static ssize_t device_read_status(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_status(struct device *,const char *, size_t, loff_t);
+
+static struct driver_file_entry device_status_entry = {
+ name: "status",
+ mode: S_IWUSR | S_IRUGO,
+ show: device_read_status,
+ store: device_write_status,
};
-static ssize_t iobus_read_status(char *, size_t, loff_t, void *);
-static ssize_t iobus_write_status(const char *, size_t, loff_t, void *);
+static ssize_t device_read_power(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_power(struct device *, const char *, size_t, loff_t);
-static struct driverfs_operations iobus_status_ops = {
- read: iobus_read_status,
- write: iobus_write_status,
+static struct driver_file_entry device_power_entry = {
+ name: "power",
+ mode: S_IWUSR | S_IRUGO,
+ show: device_read_power,
+ store: device_write_power,
};
-
/**
* device_create_file - create a driverfs file for a device
* @dev: device requesting file
- * @name: name of file
- * @mode: permissions of file
- * @ops: operations for the file
- * @data: private data for the file
+ * @entry: entry describing file
*
- * Create a driverfs entry, then create the actual file the entry describes.
+ * Allocate space for file entry, copy descriptor, and create.
*/
-int device_create_file(struct device * dev, const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data)
+int device_create_file(struct device * dev, struct driver_file_entry * entry)
{
- int error = -EFAULT;
- struct driver_file_entry * entry;
+ struct driver_file_entry * new_entry;
+ int error = -ENOMEM;
if (!dev)
return -EINVAL;
if (!valid_device(dev))
return -EFAULT;
- entry = driverfs_create_entry(name,mode,ops,data);
- if (entry)
- error = driverfs_create_file(entry,dev->dir);
+ new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
+ if (!new_entry)
+ goto done;
+ memcpy(new_entry,entry,sizeof(*entry));
+ error = driverfs_create_file(new_entry,&dev->dir);
+ if (error)
+ kfree(new_entry);
+ done:
put_device(dev);
return error;
}
if (!valid_device(dev))
return;
- driverfs_remove_file(dev->dir,name);
+ driverfs_remove_file(&dev->dir,name);
put_device(dev);
}
*/
void device_remove_dir(struct device * dev)
{
- struct driver_dir_entry * dir;
-
- if (!dev)
- return;
-
- lock_device(dev);
- dir = dev->dir;
- dev->dir = NULL;
- unlock_device(dev);
-
- if (dir)
- driverfs_remove_dir(dir);
+ if (dev)
+ driverfs_remove_dir(&dev->dir);
}
/**
*/
static int device_make_dir(struct device * dev)
{
- struct driver_dir_entry * entry;
+ struct driver_dir_entry * parent = NULL;
int error;
- entry = driverfs_create_dir_entry(dev->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
- if (!entry)
- return -EFAULT;
+ INIT_LIST_HEAD(&dev->dir.files);
+ dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+ dev->dir.name = dev->bus_id;
- error = driverfs_create_dir(entry,dev->parent->dir);
+ if (dev->parent)
+ parent = &dev->parent->dir;
- if (error) {
- kfree(entry);
- return error;
- }
+ error = driverfs_create_dir(&dev->dir,parent);
- lock_device(dev);
- dev->dir = entry;
- unlock_device(dev);
+ if (error)
+ return error;
- /* first the status file */
- error = device_create_file(dev, "status", S_IRUGO | S_IWUSR,
- &device_status_ops, (void *) dev);
+ error = device_create_file(dev,&device_status_entry);
if (error) {
device_remove_dir(dev);
goto done;
}
-
- /* now the power file */
- error = device_create_file(dev,"power",S_IRUGO | S_IWUSR,
- &device_power_ops, (void *) dev);
- if (error)
+ error = device_create_file(dev,&device_power_entry);
+ if (error)
device_remove_dir(dev);
-
done:
return error;
}
-/* iobus interface.
- * For practical purposes, it's exactly the same as the device interface above.
- * Even below, the two are almost identical, only taking different pointer
- * types.
- * I have fantasized about removing struct iobus completely. It would reduce
- * this file by about 30%, and make life much easier. However, it will take some
- * time to really work everything out..
- */
-
-int iobus_create_file(struct iobus * iobus, const char * name, mode_t mode,
- struct driverfs_operations * ops, void * data)
-{
- int error = -EFAULT;
- struct driver_file_entry * entry;
-
- if (!iobus)
- return -EINVAL;
-
- if (!valid_iobus(iobus))
- return -EFAULT;
-
- entry = driverfs_create_entry(name,mode,ops,data);
- if (entry)
- error = driverfs_create_file(entry,iobus->dir);
-
- put_iobus(iobus);
- return error;
-}
-
-void iobus_remove_file(struct iobus * iobus, const char * name)
-{
- if (!iobus)
- return;
-
- if (!valid_iobus(iobus))
- return;
-
- driverfs_remove_file(iobus->dir,name);
-
- put_iobus(iobus);
-}
-
void iobus_remove_dir(struct iobus * iobus)
{
- struct driver_dir_entry * dir;
-
- if (!iobus)
- return;
-
- lock_iobus(iobus);
- dir = iobus->dir;
- iobus->dir = NULL;
- unlock_iobus(iobus);
-
- if (dir)
- driverfs_remove_dir(dir);
+ if (iobus)
+ driverfs_remove_dir(&iobus->dir);
}
static int iobus_make_dir(struct iobus * iobus)
{
- struct driver_dir_entry * entry;
struct driver_dir_entry * parent = NULL;
int error;
- entry = driverfs_create_dir_entry(iobus->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
- if (!entry)
- return -EFAULT;
+ INIT_LIST_HEAD(&iobus->dir.files);
+ iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+ iobus->dir.name = iobus->bus_id;
if (iobus->parent)
- parent = iobus->parent->dir;
-
- error = driverfs_create_dir(entry,parent);
- if (error) {
- kfree(entry);
- return error;
- }
-
- lock_iobus(iobus);
- iobus->dir = entry;
- unlock_iobus(iobus);
-
- error = iobus_create_file(iobus, "status", S_IRUGO | S_IWUSR,
- &iobus_status_ops, (void *)iobus);
- if (error)
- iobus_remove_dir(iobus);
+ parent = &iobus->parent->dir;
+ error = driverfs_create_dir(&iobus->dir,parent);
return error;
}
dev->parent = &device_root;
parent = dev->parent;
+ DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
+ dev->bus_id, dev->name, parent->bus_id);
+
if (valid_iobus(parent)) {
if (!valid_device(dev)) {
put_iobus(parent);
list_add_tail(&dev->node, &parent->devices);
unlock_iobus(parent);
- DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
- dev->bus_id, dev->name, parent->bus_id);
-
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
- return 0;
-
register_done:
put_device(dev);
put_iobus(parent);
list_add_tail(&bus->node,&parent->children);
unlock_iobus(parent);
- return 0;
-
register_done_put:
put_iobus(bus);
put_iobus(parent);
return bus;
}
-static int do_device_suspend(struct device * dev, u32 state)
-{
- int error = 0;
-
- if (!dev->driver->suspend)
- return error;
-
- error = dev->driver->suspend(dev,state,SUSPEND_NOTIFY);
-
- if (error)
- return error;
-
- error = dev->driver->suspend(dev,state,SUSPEND_SAVE_STATE);
- if (error) {
- if (dev->driver->resume)
- dev->driver->resume(dev,RESUME_RESTORE_STATE);
- return error;
- }
- error = dev->driver->suspend(dev,state,SUSPEND_POWER_DOWN);
- if (error) {
- if (dev->driver->resume)
- dev->driver->resume(dev,RESUME_RESTORE_STATE);
- }
- return error;
-}
-
-static int do_device_resume(struct device * dev)
-{
- int error = 0;
-
- if (!dev->driver->resume)
- return 0;
- error = dev->driver->resume(dev,RESUME_POWER_ON);
- if (error)
- return error;
- error = dev->driver->resume(dev,RESUME_RESTORE_STATE);
- return error;
-}
-
/**
* device_read_status - report some device information
* @page: page-sized buffer to write into
* Report some human-readable information about the device.
* This includes the name, the bus id, and the current power state.
*/
-static ssize_t device_read_status(char * page, size_t count,
- loff_t off, void * data)
+static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
{
char *str = page;
- struct device *dev = (struct device*)data;
- ssize_t len = 0;
-
- if (!dev)
- return -EINVAL;
-
- if (!valid_device(dev))
- return -EFAULT;
if (off)
- goto done;
+ return 0;
str += sprintf(str,"Name: %s\n",dev->name);
str += sprintf(str,"Bus ID: %s\n",dev->bus_id);
- len = str - page;
-
- if (len > count)
- len = count;
-
- if (len < 0)
- len = 0;
-
- done:
- put_device(dev);
-
- return len;
+ return (str - page);
}
/**
* (See Documentation/driver-model.txt for the theory of an n-stage
* suspend sequence).
*/
-static ssize_t device_write_status(const char* buf, size_t count, loff_t off, void *data)
+static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
{
char command[20];
- struct device *dev = (struct device *)data;
int num;
int arg = 0;
int error = 0;
- if (!dev)
- return 0;
-
- if (!valid_device(dev))
- return -EFAULT;
-
if (off)
- goto done_put;
+ return 0;
/* everything involves dealing with the driver. */
if (!dev->driver)
- goto done_put;
+ return 0;
num = sscanf(buf,"%10s %d",command,&arg);
if (!num)
- goto done_put;
+ return 0;
if (!strcmp(command,"probe")) {
if (dev->driver->probe)
error = dev->driver->remove(dev,REMOVE_NOTIFY);
} else
error = -EFAULT;
-
- done_put:
- put_device(dev);
return error < 0 ? error : count;
}
static ssize_t
-device_read_power(char * page, size_t count, loff_t off, void * data)
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
{
char * str = page;
- struct device * dev = (struct device *)data;
- ssize_t len = 0;
-
- if (!dev)
- return 0;
- if (!valid_device(dev))
+ if (off)
return 0;
str += sprintf(str,"State: %d\n",dev->current_state);
- len = str - page;
-
- if (off) {
- if (len < off) {
- len = 0;
- goto done;
- }
- str += off;
- len -= off;
- }
-
- if (len > count)
- len = count;
-
- done:
- put_device(dev);
- return len;
+ return (str - page);
}
static ssize_t
-device_write_power(const char * buf, size_t count, loff_t off, void * data)
+device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
{
- struct device * dev = (struct device *)data;
char str_command[20];
char str_stage[20];
int num_args;
u32 int_stage;
int error = 0;
- if (!dev)
+ if (off)
return 0;
- if (!valid_device(dev))
- return -EFAULT;
-
- if (off)
- goto done;
if (!dev->driver)
goto done;
error = 0;
}
done:
- put_device(dev);
-
- DBG("%s: returning %d\n",__FUNCTION__,error);
-
- return error < 0 ? error : count;
-}
-
-/**
- * bus_read_status - report human readable information
- * @page: page-sized buffer to write into
- * @count: number of bytes requested
- * @off: offset into buffer to start at
- * @data: bus-specific data
- */
-static ssize_t iobus_read_status(char *page, size_t count,
- loff_t off, void *data)
-{
- char *str = page;
- struct iobus *bus = (struct iobus*)data;
- ssize_t len = 0;
-
- if (!bus)
- return -EINVAL;
-
- if (!valid_iobus(bus))
- return -EFAULT;
-
- if (off)
- goto done;
-
- str += sprintf(str,"Name: %s\n",bus->name);
- str += sprintf(str,"Bus ID: %s\n",bus->bus_id);
-
- if (bus->driver)
- str += sprintf(str,"Type: %s\n",bus->driver->name);
-
- len = str - page;
- if (len < off)
- len = 0;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
-
- done:
- put_iobus(bus);
- return len;
-}
-
-/**
- * bus_write_status - forward a command to a bus
- * @buf: string encoded command
- * @count: number of bytes requested
- * @off: offset into buffer to start at
- * @data: bus-specific data
- *
- * Like device_write_status, this sends a command to a bus driver.
- * Supported actions are:
- * scan - scan a bus for devices
- * add_device <id> - add a child device
- */
-static ssize_t iobus_write_status(const char *buf, size_t count, loff_t off, void *data)
-{
- char command[10];
- char which[15];
- char id[10];
- struct iobus *bus = (struct iobus*)data;
- int num;
- int error = -EINVAL;
-
- if (!bus)
- return -EINVAL;
-
- if (!valid_iobus(bus))
- return -EFAULT;
-
- if (!bus->driver)
- goto done;
-
- num = sscanf(buf,"%10s %15s %10s",command,which,id);
-
- if (!num)
- goto done;
-
- if (!strnicmp(command,"scan",4)) {
- if (bus->driver->scan)
- error = bus->driver->scan(bus);
- } else if (!strnicmp(command,"add",3) && num == 2) {
- error = bus->driver->add_device(bus,id);
- } else if (!strnicmp(command, "suspend",7)) {
- u32 state = simple_strtoul(which,NULL,0);
- if (state > 0)
- error = do_device_suspend(bus->self,state);
-
- } else if (!strnicmp(command,"resume",6)) {
- error = do_device_resume(bus->self);
-
- }
-
- done:
- put_iobus(bus);
return error < 0 ? error : count;
}
* needs to do is create the root directory. Easier
* to just do it here than special case it elsewhere..
*/
- iobus_make_dir(&device_root);
-
- return (device_root.dir ? 0 : -EFAULT);
+ return iobus_make_dir(&device_root);
}
int __init device_driver_init(void)
EXPORT_SYMBOL(iobus_alloc);
EXPORT_SYMBOL(iobus_init);
-EXPORT_SYMBOL(iobus_create_file);
-EXPORT_SYMBOL(iobus_remove_file);
-
EXPORT_SYMBOL(device_driver_init);
EXPORT_SYMBOL(lock_may_read);
EXPORT_SYMBOL(lock_may_write);
EXPORT_SYMBOL(dcache_readdir);
+EXPORT_SYMBOL(fd_install);
+EXPORT_SYMBOL(put_unused_fd);
/* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
EXPORT_SYMBOL(default_llseek);
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
-/* time */
-EXPORT_SYMBOL(get_fast_time);
-
/* library functions */
EXPORT_SYMBOL(strnicmp);
EXPORT_SYMBOL(strspn);
*/
struct timezone sys_tz;
-static void do_normal_gettime(struct timeval * tm)
-{
- *tm=xtime;
-}
-
-void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
-
-/*
- * Generic way to access 'xtime' (the current time of day).
- * This can be changed if the platform provides a more accurate (and fast!)
- * version.
- */
-
-void get_fast_time(struct timeval * t)
-{
- do_get_fast_time(t);
-}
-
/* The xtime_lock is not only serializing the xtime read/writes but it's also
serializing all accesses to the global NTP variables now. */
extern rwlock_t xtime_lock;
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ * $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
write_lock_bh(&br->hash_lock);
fdb = br->hash[hash];
while (fdb != NULL) {
- if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+ if (!fdb->is_local &&
+ !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
__fdb_possibly_replace(fdb, source, is_local);
write_unlock_bh(&br->hash_lock);
return;
#ifdef CONFIG_NET_FASTROUTE
/* Hack to detect packet socket */
- if (pt->data) {
+ if ((pt->data) && ((int)(pt->data)!=1)) {
netdev_fastroute_obstacles++;
dev_clear_fastroute(pt->dev);
}
void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
{
struct packet_type *ptype;
- get_fast_time(&skb->stamp);
+ do_gettimeofday(&skb->stamp);
br_read_lock(BR_NETPROTO_LOCK);
for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next)
unsigned long flags;
if (skb->stamp.tv_sec == 0)
- get_fast_time(&skb->stamp);
+ do_gettimeofday(&skb->stamp);
/* The code is rearranged so that the path is the most
short when CPU is congested, but is still operating.
dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
dep_tristate ' LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
dep_tristate ' TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
fi
dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+ if [ "$CONFIG_NETLINK" != "n" ]; then
+ dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES
+ fi
dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
fi
obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
# backwards compatibility
/* Fall thru... */
case IPPROTO_TCP:
case IPPROTO_UDP:
- IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+ IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
if (net_ratelimit())
static struct ipt_table nat_table
= { { NULL, NULL }, "nat", &nat_initial_table.repl,
- NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+ NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
LIST_HEAD(nat_expect_list);
* Packet matching code.
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2009-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * - increase module usage count as soon as we have rules inside
+ * a table
*/
#include <linux/config.h>
#include <linux/skbuff.h>
unsigned int size;
/* Number of entries: FIXME. --RR */
unsigned int number;
+ /* Initial number of entries. Needed for module usage count */
+ unsigned int initial_entries;
/* Entry points and underflows */
unsigned int hook_entry[NF_IP_NUMHOOKS];
}
oldinfo = table->private;
table->private = newinfo;
+ newinfo->initial_entries = oldinfo->initial_entries;
write_unlock_bh(&table->lock);
return oldinfo;
if (!oldinfo)
goto free_newinfo_counters_untrans_unlock;
+ /* Update module usage count based on number of rules */
+ duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+ oldinfo->number, oldinfo->initial_entries, newinfo->number);
+ if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ (newinfo->number > oldinfo->initial_entries))
+ __MOD_INC_USE_COUNT(t->me);
+ else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+ (newinfo->number <= oldinfo->initial_entries))
+ __MOD_DEC_USE_COUNT(t->me);
+
/* Get the old counters. */
get_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
int ret;
struct ipt_table_info *newinfo;
static struct ipt_table_info bootstrap
- = { 0, 0, { 0 }, { 0 }, { } };
+ = { 0, 0, 0, { 0 }, { 0 }, { } };
MOD_INC_USE_COUNT;
newinfo = vmalloc(sizeof(struct ipt_table_info)
duprintf("table->private->number = %u\n",
table->private->number);
+
+ /* save number of initial entries */
+ table->private->initial_entries = table->private->number;
table->lock = RW_LOCK_UNLOCKED;
list_prepend(&ipt_tables, table);
}
#endif
- printk("ip_tables: (c)2000 Netfilter core team\n");
+ printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
return 0;
}
i->branch->refcount--;
kfree(i);
i = tmp;
+ MOD_DEC_USE_COUNT;
}
return 0;
}
* interrupts is not necessary. */
chainptr->chain = rule;
if (rule->branch) rule->branch->refcount++;
- return 0;
+ goto append_successful;
}
/* Find the rule before the end of the chain */
for (i = chainptr->chain; i->next; i = i->next);
i->next = rule;
if (rule->branch) rule->branch->refcount++;
+
+append_successful:
+ MOD_INC_USE_COUNT;
return 0;
}
frwl->next = chainptr->chain;
if (frwl->branch) frwl->branch->refcount++;
chainptr->chain = frwl;
- return 0;
+ goto insert_successful;
}
position--;
while (--position && f != NULL) f = f->next;
frwl->next = f->next;
f->next = frwl;
+
+insert_successful:
+ MOD_INC_USE_COUNT;
return 0;
}
i->next = i->next->next;
kfree(tmp);
}
+
+ MOD_DEC_USE_COUNT;
return 0;
}
else
chainptr->chain = ftmp->next;
kfree(ftmp);
+ MOD_DEC_USE_COUNT;
break;
}
tmp->next = tmp2->next;
kfree(tmp2);
+
+ MOD_DEC_USE_COUNT;
return 0;
}
* user defined chain *
* and therefore can be
* deleted */
+ MOD_INC_USE_COUNT;
return 0;
}
* license in recognition of the original copyright.
* -- Alan Cox.
*
- * $Id: ipfwadm_core.c,v 1.9 2001/09/18 22:29:10 davem Exp $
+ * $Id: ipfwadm_core.c,v 1.10 2002/01/23 13:20:54 davem Exp $
*
* Ported from BSD to Linux,
* Alan Cox 22/Nov/1994.
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/socket.h>
#include <linux/sockios.h>
ftmp = *chainptr;
*chainptr = ftmp->fw_next;
kfree(ftmp);
+ MOD_DEC_USE_COUNT();
}
restore_flags(flags);
}
ftmp->fw_next = *chainptr;
*chainptr=ftmp;
restore_flags(flags);
+ MOD_INC_USE_COUNT();
return(0);
}
else
*chainptr=ftmp;
restore_flags(flags);
+ MOD_INC_USE_COUNT();
return(0);
}
}
}
restore_flags(flags);
- if (was_found)
+ if (was_found) {
+ MOD_DEC_USE_COUNT();
return 0;
- else
+ } else
return(EINVAL);
}
printk("[");
dump_packet(info,
(struct iphdr *)(icmph + 1),
- datalen-sizeof(struct iphdr),
+ datalen-sizeof(struct icmphdr),
0);
printk("] ");
}
/* Local packets: make them go to loopback */
if (hooknum == NF_IP_LOCAL_OUT)
newdst = htonl(0x7F000001);
- else
+ else {
+ struct in_device *indev;
+
+ /* Device might not have an associated in_device. */
+ indev = (struct in_device *)(*pskb)->dev->ip_ptr;
+ if (indev == NULL)
+ return NF_DROP;
+
/* Grab first address on interface. */
- newdst = (((struct in_device *)(*pskb)->dev->ip_ptr)
- ->ifa_list->ifa_local);
+ newdst = indev->ifa_list->ifa_local;
+ }
/* Transfer from original range. */
newrange = ((struct ip_nat_multi_range)
--- /dev/null
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander
+ * <zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue.
+ * nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ * module loadtime -HW
+ *
+ * Released under the terms of the GPL
+ *
+ * This module accepts two parameters:
+ *
+ * nlbufsiz:
+ * The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ * Specify, after how many clock ticks (intel: 100 per second) the queue
+ * should be flushed even if it is not full yet.
+ *
+ * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+
+#define ULOG_NL_EVENT 111 /* Harald's favorite number */
+#define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */
+
+#if 0
+#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ":" \
+ format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
+
+
+static unsigned int nlbufsiz = 4096;
+MODULE_PARM(nlbufsiz, "i");
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
+
+static unsigned int flushtimeout = 10 * HZ;
+MODULE_PARM(flushtimeout, "i");
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
+
+/* global data structures */
+
+typedef struct {
+ unsigned int qlen; /* number of nlmsgs' in the skb */
+ struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
+ struct sk_buff *skb; /* the pre-allocated skb */
+ struct timer_list timer; /* the timer function */
+} ulog_buff_t;
+
+static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; /* array of buffers */
+
+static struct sock *nflognl; /* our socket */
+static size_t qlen; /* current length of multipart-nlmsg */
+DECLARE_LOCK(ulog_lock); /* spinlock */
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+ ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+ if (timer_pending(&ub->timer)) {
+ DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+ del_timer(&ub->timer);
+ }
+
+ /* last nlmsg needs NLMSG_DONE */
+ if (ub->qlen > 1)
+ ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+ NETLINK_CB(ub->skb).dst_groups = nlgroup;
+ DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
+ ub->qlen, nlgroup);
+ netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+
+ ub->qlen = 0;
+ ub->skb = NULL;
+ ub->lastnlh = NULL;
+
+}
+
+
+/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
+static void ulog_timer(unsigned long data)
+{
+ DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+
+ /* lock to protect against somebody modifying our structure
+ * from ipt_ulog_target at the same time */
+ LOCK_BH(&ulog_lock);
+ ulog_send(data);
+ UNLOCK_BH(&ulog_lock);
+}
+
+static void nflog_rcv(struct sock *sk, int len)
+{
+ printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
+}
+
+struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+ struct sk_buff *skb;
+
+ /* alloc skb which should be big enough for a whole
+ * multipart message. WARNING: has to be <= 131000
+ * due to slab allocator restrictions */
+
+ skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+ if (!skb) {
+ PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
+ nlbufsiz);
+
+ /* try to allocate only as much as we need for
+ * current packet */
+
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+ }
+
+ return skb;
+}
+
+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+ unsigned int hooknum,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *targinfo, void *userinfo)
+{
+ ulog_buff_t *ub;
+ ulog_packet_msg_t *pm;
+ size_t size, copy_len;
+ struct nlmsghdr *nlh;
+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+ /* calculate the size of the skb needed */
+ if ((loginfo->copy_range == 0) ||
+ (loginfo->copy_range > (*pskb)->len)) {
+ copy_len = (*pskb)->len;
+ } else {
+ copy_len = loginfo->copy_range;
+ }
+
+ size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+
+ ub = &ulog_buffers[loginfo->nl_group];
+
+ LOCK_BH(&ulog_lock);
+
+ if (!ub->skb) {
+ if (!(ub->skb = ulog_alloc_skb(size)))
+ goto alloc_failure;
+ } else if (ub->qlen >= loginfo->qthreshold ||
+ size > skb_tailroom(ub->skb)) {
+ /* either the queue len is too high or we don't have
+ * enough room in nlskb left. send it to userspace. */
+
+ ulog_send(loginfo->nl_group);
+
+ if (!(ub->skb = ulog_alloc_skb(size)))
+ goto alloc_failure;
+ }
+
+ DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen,
+ loginfo->qthreshold);
+
+ /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
+ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT,
+ size - sizeof(*nlh));
+ ub->qlen++;
+
+ pm = NLMSG_DATA(nlh);
+
+ /* copy hook, prefix, timestamp, payload, etc. */
+ pm->data_len = copy_len;
+ pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+ pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+ pm->mark = (*pskb)->nfmark;
+ pm->hook = hooknum;
+ if (loginfo->prefix[0] != '\0')
+ strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+ else
+ *(pm->prefix) = '\0';
+
+ if (in && in->hard_header_len > 0
+ && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
+ && in->hard_header_len <= ULOG_MAC_LEN) {
+ memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
+ pm->mac_len = in->hard_header_len;
+ }
+
+ if (in)
+ strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+ else
+ pm->indev_name[0] = '\0';
+
+ if (out)
+ strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
+ else
+ pm->outdev_name[0] = '\0';
+
+ if (copy_len)
+ memcpy(pm->payload, (*pskb)->data, copy_len);
+
+ /* check if we are building multi-part messages */
+ if (ub->qlen > 1) {
+ ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+ }
+
+ /* if threshold is reached, send message to userspace */
+ if (qlen >= loginfo->qthreshold) {
+ if (loginfo->qthreshold > 1)
+ nlh->nlmsg_type = NLMSG_DONE;
+ }
+
+ ub->lastnlh = nlh;
+
+ /* if timer isn't already running, start it */
+ if (!timer_pending(&ub->timer)) {
+ ub->timer.expires = jiffies + flushtimeout;
+ add_timer(&ub->timer);
+ }
+
+ UNLOCK_BH(&ulog_lock);
+
+ return IPT_CONTINUE;
+
+
+nlmsg_failure:
+ PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+
+alloc_failure:
+ PRINTR("ipt_ULOG: Error building netlink message\n");
+
+ UNLOCK_BH(&ulog_lock);
+
+ return IPT_CONTINUE;
+}
+
+static int ipt_ulog_checkentry(const char *tablename,
+ const struct ipt_entry *e,
+ void *targinfo,
+ unsigned int targinfosize,
+ unsigned int hookmask)
+{
+ struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
+ DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
+ return 0;
+ }
+
+ if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+ DEBUGP("ipt_ULOG: prefix term %i\n",
+ loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+ return 0;
+ }
+
+ if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+ DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
+ loginfo->qthreshold);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_target ipt_ulog_reg =
+ { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
+THIS_MODULE
+};
+
+static int __init init(void)
+{
+ int i;
+
+ DEBUGP("ipt_ULOG: init module\n");
+
+ if (nlbufsiz >= 128*1024) {
+ printk("Netlink buffer has to be <= 128kB\n");
+ return -EINVAL;
+ }
+
+ /* initialize ulog_buffers */
+ for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+ memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
+ init_timer(&ulog_buffers[i].timer);
+ ulog_buffers[i].timer.function = ulog_timer;
+ ulog_buffers[i].timer.data = i;
+ }
+
+ nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+ if (!nflognl)
+ return -ENOMEM;
+
+ if (ipt_register_target(&ipt_ulog_reg) != 0) {
+ sock_release(nflognl->socket);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ DEBUGP("ipt_ULOG: cleanup_module\n");
+
+ ipt_unregister_target(&ipt_ulog_reg);
+ sock_release(nflognl->socket);
+}
+
+module_init(init);
+module_exit(fini);
--- /dev/null
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_ah.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct ahhdr {
+ __u32 spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+ int r=0;
+ duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+ min,spi,max);
+ r=(spi >= min && spi <= max) ^ invert;
+ duprintf(" result %s\n",r? "PASS" : "FAILED");
+ return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ int offset,
+ const void *hdr,
+ u_int16_t datalen,
+ int *hotdrop)
+{
+ const struct ahhdr *ah = hdr;
+ const struct ipt_ah *ahinfo = matchinfo;
+
+ if (offset == 0 && datalen < sizeof(struct ahhdr)) {
+ /* We've been asked to examine this packet, and we
+ can't. Hence, no choice but to drop. */
+ duprintf("Dropping evil AH tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ /* Must not be a fragment. */
+ return !offset
+ && spi_match(ahinfo->spis[0], ahinfo->spis[1],
+ ntohl(ah->spi),
+ !!(ahinfo->invflags & IPT_AH_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+ const struct ipt_ip *ip,
+ void *matchinfo,
+ unsigned int matchinfosize,
+ unsigned int hook_mask)
+{
+ const struct ipt_ah *ahinfo = matchinfo;
+
+ /* Must specify proto == AH, and no unknown invflags */
+ if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
+ duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
+ IPPROTO_AH);
+ return 0;
+ }
+ if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
+ duprintf("ipt_ah: matchsize %u != %u\n",
+ matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
+ return 0;
+ }
+ if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
+ duprintf("ipt_ah: unknown flags %X\n",
+ ahinfo->invflags);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+int __init init(void)
+{
+ return ipt_register_match(&ah_match);
+}
+
+void __exit cleanup(void)
+{
+ ipt_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
--- /dev/null
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_esp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct esphdr {
+ __u32 spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+ int r=0;
+ duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+ min,spi,max);
+ r=(spi >= min && spi <= max) ^ invert;
+ duprintf(" result %s\n",r? "PASS" : "FAILED");
+ return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const void *matchinfo,
+ int offset,
+ const void *hdr,
+ u_int16_t datalen,
+ int *hotdrop)
+{
+ const struct esphdr *esp = hdr;
+ const struct ipt_esp *espinfo = matchinfo;
+
+ if (offset == 0 && datalen < sizeof(struct esphdr)) {
+ /* We've been asked to examine this packet, and we
+ can't. Hence, no choice but to drop. */
+ duprintf("Dropping evil ESP tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ /* Must not be a fragment. */
+ return !offset
+ && spi_match(espinfo->spis[0], espinfo->spis[1],
+ ntohl(esp->spi),
+ !!(espinfo->invflags & IPT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+ const struct ipt_ip *ip,
+ void *matchinfo,
+ unsigned int matchinfosize,
+ unsigned int hook_mask)
+{
+ const struct ipt_esp *espinfo = matchinfo;
+
+ /* Must specify proto == ESP, and no unknown invflags */
+ if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
+ duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
+ IPPROTO_ESP);
+ return 0;
+ }
+ if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
+ duprintf("ipt_esp: matchsize %u != %u\n",
+ matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
+ return 0;
+ }
+ if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
+ duprintf("ipt_esp: unknown flags %X\n",
+ espinfo->invflags);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+ return ipt_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+ ipt_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
static struct ipt_table packet_filter
= { { NULL, NULL }, "filter", &initial_table.repl,
- FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+ FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
/* The work comes in here from netfilter.c. */
static unsigned int
* This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
*/
#include <linux/config.h>
#include <linux/module.h>
#include <net/route.h>
#include <linux/ip.h>
-#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
+ (1 << NF_IP_LOCAL_IN) | \
+ (1 << NF_IP_FORWARD) | \
+ (1 << NF_IP_LOCAL_OUT) | \
+ (1 << NF_IP_POST_ROUTING))
/* Standard entry. */
struct ipt_standard
struct ipt_error_target target;
};
+/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
static struct
{
struct ipt_replace repl;
- struct ipt_standard entries[2];
+ struct ipt_standard entries[5];
struct ipt_error term;
} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
- sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
- { [NF_IP_PRE_ROUTING] 0,
- [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
- { [NF_IP_PRE_ROUTING] 0,
- [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+ sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+ { [NF_IP_PRE_ROUTING] 0,
+ [NF_IP_LOCAL_IN] sizeof(struct ipt_standard),
+ [NF_IP_FORWARD] sizeof(struct ipt_standard) * 2,
+ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 3,
+ [NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 4 },
+ { [NF_IP_PRE_ROUTING] 0,
+ [NF_IP_LOCAL_IN] sizeof(struct ipt_standard),
+ [NF_IP_FORWARD] sizeof(struct ipt_standard) * 2,
+ [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) * 3,
+ [NF_IP_POST_ROUTING] sizeof(struct ipt_standard) * 4 },
0, NULL, { } },
{
/* PRE_ROUTING */
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
+ /* LOCAL_IN */
+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
/* LOCAL_OUT */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ipt_standard),
0, { 0, 0 }, { } },
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } }
+ -NF_ACCEPT - 1 } },
+ /* POST_ROUTING */
+ { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
},
/* ERROR */
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
static struct ipt_table packet_mangler
= { { NULL, NULL }, "mangle", &initial_table.repl,
- MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+ MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
/* The work comes in here from netfilter.c. */
static unsigned int
-ipt_hook(unsigned int hook,
+ipt_route_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
}
static unsigned int
-ipt_local_out_hook(unsigned int hook,
+ipt_local_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
}
static struct nf_hook_ops ipt_ops[]
-= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
- { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
- NF_IP_PRI_MANGLE }
+= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING,
+ NF_IP_PRI_MANGLE },
+ { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+ NF_IP_PRI_MANGLE },
+ { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
+ NF_IP_PRI_MANGLE },
+ { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
+ NF_IP_PRI_MANGLE },
+ { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
+ NF_IP_PRI_MANGLE }
};
static int __init init(void)
if (ret < 0)
goto cleanup_hook0;
+ ret = nf_register_hook(&ipt_ops[2]);
+ if (ret < 0)
+ goto cleanup_hook1;
+
+ ret = nf_register_hook(&ipt_ops[3]);
+ if (ret < 0)
+ goto cleanup_hook2;
+
+ ret = nf_register_hook(&ipt_ops[4]);
+ if (ret < 0)
+ goto cleanup_hook3;
+
return ret;
+ cleanup_hook3:
+ nf_unregister_hook(&ipt_ops[3]);
+ cleanup_hook2:
+ nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+ nf_unregister_hook(&ipt_ops[1]);
cleanup_hook0:
nf_unregister_hook(&ipt_ops[0]);
cleanup_table:
struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
struct neighbour *neigh;
struct inet6_ifaddr *ifp;
+ unsigned int payload_len;
__skb_push(skb, skb->data-skb->h.raw);
* (Some checking in ndisc_find_option)
*/
+ payload_len = ntohs(skb->nh.ipv6h->payload_len);
switch (msg->icmph.icmp6_type) {
case NDISC_NEIGHBOUR_SOLICITATION:
/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
- if (skb->nh.ipv6h->payload_len < 8+16) {
+ if (payload_len < 8+16) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: packet too short\n");
return 0;
case NDISC_NEIGHBOUR_ADVERTISEMENT:
/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
- if (skb->nh.ipv6h->payload_len < 16+8 ) {
+ if (payload_len < 16+8 ) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NA: packet too short\n");
return 0;
case NDISC_ROUTER_ADVERTISEMENT:
/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
- if (skb->nh.ipv6h->payload_len < 8+4+4) {
+ if (payload_len < 8+4+4) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP RA: packet too short\n");
return 0;
case NDISC_REDIRECT:
/* XXX: import nd_redirect from glibc netinet/icmp6.h */
- if (skb->nh.ipv6h->payload_len < 8+16+16) {
+ if (payload_len < 8+16+16) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP redirect: packet too short\n");
return 0;
/* No RS support in the kernel, but we do some required checks */
/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
- if (skb->nh.ipv6h->payload_len < 8) {
+ if (payload_len < 8) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP RS: packet too short\n");
return 0;
# dep_tristate ' FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
#fi
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-# tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
+fi
+
tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
# The simple matches.
obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * This is a module which is used for queueing IPv6 packets and
+ * communicating with userspace via netlink.
+ *
+ * (C) 2001 Fernando Anton, this code is GPL.
+ * IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ * Universidad Carlos III de Madrid - Leganes (Madrid) - Spain
+ * Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain
+ * email: fanton@it.uc3m.es
+ *
+ * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
+ * to adapt it to IPv6
+ * HEAVILY based in ipqueue.c by James Morris. It's just
+ * a little modified version of it, so he's nearly the
+ * real coder of this.
+ * Few changes needed, mainly the hard_routing code and
+ * the netlink socket protocol (we're NETLINK_IP6_FW).
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+/* We're still usign the following structs. No need to change them: */
+/* ipq_packet_msg */
+/* ipq_mode_msg */
+/* ipq_verdict_msg */
+/* ipq_peer_msg */
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define IPQ_QMAX_DEFAULT 1024
+#define IPQ_PROC_FS_NAME "ip6_queue"
+#define NET_IPQ_QMAX 2088
+#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
+
+typedef struct ip6q_rt_info {
+ struct in6_addr daddr;
+ struct in6_addr saddr;
+} ip6q_rt_info_t;
+
+typedef struct ip6q_queue_element {
+ struct list_head list; /* Links element into queue */
+ int verdict; /* Current verdict */
+ struct nf_info *info; /* Extra info from netfilter */
+ struct sk_buff *skb; /* Packet inside */
+ ip6q_rt_info_t rt_info; /* May need post-mangle routing */
+} ip6q_queue_element_t;
+
+typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
+
+typedef struct ip6q_peer {
+ pid_t pid; /* PID of userland peer */
+ unsigned char died; /* We think the peer died */
+ unsigned char copy_mode; /* Copy packet as well as metadata? */
+ size_t copy_range; /* Range past metadata to copy */
+ ip6q_send_cb_t send; /* Callback for sending data to peer */
+} ip6q_peer_t;
+
+typedef struct ip6q_queue {
+ int len; /* Current queue len */
+ int *maxlen; /* Maximum queue len, via sysctl */
+ unsigned char flushing; /* If queue is being flushed */
+ unsigned char terminate; /* If the queue is being terminated */
+ struct list_head list; /* Head of packet queue */
+ spinlock_t lock; /* Queue spinlock */
+ ip6q_peer_t peer; /* Userland peer */
+} ip6q_queue_t;
+
+/****************************************************************************
+ *
+ * Packet queue
+ *
+ ****************************************************************************/
+/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
+static ip6q_queue_element_t *
+ip6q_dequeue(ip6q_queue_t *q,
+ int (*cmp)(ip6q_queue_element_t *, unsigned long),
+ unsigned long data)
+{
+ struct list_head *i;
+
+ spin_lock_bh(&q->lock);
+ for (i = q->list.prev; i != &q->list; i = i->prev) {
+ ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
+
+ if (!cmp || cmp(e, data)) {
+ list_del(&e->list);
+ q->len--;
+ spin_unlock_bh(&q->lock);
+ return e;
+ }
+ }
+ spin_unlock_bh(&q->lock);
+ return NULL;
+}
+
+/* Flush all packets */
+static void ip6q_flush(ip6q_queue_t *q)
+{
+ ip6q_queue_element_t *e;
+
+ spin_lock_bh(&q->lock);
+ q->flushing = 1;
+ spin_unlock_bh(&q->lock);
+ while ((e = ip6q_dequeue(q, NULL, 0))) {
+ e->verdict = NF_DROP;
+ nf_reinject(e->skb, e->info, e->verdict);
+ kfree(e);
+ }
+ spin_lock_bh(&q->lock);
+ q->flushing = 0;
+ spin_unlock_bh(&q->lock);
+}
+
+static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
+ ip6q_send_cb_t send_cb,
+ int *errp, int *sysctl_qmax)
+{
+ int status;
+ ip6q_queue_t *q;
+
+ *errp = 0;
+ q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
+ if (q == NULL) {
+ *errp = -ENOMEM;
+ return NULL;
+ }
+ q->peer.pid = 0;
+ q->peer.died = 0;
+ q->peer.copy_mode = IPQ_COPY_NONE;
+ q->peer.copy_range = 0;
+ q->peer.send = send_cb;
+ q->len = 0;
+ q->maxlen = sysctl_qmax;
+ q->flushing = 0;
+ q->terminate = 0;
+ INIT_LIST_HEAD(&q->list);
+ spin_lock_init(&q->lock);
+ status = nf_register_queue_handler(PF_INET6, outfn, q);
+ if (status < 0) {
+ *errp = -EBUSY;
+ kfree(q);
+ return NULL;
+ }
+ return q;
+}
+
+static int ip6q_enqueue(ip6q_queue_t *q,
+ struct sk_buff *skb, struct nf_info *info)
+{
+ ip6q_queue_element_t *e;
+ int status;
+
+ e = kmalloc(sizeof(*e), GFP_ATOMIC);
+ if (e == NULL) {
+ printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+ return -ENOMEM;
+ }
+
+ e->verdict = NF_DROP;
+ e->info = info;
+ e->skb = skb;
+
+ if (e->info->hook == NF_IP_LOCAL_OUT) {
+ struct ipv6hdr *iph = skb->nh.ipv6h;
+
+ e->rt_info.daddr = iph->daddr;
+ e->rt_info.saddr = iph->saddr;
+ }
+
+ spin_lock_bh(&q->lock);
+ if (q->len >= *q->maxlen) {
+ spin_unlock_bh(&q->lock);
+ if (net_ratelimit())
+ printk(KERN_WARNING "ip6_queue: full at %d entries, "
+ "dropping packet(s).\n", q->len);
+ goto free_drop;
+ }
+ if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+ || q->peer.pid == 0 || q->peer.died || q->terminate) {
+ spin_unlock_bh(&q->lock);
+ goto free_drop;
+ }
+ status = q->peer.send(e);
+ if (status > 0) {
+ list_add(&e->list, &q->list);
+ q->len++;
+ spin_unlock_bh(&q->lock);
+ return status;
+ }
+ spin_unlock_bh(&q->lock);
+ if (status == -ECONNREFUSED) {
+ printk(KERN_INFO "ip6_queue: peer %d died, "
+ "resetting state and flushing queue\n", q->peer.pid);
+ q->peer.died = 1;
+ q->peer.pid = 0;
+ q->peer.copy_mode = IPQ_COPY_NONE;
+ q->peer.copy_range = 0;
+ ip6q_flush(q);
+ }
+free_drop:
+ kfree(e);
+ return -EBUSY;
+}
+
+static void ip6q_destroy_queue(ip6q_queue_t *q)
+{
+ nf_unregister_queue_handler(PF_INET6);
+ spin_lock_bh(&q->lock);
+ q->terminate = 1;
+ spin_unlock_bh(&q->lock);
+ ip6q_flush(q);
+ kfree(q);
+}
+
+/*
+ * Taken from net/ipv6/ip6_output.c
+ *
+ * We should use the one there, but is defined static
+ * so we put this just here and let the things as
+ * they are now.
+ *
+ * If that one is modified, this one should be modified too.
+ */
+static int route6_me_harder(struct sk_buff *skb)
+{
+ struct ipv6hdr *iph = skb->nh.ipv6h;
+ struct dst_entry *dst;
+ struct flowi fl;
+
+ fl.proto = iph->nexthdr;
+ fl.fl6_dst = &iph->daddr;
+ fl.fl6_src = &iph->saddr;
+ fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
+ fl.fl6_flowlabel = 0;
+ fl.uli_u.ports.dport = 0;
+ fl.uli_u.ports.sport = 0;
+
+ dst = ip6_route_output(skb->sk, &fl);
+
+ if (dst->error) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+ return -EINVAL;
+ }
+
+ /* Drop old route. */
+ dst_release(skb->dst);
+
+ skb->dst = dst;
+ return 0;
+}
+static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+{
+ int diff;
+ struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+
+ if (v->data_len < sizeof(*user_iph))
+ return 0;
+ diff = v->data_len - e->skb->len;
+ if (diff < 0)
+ skb_trim(e->skb, v->data_len);
+ else if (diff > 0) {
+ if (v->data_len > 0xFFFF)
+ return -EINVAL;
+ if (diff > skb_tailroom(e->skb)) {
+ struct sk_buff *newskb;
+
+ newskb = skb_copy_expand(e->skb,
+ skb_headroom(e->skb),
+ diff,
+ GFP_ATOMIC);
+ if (newskb == NULL) {
+ printk(KERN_WARNING "ip6_queue: OOM "
+ "in mangle, dropping packet\n");
+ return -ENOMEM;
+ }
+ if (e->skb->sk)
+ skb_set_owner_w(newskb, e->skb->sk);
+ kfree_skb(e->skb);
+ e->skb = newskb;
+ }
+ skb_put(e->skb, diff);
+ }
+ memcpy(e->skb->data, v->payload, v->data_len);
+ e->skb->nfcache |= NFC_ALTERED;
+
+ /*
+ * Extra routing may needed on local out, as the QUEUE target never
+ * returns control to the table.
+ * Not a nice way to cmp, but works
+ */
+ if (e->info->hook == NF_IP_LOCAL_OUT) {
+ struct ipv6hdr *iph = e->skb->nh.ipv6h;
+ if (!( iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
+ && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
+ && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
+ && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
+ && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
+ && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
+ && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
+ && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+ return route6_me_harder(e->skb);
+ }
+ return 0;
+}
+
+static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+{
+ return (id == (unsigned long )e);
+}
+
+static int ip6q_set_verdict(ip6q_queue_t *q,
+ ipq_verdict_msg_t *v, unsigned int len)
+{
+ ip6q_queue_element_t *e;
+
+ if (v->value > NF_MAX_VERDICT)
+ return -EINVAL;
+ e = ip6q_dequeue(q, id_cmp, v->id);
+ if (e == NULL)
+ return -ENOENT;
+ else {
+ e->verdict = v->value;
+ if (v->data_len && v->data_len == len)
+ if (ip6q_mangle_ipv6(v, e) < 0)
+ e->verdict = NF_DROP;
+ nf_reinject(e->skb, e->info, e->verdict);
+ kfree(e);
+ return 0;
+ }
+}
+
+static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
+ unsigned char type, unsigned int len)
+{
+
+ int status = 0;
+ int busy;
+
+ spin_lock_bh(&q->lock);
+ busy = (q->terminate || q->flushing);
+ spin_unlock_bh(&q->lock);
+ if (busy)
+ return -EBUSY;
+ if (len < sizeof(ipq_peer_msg_t))
+ return -EINVAL;
+ switch (type) {
+ case IPQM_MODE:
+ switch (m->msg.mode.value) {
+ case IPQ_COPY_META:
+ q->peer.copy_mode = IPQ_COPY_META;
+ q->peer.copy_range = 0;
+ break;
+ case IPQ_COPY_PACKET:
+ q->peer.copy_mode = IPQ_COPY_PACKET;
+ q->peer.copy_range = m->msg.mode.range;
+ if (q->peer.copy_range > 0xFFFF)
+ q->peer.copy_range = 0xFFFF;
+ break;
+ default:
+ status = -EINVAL;
+ }
+ break;
+ case IPQM_VERDICT:
+ if (m->msg.verdict.value > NF_MAX_VERDICT)
+ status = -EINVAL;
+ else
+ status = ip6q_set_verdict(q,
+ &m->msg.verdict,
+ len - sizeof(*m));
+ break;
+ default:
+ status = -EINVAL;
+ }
+ return status;
+}
+
+static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+{
+ if (e->info->indev)
+ if (e->info->indev->ifindex == ifindex)
+ return 1;
+ if (e->info->outdev)
+ if (e->info->outdev->ifindex == ifindex)
+ return 1;
+ return 0;
+}
+
+/* Drop any queued packets associated with device ifindex */
+static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+{
+ ip6q_queue_element_t *e;
+
+ while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
+ e->verdict = NF_DROP;
+ nf_reinject(e->skb, e->info, e->verdict);
+ kfree(e);
+ }
+}
+
+/****************************************************************************
+ *
+ * Netfilter interface
+ *
+ ****************************************************************************/
+
+/*
+ * Packets arrive here from netfilter for queuing to userspace.
+ * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
+ */
+static int netfilter6_receive(struct sk_buff *skb,
+ struct nf_info *info, void *data)
+{
+ return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
+}
+
+/****************************************************************************
+ *
+ * Netlink interface.
+ *
+ ****************************************************************************/
+
+static struct sock *nfnl = NULL;
+/* This is not a static one, so we should not repeat its name */
+ip6q_queue_t *nlq6 = NULL;
+
+static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
+{
+ unsigned char *old_tail;
+ size_t size = 0;
+ size_t data_len = 0;
+ struct sk_buff *skb;
+ ipq_packet_msg_t *pm;
+ struct nlmsghdr *nlh;
+
+ switch (nlq6->peer.copy_mode) {
+ size_t copy_range;
+
+ case IPQ_COPY_META:
+ size = NLMSG_SPACE(sizeof(*pm));
+ data_len = 0;
+ break;
+ case IPQ_COPY_PACKET:
+ copy_range = nlq6->peer.copy_range;
+ if (copy_range == 0 || copy_range > e->skb->len)
+ data_len = e->skb->len;
+ else
+ data_len = copy_range;
+ size = NLMSG_SPACE(sizeof(*pm) + data_len);
+
+ break;
+ case IPQ_COPY_NONE:
+ default:
+ *errp = -EINVAL;
+ return NULL;
+ }
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ goto nlmsg_failure;
+ old_tail = skb->tail;
+ nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+ pm = NLMSG_DATA(nlh);
+ memset(pm, 0, sizeof(*pm));
+ pm->packet_id = (unsigned long )e;
+ pm->data_len = data_len;
+ pm->timestamp_sec = e->skb->stamp.tv_sec;
+ pm->timestamp_usec = e->skb->stamp.tv_usec;
+ pm->mark = e->skb->nfmark;
+ pm->hook = e->info->hook;
+ if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
+ else pm->indev_name[0] = '\0';
+ if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
+ else pm->outdev_name[0] = '\0';
+ pm->hw_protocol = e->skb->protocol;
+ if (e->info->indev && e->skb->dev) {
+ pm->hw_type = e->skb->dev->type;
+ if (e->skb->dev->hard_header_parse)
+ pm->hw_addrlen =
+ e->skb->dev->hard_header_parse(e->skb,
+ pm->hw_addr);
+ }
+ if (data_len)
+ memcpy(pm->payload, e->skb->data, data_len);
+ nlh->nlmsg_len = skb->tail - old_tail;
+ NETLINK_CB(skb).dst_groups = 0;
+ return skb;
+nlmsg_failure:
+ if (skb)
+ kfree_skb(skb);
+ *errp = 0;
+ printk(KERN_ERR "ip6_queue: error creating netlink message\n");
+ return NULL;
+}
+
+static int netlink_send_peer(ip6q_queue_element_t *e)
+{
+ int status = 0;
+ struct sk_buff *skb;
+
+ skb = netlink_build_message(e, &status);
+ if (skb == NULL)
+ return status;
+ return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+
+static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+{
+ int status, type;
+ struct nlmsghdr *nlh;
+
+ if (skb->len < sizeof(struct nlmsghdr))
+ return;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+ || skb->len < nlh->nlmsg_len)
+ return;
+
+ if(nlh->nlmsg_pid <= 0
+ || !(nlh->nlmsg_flags & NLM_F_REQUEST)
+ || nlh->nlmsg_flags & NLM_F_MULTI)
+ RCV_SKB_FAIL(-EINVAL);
+ if (nlh->nlmsg_flags & MSG_TRUNC)
+ RCV_SKB_FAIL(-ECOMM);
+ type = nlh->nlmsg_type;
+ if (type < NLMSG_NOOP || type >= IPQM_MAX)
+ RCV_SKB_FAIL(-EINVAL);
+ if (type <= IPQM_BASE)
+ return;
+ if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ RCV_SKB_FAIL(-EPERM);
+ if (nlq6->peer.pid && !nlq6->peer.died
+ && (nlq6->peer.pid != nlh->nlmsg_pid)) {
+ printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
+ "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
+ ip6q_flush(nlq6);
+ }
+ nlq6->peer.pid = nlh->nlmsg_pid;
+ nlq6->peer.died = 0;
+ status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
+ type, skb->len - NLMSG_LENGTH(0));
+ if (status < 0)
+ RCV_SKB_FAIL(status);
+ if (nlh->nlmsg_flags & NLM_F_ACK)
+ netlink_ack(skb, nlh, 0);
+ return;
+}
+
+/* Note: we are only dealing with single part messages at the moment. */
+static void netlink_receive_user_sk(struct sock *sk, int len)
+{
+ do {
+ struct sk_buff *skb;
+
+ if (rtnl_shlock_nowait())
+ return;
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+ netlink_receive_user_skb(skb);
+ kfree_skb(skb);
+ }
+ up(&rtnl_sem);
+ } while (nfnl && nfnl->receive_queue.qlen);
+}
+
+/****************************************************************************
+ *
+ * System events
+ *
+ ****************************************************************************/
+
+static int receive_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ /* Drop any packets associated with the downed device */
+ if (event == NETDEV_DOWN)
+ ip6q_dev_drop(nlq6, dev->ifindex);
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ip6q_dev_notifier = {
+ receive_event,
+ NULL,
+ 0
+};
+
+/****************************************************************************
+ *
+ * Sysctl - queue tuning.
+ *
+ ****************************************************************************/
+
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+
+static struct ctl_table_header *ip6q_sysctl_header;
+
+static ctl_table ip6q_table[] = {
+ { NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
+ sizeof(sysctl_maxlen), 0644, NULL, proc_dointvec },
+ { 0 }
+};
+
+static ctl_table ip6q_dir_table[] = {
+ {NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+ { 0 }
+};
+
+static ctl_table ip6q_root_table[] = {
+ {CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+ { 0 }
+};
+
+/****************************************************************************
+ *
+ * Procfs - debugging info.
+ *
+ ****************************************************************************/
+
+static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+{
+ int len;
+
+ spin_lock_bh(&nlq6->lock);
+ len = sprintf(buffer,
+ "Peer pid : %d\n"
+ "Peer died : %d\n"
+ "Peer copy mode : %d\n"
+ "Peer copy range : %Zu\n"
+ "Queue length : %d\n"
+ "Queue max. length : %d\n"
+ "Queue flushing : %d\n"
+ "Queue terminate : %d\n",
+ nlq6->peer.pid,
+ nlq6->peer.died,
+ nlq6->peer.copy_mode,
+ nlq6->peer.copy_range,
+ nlq6->len,
+ *nlq6->maxlen,
+ nlq6->flushing,
+ nlq6->terminate);
+ spin_unlock_bh(&nlq6->lock);
+ *start = buffer + offset;
+ len -= offset;
+ if (len > length)
+ len = length;
+ else if (len < 0)
+ len = 0;
+ return len;
+}
+
+/****************************************************************************
+ *
+ * Module stuff.
+ *
+ ****************************************************************************/
+
+static int __init init(void)
+{
+ int status = 0;
+ struct proc_dir_entry *proc;
+
+ /* We must create the NETLINK_IP6_FW protocol service */
+ nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
+ if (nfnl == NULL) {
+ printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+ "create kernel netlink socket\n");
+ return -ENOMEM;
+ }
+ nlq6 = ip6q_create_queue(netfilter6_receive,
+ netlink_send_peer, &status, &sysctl_maxlen);
+ if (nlq6 == NULL) {
+ printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+ "create queue\n");
+ sock_release(nfnl->socket);
+ return status;
+ }
+ /* The file will be /proc/net/ip6_queue */
+ proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
+ if (proc) proc->owner = THIS_MODULE;
+ else {
+ ip6q_destroy_queue(nlq6);
+ sock_release(nfnl->socket);
+ return -ENOMEM;
+ }
+ register_netdevice_notifier(&ip6q_dev_notifier);
+ ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+ return status;
+}
+
+static void __exit fini(void)
+{
+ unregister_sysctl_table(ip6q_sysctl_header);
+ proc_net_remove(IPQ_PROC_FS_NAME);
+ unregister_netdevice_notifier(&ip6q_dev_notifier);
+ ip6q_destroy_queue(nlq6);
+ sock_release(nfnl->socket);
+}
+
+MODULE_DESCRIPTION("IPv6 packet queue handler");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
* Packet matching code.
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * - increase module usage count as soon as we have rules inside
+ * a table
*/
#include <linux/config.h>
#include <linux/skbuff.h>
unsigned int size;
/* Number of entries: FIXME. --RR */
unsigned int number;
+ /* Initial number of entries. Needed for module usage count */
+ unsigned int initial_entries;
/* Entry points and underflows */
unsigned int hook_entry[NF_IP6_NUMHOOKS];
}
oldinfo = table->private;
table->private = newinfo;
+ newinfo->initial_entries = oldinfo->initial_entries;
write_unlock_bh(&table->lock);
return oldinfo;
if (!oldinfo)
goto free_newinfo_counters_untrans_unlock;
+ /* Update module usage count based on number of rules */
+ duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+ oldinfo->number, oldinfo->initial_entries, newinfo->number);
+ if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ (newinfo->number > oldinfo->initial_entries))
+ __MOD_INC_USE_COUNT(t->me);
+ else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+ (newinfo->number <= oldinfo->initial_entries))
+ __MOD_DEC_USE_COUNT(t->me);
+
/* Get the old counters. */
get_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
int ret;
struct ip6t_table_info *newinfo;
static struct ip6t_table_info bootstrap
- = { 0, 0, { 0 }, { 0 }, { }, { } };
+ = { 0, 0, 0, { 0 }, { 0 }, { }, { } };
MOD_INC_USE_COUNT;
newinfo = vmalloc(sizeof(struct ip6t_table_info)
}
#endif
- printk("ip6_tables: (c)2000 Netfilter core team\n");
+ printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
return 0;
}
static int __init init(void)
{
- printk(KERN_DEBUG "registreing ipv6 mark target\n");
+ printk(KERN_DEBUG "registering ipv6 mark target\n");
if (ip6t_register_target(&ip6t_mark_reg))
return -EINVAL;
static struct ip6t_table packet_filter
= { { NULL, NULL }, "filter", &initial_table.repl,
- FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+ FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
/* The work comes in here from netfilter.c. */
static unsigned int
/*
* IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
*
- * Copyright (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
*/
#include <linux/module.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
-#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
+ (1 << NF_IP6_LOCAL_IN) | \
+ (1 << NF_IP6_FORWARD) | \
+ (1 << NF_IP6_LOCAL_OUT) | \
+ (1 << NF_IP6_POST_ROUTING))
-#if 1
+#if 0
#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
#else
#define DEBUGP(x, args...)
static struct
{
struct ip6t_replace repl;
- struct ip6t_standard entries[2];
+ struct ip6t_standard entries[5];
struct ip6t_error term;
} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
- sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
- { [NF_IP6_PRE_ROUTING] 0,
- [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
- { [NF_IP6_PRE_ROUTING] 0,
- [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+ sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+ { [NF_IP6_PRE_ROUTING] 0,
+ [NF_IP6_LOCAL_IN] sizeof(struct ip6t_standard),
+ [NF_IP6_FORWARD] sizeof(struct ip6t_standard) * 2,
+ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) * 3,
+ [NF_IP6_POST_ROUTING] sizeof(struct ip6t_standard) * 4},
+ { [NF_IP6_PRE_ROUTING] 0,
+ [NF_IP6_LOCAL_IN] sizeof(struct ip6t_standard),
+ [NF_IP6_FORWARD] sizeof(struct ip6t_standard) * 2,
+ [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) * 3,
+ [NF_IP6_POST_ROUTING] sizeof(struct ip6t_standard) * 4},
0, NULL, { } },
{
/* PRE_ROUTING */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_IN */
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+ 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* POST_ROUTING */
{ { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
static struct ip6t_table packet_mangler
= { { NULL, NULL }, "mangle", &initial_table.repl,
- MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+ MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
/* The work comes in here from netfilter.c. */
static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_route_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
}
static unsigned int
-ip6t_local_out_hook(unsigned int hook,
+ip6t_local_hook(unsigned int hook,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
}
static struct nf_hook_ops ip6t_ops[]
-= { { { NULL, NULL }, ip6t_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
- { { NULL, NULL }, ip6t_local_out_hook, PF_INET6, NF_IP6_LOCAL_OUT,
- NF_IP6_PRI_MANGLE }
+= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
+ { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN, NF_IP6_PRI_MANGLE },
+ { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD, NF_IP6_PRI_MANGLE },
+ { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT, NF_IP6_PRI_MANGLE },
+ { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE }
};
static int __init init(void)
if (ret < 0)
goto cleanup_hook0;
+ ret = nf_register_hook(&ip6t_ops[2]);
+ if (ret < 0)
+ goto cleanup_hook1;
+
+ ret = nf_register_hook(&ip6t_ops[3]);
+ if (ret < 0)
+ goto cleanup_hook2;
+
+ ret = nf_register_hook(&ip6t_ops[4]);
+ if (ret < 0)
+ goto cleanup_hook3;
+
return ret;
+ cleanup_hook3:
+ nf_unregister_hook(&ip6t_ops[3]);
+ cleanup_hook2:
+ nf_unregister_hook(&ip6t_ops[2]);
+ cleanup_hook1:
+ nf_unregister_hook(&ip6t_ops[1]);
cleanup_hook0:
nf_unregister_hook(&ip6t_ops[0]);
cleanup_table:
register_netdevice_notifier(&irda_dev_notifier);
irda_init();
-#ifdef MODULE
- irda_device_init(); /* Called by init/main.c when non-modular */
-#endif
+ irda_device_init();
return 0;
}
-#ifdef MODULE
-module_init(irda_proto_init); /* If non-module, called from init/main.c */
-#endif
+
+late_initcall(irda_proto_init);
/*
* Function irda_proto_cleanup (void)
#include <asm/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
#include <net/sock.h>
#define NL_EMULATE_DEV
#endif
-#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
-
struct netlink_opt
{
u32 pid;
EXPORT_SYMBOL(ndisc_mc_map);
EXPORT_SYMBOL(register_inet6addr_notifier);
EXPORT_SYMBOL(unregister_inet6addr_notifier);
+#include <net/ip6_route.h>
+EXPORT_SYMBOL(ip6_route_output);
#endif
#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
/* inet functions common to v4 and v6 */
EXPORT_SYMBOL(hippi_type_trans);
#endif
+#ifdef CONFIG_NET_FASTROUTE
+EXPORT_SYMBOL(netdev_fastroute);
+#endif
+
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_wmem_max);
EXPORT_SYMBOL(sysctl_rmem_max);