--- linux-2.6.8-rc1/arch/alpha/kernel/core_tsunami.c 2004-02-17 20:48:42.000000000 -0800 +++ 25/arch/alpha/kernel/core_tsunami.c 2004-07-13 17:09:13.000000000 -0700 @@ -263,9 +263,9 @@ tsunami_init_one_pchip(tsunami_pchip *pc hose->sparse_mem_base = 0; hose->sparse_io_base = 0; hose->dense_mem_base - = (TSUNAMI_MEM(index) & 0xffffffffff) | 0x80000000000; + = (TSUNAMI_MEM(index) & 0xffffffffffL) | 0x80000000000L; hose->dense_io_base - = (TSUNAMI_IO(index) & 0xffffffffff) | 0x80000000000; + = (TSUNAMI_IO(index) & 0xffffffffffL) | 0x80000000000L; hose->config_space_base = TSUNAMI_CONF(index); hose->index = index; --- linux-2.6.8-rc1/arch/alpha/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/alpha/kernel/irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -361,7 +361,7 @@ init_irq_proc (void) int i; /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); #ifdef CONFIG_SMP /* create /proc/irq/prof_cpu_mask */ --- linux-2.6.8-rc1/arch/alpha/kernel/osf_sys.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/alpha/kernel/osf_sys.c 2004-07-13 17:09:13.000000000 -0700 @@ -588,7 +588,7 @@ osf_sigstack(struct sigstack __user *uss int error; if (uss) { - void *ss_sp; + void __user *ss_sp; error = -EFAULT; if (get_user(ss_sp, &uss->ss_sp)) @@ -762,7 +762,7 @@ osf_setsysinfo(unsigned long op, void __ info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = si_code; - info.si_addr = 0; /* FIXME */ + info.si_addr = NULL; /* FIXME */ send_sig_info(SIGFPE, &info, current); } @@ -956,7 +956,7 @@ osf_utimes(char __user *filename, struct return -EFAULT; } - return do_utimes(filename, tvs ? ktvs : 0); + return do_utimes(filename, tvs ? ktvs : NULL); } #define MAX_SELECT_SECONDS \ @@ -1303,7 +1303,7 @@ osf_fix_iov_len(const struct iovec __use unsigned long i; for (i = 0 ; i < count ; i++) { - int *iov_len_high = (int __user *)&iov[i].iov_len + 1; + int __user *iov_len_high = (int __user *)&iov[i].iov_len + 1; if (put_user(0, iov_len_high)) return -EFAULT; --- linux-2.6.8-rc1/arch/alpha/kernel/process.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/alpha/kernel/process.c 2004-07-13 17:09:13.000000000 -0700 @@ -189,7 +189,7 @@ EXPORT_SYMBOL(machine_power_off); void show_regs(struct pt_regs *regs) { - dik_show_regs(regs, 0); + dik_show_regs(regs, NULL); } /* --- linux-2.6.8-rc1/arch/alpha/kernel/signal.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/alpha/kernel/signal.c 2004-07-13 17:09:13.000000000 -0700 @@ -304,7 +304,7 @@ do_sigreturn(struct sigcontext __user *s info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; info.si_trapno = 0; send_sig_info(SIGTRAP, &info, current); } @@ -342,7 +342,7 @@ do_rt_sigreturn(struct rt_sigframe __use info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; info.si_trapno = 0; send_sig_info(SIGTRAP, &info, current); } --- linux-2.6.8-rc1/arch/alpha/kernel/smc37c669.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/alpha/kernel/smc37c669.c 2004-07-13 17:09:13.000000000 -0700 @@ -996,7 +996,7 @@ static SMC37c669_CONFIG_REGS *SMC37c669 ** and standard ISA IRQs. ** */ -static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata = 0; +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; /* ** The following definition is for the default IRQ @@ -1045,7 +1045,7 @@ static SMC37c669_IRQ_TRANSLATION_ENTRY * ** ISA DMA channels. ** */ -static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata = 0; +static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; /* ** The following definition is the default DRQ --- linux-2.6.8-rc1/arch/alpha/kernel/smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/alpha/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -439,8 +439,6 @@ smp_boot_one_cpu(int cpuid) if (IS_ERR(idle)) panic("failed fork for CPU %d", cpuid); - wake_up_forked_process(idle); - init_idle(idle, cpuid); unhash_process(idle); @@ -864,7 +862,7 @@ smp_call_function_on_cpu (void (*func) ( /* We either got one or timed out -- clear the lock. */ mb(); - smp_call_function_data = 0; + smp_call_function_data = NULL; /* * If after both the initial and long timeout periods we still don't --- linux-2.6.8-rc1/arch/alpha/kernel/traps.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/alpha/kernel/traps.c 2004-07-13 17:09:13.000000000 -0700 @@ -223,12 +223,12 @@ do_entArith(unsigned long summary, unsig if (si_code == 0) return; } - die_if_kernel("Arithmetic fault", regs, 0, 0); + die_if_kernel("Arithmetic fault", regs, 0, NULL); info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = si_code; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; send_sig_info(SIGFPE, &info, current); } @@ -247,7 +247,7 @@ do_entIF(unsigned long type, struct pt_r data[0]); } die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), - regs, type, 0); + regs, type, NULL); } switch (type) { @@ -256,7 +256,7 @@ do_entIF(unsigned long type, struct pt_r info.si_errno = 0; info.si_code = TRAP_BRKPT; info.si_trapno = 0; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; if (ptrace_cancel_bpt(current)) { regs->pc -= 4; /* make pc point to former bpt */ @@ -269,13 +269,13 @@ do_entIF(unsigned long type, struct pt_r info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = __SI_FAULT; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; info.si_trapno = 0; send_sig_info(SIGTRAP, &info, current); return; case 2: /* gentrap */ - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; info.si_trapno = regs->r16; switch ((long) regs->r16) { case GEN_INTOVF: @@ -337,7 +337,7 @@ do_entIF(unsigned long type, struct pt_r info.si_signo = signo; info.si_errno = 0; info.si_code = code; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; send_sig_info(signo, &info, current); return; @@ -365,7 +365,7 @@ do_entIF(unsigned long type, struct pt_r info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = si_code; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; send_sig_info(SIGFPE, &info, current); return; } @@ -394,7 +394,7 @@ do_entIF(unsigned long type, struct pt_r info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; send_sig_info(SIGILL, &info, current); } @@ -410,12 +410,12 @@ do_entDbg(struct pt_regs *regs) { siginfo_t info; - die_if_kernel("Instruction fault", regs, 0, 0); + die_if_kernel("Instruction fault", regs, 0, NULL); info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; - info.si_addr = (void *) regs->pc; + info.si_addr = (void __user *) regs->pc; force_sig_info(SIGILL, &info, current); } @@ -765,7 +765,7 @@ static int unauser_reg_offsets[32] = { #undef R asmlinkage void -do_entUnaUser(void * va, unsigned long opcode, +do_entUnaUser(void __user * va, unsigned long opcode, unsigned long reg, struct pt_regs *regs) { static int cnt = 0; --- linux-2.6.8-rc1/arch/alpha/Makefile 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/alpha/Makefile 2004-07-13 17:09:13.000000000 -0700 @@ -11,6 +11,7 @@ NM := $(NM) -B LDFLAGS_vmlinux := -static -N #-relax +CHECK := $(CHECK) -D__alpha__=1 cflags-y := -pipe -mno-fp-regs -ffixed-8 # Determine if we can use the BWX instructions with GAS. --- linux-2.6.8-rc1/arch/alpha/mm/fault.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/alpha/mm/fault.c 2004-07-13 17:09:13.000000000 -0700 @@ -211,7 +211,7 @@ do_page_fault(unsigned long address, uns info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; force_sig_info(SIGBUS, &info, current); if (!user_mode(regs)) goto no_context; @@ -221,7 +221,7 @@ do_page_fault(unsigned long address, uns info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = si_code; - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; force_sig_info(SIGSEGV, &info, current); return; --- linux-2.6.8-rc1/arch/arm/mach-s3c2410/mach-vr1000.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/arm/mach-s3c2410/mach-vr1000.c 2004-07-13 17:09:13.000000000 -0700 @@ -1,15 +1,17 @@ /* linux/arch/arm/mach-s3c2410/mach-vr1000.c * - * Copyright (c) 2003 Simtec Electronics + * Copyright (c) 2003,2004 Simtec Electronics * Ben Dooks * - * http://www.simtec.co.uk/ + * Machine support for Thorcom VR1000 board. Designed for Thorcom by + * Simtec Electronics, http://www.simtec.co.uk/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Modifications: + * 12-Jul-2004 BJD Renamed machine * 16-May-2003 BJD Created initial version * 16-Aug-2003 BJD Fixed header files and copyright, added URL * 05-Sep-2003 BJD Moved to v2.6 kernel @@ -160,7 +162,7 @@ void __init vr1000_init_time(void) s3c2401_init_time(); } -MACHINE_START(VR1000, "Simtec-VR1000") +MACHINE_START(VR1000, "Thorcom-VR1000") MAINTAINER("Ben Dooks ") BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, S3C2410_VA_UART) BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100) --- linux-2.6.8-rc1/arch/arm/mach-sa1100/collie.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/arm/mach-sa1100/collie.c 2004-07-13 17:09:13.000000000 -0700 @@ -89,7 +89,7 @@ static struct platform_device *devices[] &locomo_device, }; -static int __init collie_init(void) +static void __init collie_init(void) { int ret = 0; @@ -120,14 +120,9 @@ static int __init collie_init(void) ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) { printk(KERN_WARNING "collie: Unable to register LoCoMo device\n"); - return ret; } - - return ret; } -arch_initcall(collie_init); - static struct map_desc collie_io_desc[] __initdata = { /* virtual physical length type */ {0xe8000000, 0x00000000, 0x02000000, MT_DEVICE}, /* 32M main flash (cs0) */ @@ -145,4 +140,5 @@ MACHINE_START(COLLIE, "Sharp-Collie") BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) MAPIO(collie_map_io) INITIRQ(sa1100_init_irq) + INIT_MACHINE(collie_init) MACHINE_END --- linux-2.6.8-rc1/arch/i386/Kconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/Kconfig 2004-07-13 17:09:34.000000000 -0700 @@ -865,6 +865,8 @@ config REGPARM generate incorrect output with certain kernel constructs when -mregparm=3 is used. +source "drivers/perfctr/Kconfig" + endmenu @@ -1275,12 +1277,194 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help If you say Y here, various routines which may sleep will become very noisy if they are called with a spinlock held. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config FRAME_POINTER bool "Compile the kernel with frame pointers" help @@ -1308,6 +1492,14 @@ config X86_MPPARSE depends on X86_LOCAL_APIC && !X86_VISWS default y +config TRAP_BAD_SYSCALL_EXITS + bool "Debug bad system call exits" + depends on KGDB + help + If you say Y here the kernel will check for system calls which + return without clearing preempt. + default n + endmenu source "security/Kconfig" --- linux-2.6.8-rc1/arch/i386/kernel/apm.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/apm.c 2004-07-13 17:09:52.000000000 -0700 @@ -601,8 +601,8 @@ static u8 apm_bios_call(u32 func, u32 eb cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -610,7 +610,7 @@ static u8 apm_bios_call(u32 func, u32 eb apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); @@ -644,8 +644,8 @@ static u8 apm_bios_call_simple(u32 func, cpus = apm_save_cpus(); cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; local_save_flags(flags); APM_DO_CLI; @@ -653,7 +653,7 @@ static u8 apm_bios_call_simple(u32 func, error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; local_irq_restore(flags); - cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40; + __get_cpu_var(cpu_gdt_table)[0x40 / 8] = save_desc_40; put_cpu(); apm_restore_cpus(cpus); return error; @@ -2292,35 +2292,35 @@ static int __init apm_init(void) apm_bios_entry.segment = APM_CS; for (i = 0; i < NR_CPUS; i++) { - set_base(cpu_gdt_table[i][APM_CS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(cpu_gdt_table[i][APM_CS_16 >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(cpu_gdt_table[i][APM_DS >> 3], + set_base(per_cpu(cpu_gdt_table, i)[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], 64 * 1024 - 1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], 64 * 1024 - 1); #ifndef APM_RELAX_SEGMENTS } else { - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], (apm_info.bios.cseg_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], (apm_info.bios.cseg_16_len - 1) & 0xffff); - _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); /* workaround for broken BIOSes */ if (apm_info.bios.cseg_len <= apm_info.bios.offset) - _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 -1); + _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 -1); if (apm_info.bios.dseg_len <= 0x40) { /* 0x40 * 4kB == 64kB */ /* for the BIOS that assumes granularity = 1 */ - cpu_gdt_table[i][APM_DS >> 3].b |= 0x800000; + per_cpu(cpu_gdt_table, i)[APM_DS >> 3].b |= 0x800000; printk(KERN_NOTICE "apm: we set the granularity of dseg.\n"); } } --- linux-2.6.8-rc1/arch/i386/kernel/cpu/common.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/cpu/common.c 2004-07-13 17:09:52.000000000 -0700 @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,8 @@ #include "cpu.h" +DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]); + static int cachesize_override __initdata = -1; static int disable_x86_fxsr __initdata = 0; static int disable_x86_serial_nr __initdata = 1; @@ -501,7 +504,7 @@ void __init early_cpu_init(void) void __init cpu_init (void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); struct thread_struct *thread = ¤t->thread; if (test_and_set_bit(cpu, &cpu_initialized)) { @@ -523,15 +526,17 @@ void __init cpu_init (void) * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ - if (cpu) { - memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); - cpu_gdt_descr[cpu].size = GDT_SIZE - 1; - cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; - } + memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table, + GDT_SIZE); + cpu_gdt_descr[cpu].size = GDT_SIZE - 1; + cpu_gdt_descr[cpu].address = + (unsigned long)&per_cpu(cpu_gdt_table, cpu); + /* * Set up the per-thread TLS descriptor cache: */ - memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); + memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), + GDT_ENTRY_TLS_ENTRIES * 8); __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0" : : "m" (idt_descr)); @@ -552,13 +557,13 @@ void __init cpu_init (void) load_esp0(t, thread); set_tss_desc(cpu,t); - cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + per_cpu(cpu_gdt_table,cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); load_LDT(&init_mm.context); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); - cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff; /* Clear %fs and %gs. */ asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,468 @@ +/* + * (C) 2004 Sebastian Witt + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NFORCE2_XTAL 25 +#define NFORCE2_BOOTFSB 0x48 +#define NFORCE2_PLLENABLE 0xa8 +#define NFORCE2_PLLREG 0xa4 +#define NFORCE2_PLLADR 0xa0 +#define NFORCE2_PLL(mul, div) (0x100000 | (mul << 8) | div) + +#define NFORCE2_MIN_FSB 50 +#define NFORCE2_MAX_FSB 300 +#define NFORCE2_SAFE_DISTANCE 50 + +/* Delay in ms between FSB changes */ +//#define NFORCE2_DELAY 10 + +/* nforce2_chipset: + * FSB is changed using the chipset + */ +static struct pci_dev *nforce2_chipset_dev; + +/* fid: + * multiplier * 10 + */ +static int fid = 0; + +/* min_fsb, max_fsb: + * maximum and minimum available FSB + */ +static int min_fsb = 0; +static int max_fsb = 0; + +MODULE_AUTHOR("Sebastian Witt "); +MODULE_DESCRIPTION("nForce2 FSB changing cpufreq driver"); +MODULE_LICENSE("GPL"); + +module_param(fid, int, 0444); +module_param(min_fsb, int, 0444); +module_param(max_fsb, int, 0444); + +MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); +MODULE_PARM_DESC(min_fsb, + "Minimum FSB to use, if not defined: current FSB - 50"); +MODULE_PARM_DESC(max_fsb, "Maximum FSB to use, if not defined: current FSB"); + +/* DEBUG + * Define it if you want verbose debug output, e.g. for bug reporting + */ +#define NFORCE2_DEBUG + +#ifdef NFORCE2_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +/* + * nforce2_calc_fsb - calculate FSB + * @pll: PLL value + * + * Calculates FSB from PLL value + */ +static int nforce2_calc_fsb(int pll) +{ + unsigned char mul, div; + + mul = (pll >> 8) & 0xff; + div = pll & 0xff; + + if (div > 0) + return NFORCE2_XTAL * mul / div; + + return 0; +} + +/* + * nforce2_calc_pll - calculate PLL value + * @fsb: FSB + * + * Calculate PLL value for given FSB + */ +static int nforce2_calc_pll(unsigned int fsb) +{ + unsigned char xmul, xdiv; + unsigned char mul = 0, div = 0; + int tried = 0; + + /* Try to calculate multiplier and divider up to 4 times */ + while (((mul == 0) || (div == 0)) && (tried <= 3)) { + for (xdiv = 1; xdiv <= 0x80; xdiv++) + for (xmul = 1; xmul <= 0xfe; xmul++) + if (nforce2_calc_fsb(NFORCE2_PLL(xmul, xdiv)) == + fsb + tried) { + mul = xmul; + div = xdiv; + } + tried++; + } + + if ((mul == 0) || (div == 0)) + return -1; + + return NFORCE2_PLL(mul, div); +} + +/* + * nforce2_write_pll - write PLL value to chipset + * @pll: PLL value + * + * Writes new FSB PLL value to chipset + */ +static void nforce2_write_pll(int pll) +{ + int temp; + + /* Set the pll addr. to 0x00 */ + temp = 0x00; + pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, temp); + + /* Now write the value in all 64 registers */ + for (temp = 0; temp <= 0x3f; temp++) { + pci_write_config_dword(nforce2_chipset_dev, + NFORCE2_PLLREG, pll); + } + + return; +} + +/* + * nforce2_fsb_read - Read FSB + * + * Read FSB from chipset + */ +static unsigned int nforce2_fsb_read(void) +{ + struct pci_dev *nforce2_sub5; + u32 fsb, temp = 0; + + /* PLL reg. already set? */ + pci_read_config_byte(nforce2_chipset_dev, + NFORCE2_PLLENABLE, (u8 *)&temp); + + if (!temp) { + /* Get chipset boot FSB from subdevice 5 */ + nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, + 0x01EF, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + + if (!nforce2_sub5) + return 0; + + pci_read_config_dword(nforce2_sub5, NFORCE2_BOOTFSB, &fsb); + fsb = fsb / 1000000; + } else { + /* Use PLL reg. value */ + pci_read_config_dword(nforce2_chipset_dev, + NFORCE2_PLLREG, &temp); + fsb = nforce2_calc_fsb(temp); + } + + return fsb; +} + +/* + * nforce2_set_fsb - set new FSB + * @fsb: New FSB + * + * Sets new FSB + */ +int nforce2_set_fsb(unsigned int fsb) +{ + u32 pll, temp = 0; + unsigned int tfsb; + int diff; + + if ((fsb > NFORCE2_MAX_FSB) || (fsb < NFORCE2_MIN_FSB)) { + printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb); + return -EINVAL; + } + + tfsb = nforce2_fsb_read(); + if (!tfsb) { + printk(KERN_ERR "cpufreq: Error while reading the FSB\n"); + return -EINVAL; + } + + /* First write? Then set actual value */ + pci_read_config_byte(nforce2_chipset_dev, + NFORCE2_PLLENABLE, (u8 *)&temp); + if (!temp) { + pll = nforce2_calc_pll(tfsb); + + if (pll < 0) + return -EINVAL; + + nforce2_write_pll(pll); + } + + /* Enable write access */ + temp = 0x01; + pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp); + + diff = tfsb - fsb; + + if (!diff) + return 0; + + while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) { + if (diff < 0) + tfsb++; + else + tfsb--; + + /* Calculate the PLL reg. value */ + if ((pll = nforce2_calc_pll(tfsb)) == -1) + return -EINVAL; + + nforce2_write_pll(pll); +#ifdef NFORCE2_DELAY + mdelay(NFORCE2_DELAY); +#endif + } + + temp = 0x40; + pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp); + + return 0; +} + +/** + * nforce2_get - get the CPU frequency + * @cpu: CPU number + * + * Returns the CPU frequency + */ +static unsigned int nforce2_get(unsigned int cpu) +{ + if (cpu) + return 0; + return nforce2_fsb_read() * fid * 100; +} + +/** + * nforce2_target - set a new CPUFreq policy + * @policy: new policy + * @target_freq: the target frequency + * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) + * + * Sets a new CPUFreq policy. + */ +static int nforce2_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ +// unsigned long flags; + struct cpufreq_freqs freqs; + unsigned int target_fsb; + + if ((target_freq > policy->max) || (target_freq < policy->min)) + return -EINVAL; + + target_fsb = target_freq / (fid * 100); + + freqs.old = nforce2_get(policy->cpu); + freqs.new = target_fsb * fid * 100; + freqs.cpu = 0; /* Only one CPU on nForce2 plattforms */ + + if (freqs.old == freqs.new) + return 0; + + printk(KERN_INFO "cpufreq: Old CPU frequency %d kHz, new %d kHz\n", + freqs.old, freqs.new); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Disable IRQs */ + //local_irq_save(flags); + + if (nforce2_set_fsb(target_fsb) < 0) + printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n", + target_fsb); + else + printk(KERN_INFO "cpufreq: Changed FSB successfully to %d\n", + target_fsb); + + /* Enable IRQs */ + //local_irq_restore(flags); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +/** + * nforce2_verify - verifies a new CPUFreq policy + * @policy: new policy + */ +static int nforce2_verify(struct cpufreq_policy *policy) +{ + unsigned int fsb_pol_max; + + fsb_pol_max = policy->max / (fid * 100); + + if (policy->min < (fsb_pol_max * fid * 100)) + policy->max = (fsb_pol_max + 1) * fid * 100; + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static int nforce2_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int fsb; + unsigned int rfid; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + fsb = nforce2_fsb_read(); + + if (!fsb) + return -EIO; + + /* FIX: Get FID from CPU */ + if (!fid) { + if (!cpu_khz) { + printk(KERN_WARNING + "cpufreq: cpu_khz not set, can't calculate multiplier!\n"); + return -ENODEV; + } + + fid = cpu_khz / (fsb * 100); + rfid = fid % 5; + + if (rfid) { + if (rfid > 2) + fid += 5 - rfid; + else + fid -= rfid; + } + } + + printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb, + fid / 10, fid % 10); + + if (!max_fsb) + max_fsb = fsb; + if (!min_fsb) + min_fsb = max_fsb - NFORCE2_SAFE_DISTANCE; + + if (max_fsb > NFORCE2_MAX_FSB) + max_fsb = NFORCE2_MAX_FSB; + if (min_fsb < NFORCE2_MIN_FSB) + min_fsb = NFORCE2_MIN_FSB; + + if (max_fsb > fsb) + printk(KERN_WARNING + "cpufreq: Warning! Overclocking the FSB from %d to %d can cause unstability and data loss!\n", + fsb, max_fsb); + + /* cpuinfo and default policy values */ + policy->cpuinfo.min_freq = min_fsb * fid * 100; + policy->cpuinfo.max_freq = max_fsb * fid * 100; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = nforce2_get(policy->cpu); + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + return 0; +} + +static int nforce2_cpu_exit(struct cpufreq_policy *policy) +{ + return 0; +} + +static struct cpufreq_driver nforce2_driver = { + .name = "nforce2", + .verify = nforce2_verify, + .target = nforce2_target, + .get = nforce2_get, + .init = nforce2_cpu_init, + .exit = nforce2_cpu_exit, + .owner = THIS_MODULE, +}; + +/** + * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic + * + * Detects nForce2 A2 and C1 stepping + * + */ +static unsigned int nforce2_detect_chipset(void) +{ + u8 revision; + + nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, + PCI_DEVICE_ID_NVIDIA_NFORCE2, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + + if (nforce2_chipset_dev == NULL) + return -ENODEV; + + pci_read_config_byte(nforce2_chipset_dev, PCI_REVISION_ID, &revision); + + printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n", + revision); + printk(KERN_INFO + "cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n"); + + return 0; +} + +/** + * nforce2_init - initializes the nForce2 CPUFreq driver + * + * Initializes the nForce2 FSB support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init nforce2_init(void) +{ + /* TODO: do we need to detect the processor? */ + + /* detect chipset */ + if (nforce2_detect_chipset()) { + printk(KERN_ERR "cpufreq: No nForce2 chipset.\n"); + return -ENODEV; + } + + return cpufreq_register_driver(&nforce2_driver); +} + +/** + * nforce2_exit - unregisters cpufreq module + * + * Unregisters nForce2 FSB change support. + */ +static void __exit nforce2_exit(void) +{ + cpufreq_unregister_driver(&nforce2_driver); +} + +module_init(nforce2_init); +module_exit(nforce2_exit); + --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-05-09 21:07:22.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/Kconfig 2004-07-13 17:09:44.000000000 -0700 @@ -88,6 +88,11 @@ config X86_POWERNOW_K7 If in doubt, say N. +config X86_POWERNOW_K7_ACPI + bool + depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y")) + default y + config X86_POWERNOW_K8 tristate "AMD Opteron/Athlon64 PowerNow!" depends on CPU_FREQ && EXPERIMENTAL @@ -98,6 +103,11 @@ config X86_POWERNOW_K8 If in doubt, say N. +config X86_POWERNOW_K8_ACPI + bool + depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y")) + default y + config X86_GX_SUSPMOD tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" depends on CPU_FREQ @@ -186,6 +196,17 @@ config X86_SPEEDSTEP_RELAXED_CAP_CHECK option let's the probing code bypass some of those checks if the parameter "relaxed_check=1" is passed to the module. +config X86_CPUFREQ_NFORCE2 + tristate "nVidia nForce2 FSB changing" + depends on CPU_FREQ && EXPERIMENTAL + help + This adds the CPUFreq driver for FSB changing on nVidia nForce2 + plattforms. + + For details, take a look at . + + If in doubt, say N. + config X86_LONGRUN tristate "Transmeta LongRun" depends on CPU_FREQ --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/longrun.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/longrun.c 2004-07-13 17:09:21.000000000 -0700 @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include @@ -19,7 +19,7 @@ static struct cpufreq_driver longrun_driver; /** - * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz + * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz * values into per cent values. In TMTA microcode, the following is valid: * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) */ @@ -42,18 +42,18 @@ static void __init longrun_get_policy(st policy->policy = CPUFREQ_POLICY_PERFORMANCE; else policy->policy = CPUFREQ_POLICY_POWERSAVE; - + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); msr_lo &= 0x0000007F; msr_hi &= 0x0000007F; - + if ( longrun_high_freq <= longrun_low_freq ) { /* Assume degenerate Longrun table */ policy->min = policy->max = longrun_high_freq; } else { - policy->min = longrun_low_freq + msr_lo * + policy->min = longrun_low_freq + msr_lo * ((longrun_high_freq - longrun_low_freq) / 100); - policy->max = longrun_low_freq + msr_hi * + policy->max = longrun_low_freq + msr_hi * ((longrun_high_freq - longrun_low_freq) / 100); } policy->cpu = 0; @@ -79,9 +79,9 @@ static int longrun_set_policy(struct cpu /* Assume degenerate Longrun table */ pctg_lo = pctg_hi = 100; } else { - pctg_lo = (policy->min - longrun_low_freq) / + pctg_lo = (policy->min - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); - pctg_hi = (policy->max - longrun_low_freq) / + pctg_hi = (policy->max - longrun_low_freq) / ((longrun_high_freq - longrun_low_freq) / 100); } @@ -118,7 +118,7 @@ static int longrun_set_policy(struct cpu * longrun_verify_poliy - verifies a new CPUFreq policy * @policy: the policy to verify * - * Validates a new CPUFreq policy. This function has to be called with + * Validates a new CPUFreq policy. This function has to be called with * cpufreq_driver locked. */ static int longrun_verify_policy(struct cpufreq_policy *policy) @@ -127,8 +127,8 @@ static int longrun_verify_policy(struct return -EINVAL; policy->cpu = 0; - cpufreq_verify_within_limits(policy, - policy->cpuinfo.min_freq, + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && @@ -160,7 +160,7 @@ static unsigned int longrun_get(unsigned * TMTA rules: * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) */ -static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, +static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, unsigned int *high_freq) { u32 msr_lo, msr_hi; @@ -174,9 +174,9 @@ static unsigned int __init longrun_deter if (cpu_has(c, X86_FEATURE_LRTI)) { /* if the LongRun Table Interface is present, the - * detection is a bit easier: + * detection is a bit easier: * For minimum frequency, read out the maximum - * level (msr_hi), write that into "currently + * level (msr_hi), write that into "currently * selected level", and read out the frequency. * For maximum frequency, read out level zero. */ @@ -223,7 +223,7 @@ static unsigned int __init longrun_deter cpuid(0x80860007, &eax, &ebx, &ecx, &edx); /* restore values */ - wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); + wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); } /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) @@ -237,7 +237,7 @@ static unsigned int __init longrun_deter if ((ecx > 95) || (ecx == 0) || (eax < ebx)) return -EIO; - edx = (eax - ebx) / (100 - ecx); + edx = (eax - ebx) / (100 - ecx); *low_freq = edx * 1000; /* back to kHz */ if (*low_freq > *high_freq) @@ -249,7 +249,7 @@ static unsigned int __init longrun_deter static int __init longrun_cpu_init(struct cpufreq_policy *policy) { - int result = 0; + int result = 0; /* capability check */ if (policy->cpu != 0) @@ -265,15 +265,15 @@ static int __init longrun_cpu_init(struc policy->cpuinfo.max_freq = longrun_high_freq; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; longrun_get_policy(policy); - + return 0; } static struct cpufreq_driver longrun_driver = { .flags = CPUFREQ_CONST_LOOPS, - .verify = longrun_verify_policy, - .setpolicy = longrun_set_policy, + .verify = longrun_verify_policy, + .setpolicy = longrun_set_policy, .get = longrun_get, .init = longrun_cpu_init, .name = "longrun", @@ -290,7 +290,7 @@ static int __init longrun_init(void) { struct cpuinfo_x86 *c = cpu_data; - if (c->x86_vendor != X86_VENDOR_TRANSMETA || + if (c->x86_vendor != X86_VENDOR_TRANSMETA || !cpu_has(c, X86_FEATURE_LONGRUN)) return -ENODEV; --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/Makefile 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/Makefile 2004-07-13 17:09:44.000000000 -0700 @@ -11,6 +11,7 @@ obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speed obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o ifdef CONFIG_X86_ACPI_CPUFREQ ifdef CONFIG_ACPI_DEBUG --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/powernow-k7.c 2004-07-13 17:09:21.000000000 -0700 @@ -6,8 +6,6 @@ * Licensed under the terms of the GNU GPL License version 2. * Based upon datasheets & sample CPUs kindly provided by AMD. * - * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* - * * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt. * - We cli/sti on stepping A0 CPUs around the FID/VID transition. * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect. @@ -29,21 +27,13 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI #include #include #endif #include "powernow-k7.h" -#define DEBUG - -#ifdef DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif - #define PFX "powernow: " @@ -64,7 +54,7 @@ struct pst_s { u8 numpstates; }; -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI union powernow_acpi_control_t { struct { unsigned long fid:5, @@ -97,6 +87,7 @@ static int fid_codes[32] = { */ static int acpi_force; +static int debug; static struct cpufreq_frequency_table *powernow_table; @@ -109,6 +100,21 @@ static unsigned int fsb; static unsigned int latency; static char have_a0; +static void dprintk(const char *fmt, ...) +{ + char s[256]; + va_list args; + + if (debug==0) + return; + + va_start(args,fmt); + vsprintf(s, fmt, args); + printk(s); + va_end(args); +} + + static int check_fsb(unsigned int fsbspeed) { int delta; @@ -190,13 +196,13 @@ static int get_ranges (unsigned char *ps speed = powernow_table[j].frequency; if ((fid_codes[fid] % 10)==5) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (have_a0 == 1) powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; #endif } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); if (speed < minimum_speed) @@ -285,7 +291,7 @@ static void change_speed (unsigned int i change_VID(vid); change_FID(fid); } - + if (have_a0 == 1) local_irq_enable(); @@ -294,7 +300,7 @@ static void change_speed (unsigned int i } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI struct acpi_processor_performance *acpi_processor_perf; @@ -377,7 +383,7 @@ static int powernow_acpi_init(void) powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; } - dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid, fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000); dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, mobile_vid_table[vid]%1000); @@ -467,9 +473,9 @@ static int powernow_decode_bios (int max (maxfid==pst->maxfid) && (startvid==pst->startvid)) { dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); - dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); - dprintk ("fsb: %d\t", pst->fsbspeed); - dprintk ("maxFID: 0x%x\t", pst->maxfid); + dprintk (KERN_INFO PFX " cpuid: 0x%x ", pst->cpuid); + dprintk ("fsb: %d ", pst->fsbspeed); + dprintk ("maxFID: 0x%x ", pst->maxfid); dprintk ("startvid: 0x%x\n", pst->startvid); ret = get_ranges ((char *) pst + sizeof (struct pst_s)); @@ -591,14 +597,14 @@ static int __init powernow_cpu_init (str rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); /* A K7 with powernow technology is set to max frequency by BIOS */ - fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID]; if (!fsb) { printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); - if (dmi_check_system(powernow_dmi_table) || acpi_force) { + if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); result = powernow_acpi_init(); } else { @@ -648,14 +654,14 @@ static struct freq_attr* powernow_table_ }; static struct cpufreq_driver powernow_driver = { - .verify = powernow_verify, - .target = powernow_target, - .get = powernow_get, - .init = powernow_cpu_init, - .exit = powernow_cpu_exit, - .name = "powernow-k7", - .owner = THIS_MODULE, - .attr = powernow_table_attr, + .verify = powernow_verify, + .target = powernow_target, + .get = powernow_get, + .init = powernow_cpu_init, + .exit = powernow_cpu_exit, + .name = "powernow-k7", + .owner = THIS_MODULE, + .attr = powernow_table_attr, }; static int __init powernow_init (void) @@ -668,7 +674,7 @@ static int __init powernow_init (void) static void __exit powernow_exit (void) { -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K7_ACPI if (acpi_processor_perf) { acpi_processor_unregister_performance(acpi_processor_perf, 0); kfree(acpi_processor_perf); @@ -679,8 +685,10 @@ static void __exit powernow_exit (void) kfree(powernow_table); } +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "enable debug output."); module_param(acpi_force, int, 0444); -MODULE_PARM_DESC(acpi_force, "Force ACPI to be used"); +MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); MODULE_AUTHOR ("Dave Jones "); MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2004-07-13 17:09:21.000000000 -0700 @@ -32,7 +32,7 @@ #include #include -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI #include #include #endif @@ -664,7 +664,7 @@ static int find_psb_table(struct powerno return -ENODEV; } -#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) +#ifdef CONFIG_X86_POWERNOW_K8_ACPI static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { if (!data->acpi_data.state_count) @@ -1024,7 +1024,7 @@ err_out: return -ENODEV; } -static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) +static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) { struct powernow_k8_data *data = powernow_data[pol->cpu]; @@ -1076,7 +1076,7 @@ static struct cpufreq_driver cpufreq_amd .verify = powernowk8_verify, .target = powernowk8_target, .init = powernowk8_cpu_init, - .exit = powernowk8_cpu_exit, + .exit = __devexit_p(powernowk8_cpu_exit), .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, --- linux-2.6.8-rc1/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2004-07-13 17:09:21.000000000 -0700 @@ -60,6 +60,13 @@ static const struct cpu_id cpu_id_dothan .x86_mask = 1, }; +static const struct cpu_id cpu_id_dothan_b0 = { + .x86_vendor = X86_VENDOR_INTEL, + .x86 = 6, + .x86_model = 13, + .x86_mask = 6, +}; + struct cpu_model { const struct cpu_id *cpu_id; @@ -214,7 +221,7 @@ static struct cpu_model models[] = BANIAS(1500), BANIAS(1600), BANIAS(1700), - { 0, } + { NULL, } }; #undef _BANIAS #undef BANIAS @@ -400,7 +407,8 @@ static int centrino_cpu_init(struct cpuf return -ENODEV; if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) && - (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) { + (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1)) && + (centrino_verify_cpu_id(cpu, &cpu_id_dothan_b0))) { printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " "send /proc/cpuinfo to " MAINTAINER "\n"); return -ENODEV; --- linux-2.6.8-rc1/arch/i386/kernel/entry.S 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/entry.S 2004-07-13 17:09:34.000000000 -0700 @@ -48,6 +48,18 @@ #include #include #include "irq_vectors.h" + /* We do not recover from a stack overflow, but at least + * we know it happened and should be able to track it down. + */ +#ifdef CONFIG_STACK_OVERFLOW_TEST +#define STACK_OVERFLOW_TEST \ + testl $(THREAD_SIZE - 512),%esp; \ + jnz 10f; \ + call stack_overflow; \ +10: +#else +#define STACK_OVERFLOW_TEST +#endif #define nr_syscalls ((syscall_table_size)/4) @@ -94,7 +106,8 @@ VM_MASK = 0x00020000 pushl %ebx; \ movl $(__USER_DS), %edx; \ movl %edx, %ds; \ - movl %edx, %es; + movl %edx, %es; \ + STACK_OVERFLOW_TEST #define RESTORE_INT_REGS \ popl %ebx; \ @@ -232,6 +245,7 @@ need_resched: # sysenter call handler stub ENTRY(sysenter_entry) movl TSS_sysenter_esp0(%esp),%esp + .globl sysenter_past_esp sysenter_past_esp: sti pushl $(__USER_DS) @@ -294,6 +308,19 @@ syscall_exit: testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work restore_all: +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al + testl $(VM_MASK | 3), %eax + jz resume_kernelX # returning to kernel or vm86-space + + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jz resume_kernelX + + int $3 + +resume_kernelX: +#endif RESTORE_ALL # perform work that needs to be done immediately before resumption @@ -348,7 +375,7 @@ syscall_trace_entry: # perform syscall exit tracing ALIGN syscall_exit_work: - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl + testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl jz work_pending sti # could let do_syscall_trace() call # schedule() instead @@ -406,6 +433,16 @@ ENTRY(name) \ /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PERFCTR) +ENTRY(perfctr_interrupt) + pushl $LOCAL_PERFCTR_VECTOR-256 + SAVE_ALL + pushl %esp + call smp_perfctr_interrupt + addl $4, %esp + jmp ret_from_intr +#endif + ENTRY(divide_error) pushl $0 # no error code pushl $do_divide_error @@ -886,5 +923,11 @@ ENTRY(sys_call_table) .long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ + .long sys_perfctr_info + .long sys_vperfctr_open + .long sys_vperfctr_control + .long sys_vperfctr_unlink + .long sys_vperfctr_iresume + .long sys_vperfctr_read syscall_table_size=(.-sys_call_table) --- linux-2.6.8-rc1/arch/i386/kernel/head.S 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/head.S 2004-07-13 17:09:52.000000000 -0700 @@ -521,6 +521,3 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ -#ifdef CONFIG_SMP - .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ -#endif --- linux-2.6.8-rc1/arch/i386/kernel/i8259.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/i8259.c 2004-07-13 17:09:34.000000000 -0700 @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -320,11 +321,11 @@ void init_8259A(int auto_eoi) static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) { - extern void math_error(void *); + extern void math_error(void __user *); outb(0,0xF0); if (ignore_fpu_irq || !boot_cpu_data.hard_math) return IRQ_NONE; - math_error((void *)regs->eip); + math_error((void __user *)regs->eip); return IRQ_HANDLED; } @@ -427,6 +428,8 @@ void __init init_IRQ(void) */ intr_init_hook(); + perfctr_vector_init(); + /* * Set the clock to HZ Hz, we already have a valid * vector now: --- linux-2.6.8-rc1/arch/i386/kernel/init_task.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/init_task.c 2004-07-13 17:09:52.000000000 -0700 @@ -40,10 +40,7 @@ EXPORT_SYMBOL(init_task); /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, - * no more per-task TSS's. The TSS size is kept cacheline-aligned - * so they are allowed to end up in the .data.cacheline_aligned - * section. Since TSS's are completely CPU-local, we want them - * on exact cacheline boundaries, to eliminate cacheline ping-pong. + * no more per-task TSS's. */ -struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS }; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; --- linux-2.6.8-rc1/arch/i386/kernel/ioport.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/i386/kernel/ioport.c 2004-07-13 17:09:52.000000000 -0700 @@ -83,7 +83,7 @@ asmlinkage long sys_ioperm(unsigned long * do it in the per-thread copy and in the TSS ... */ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); if (tss->io_bitmap_base == IO_BITMAP_OFFSET) { /* already active? */ set_bitmap(tss->io_bitmap, from, num, !turn_on); } else { --- linux-2.6.8-rc1/arch/i386/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/irq.c 2004-07-13 17:09:26.000000000 -0700 @@ -569,6 +569,8 @@ out: irq_exit(); + kgdb_process_breakpoint(); + return 1; } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/i386/kernel/kgdb_stub.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,2454 @@ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 400 + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES 64 +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + */ +enum regnames { _EAX, /* 0 */ + _ECX, /* 1 */ + _EDX, /* 2 */ + _EBX, /* 3 */ + _ESP, /* 4 */ + _EBP, /* 5 */ + _ESI, /* 6 */ + _EDI, /* 7 */ + _PC /* 8 also known as eip */ , + _PS /* 9 also known as eflags */ , + _CS, /* 10 */ + _SS, /* 11 */ + _DS, /* 12 */ + _ES, /* 13 */ + _FS, /* 14 */ + _GS /* 15 */ +}; + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_tsc; + int errcode; + int vector; + int print_debug_info; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define LOOKASIDE_SIZE 200 /* should be more than enough */ +#define MALLOC_MAX 200 /* Max malloc size */ +struct { + unsigned int esp; + int array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +static int trap_cpu; +static unsigned int OLD_esp; + +#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + return tty_getDebugChar(); + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +__asm__("fn_rtn_stub:\n\t" + "movl %eax,%esp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addl $-4,%ebx\n\t" + "movl (%ebx), %eax\n\t" + "pushl %eax\n\t" + "cmpl %esp,%ecx\n\t" + "jne 1b\n\t" + "popl %eax\n\t" + "popl %ebx\n\t" + "popl %ecx\n\t" + "iret \n\t"); +/* *INDENT-ON* */ +#define gdb_i386vector kgdb_info.vector +#define gdb_i386errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(®s);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("EAX=%08lx ", regs->eax); + printk("EBX=%08lx ", regs->ebx); + printk("ECX=%08lx ", regs->ecx); + printk("EDX=%08lx ", regs->edx); + printk("\n"); + printk("ESI=%08lx ", regs->esi); + printk("EDI=%08lx ", regs->edi); + printk("EBP=%08lx ", regs->ebp); + printk("ESP=%08lx ", (long) ®s->esp); + printk("\n"); + printk(" DS=%08x ", regs->xds); + printk(" ES=%08x ", regs->xes); + printk(" SS=%08x ", __KERNEL_DS); + printk(" FL=%08lx ", regs->eflags); + printk("\n"); + printk(" CS=%08x ", regs->xcs); + printk(" IP=%08lx ", regs->eip); +#if 0 + printk(" FS=%08x ", regs->fs); + printk(" GS=%08x ", regs->gs); +#endif + printk("\n"); + +} /* print_regs */ + +#define NEW_esp fn_call_lookaside[trap_cpu].esp + +static void +regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_EAX] = regs->eax; + gdb_regs[_EBX] = regs->ebx; + gdb_regs[_ECX] = regs->ecx; + gdb_regs[_EDX] = regs->edx; + gdb_regs[_ESI] = regs->esi; + gdb_regs[_EDI] = regs->edi; + gdb_regs[_EBP] = regs->ebp; + gdb_regs[_DS] = regs->xds; + gdb_regs[_ES] = regs->xes; + gdb_regs[_PS] = regs->eflags; + gdb_regs[_CS] = regs->xcs; + gdb_regs[_PC] = regs->eip; + /* Note, as we are a debugging the kernel, we will always + * trap in kernel code, this means no priviledge change, + * and so the pt_regs structure is not completely valid. In a non + * privilege change trap, only EFLAGS, CS and EIP are put on the stack, + * SS and ESP are not stacked, this means that the last 2 elements of + * pt_regs is not valid (they would normally refer to the user stack) + * also, using regs+1 is no good because you end up will a value that is + * 2 longs (8) too high. This used to cause stepping over functions + * to fail, so my fix is to use the address of regs->esp, which + * should point at the end of the stack frame. Note I have ignored + * completely exceptions that cause an error code to be stacked, such + * as double fault. Stuart Hughes, Zentropix. + * original code: gdb_regs[_ESP] = (int) (regs + 1) ; + + * this is now done on entry and moved to OLD_esp (as well as NEW_esp). + */ + gdb_regs[_ESP] = NEW_esp; + gdb_regs[_SS] = __KERNEL_DS; + gdb_regs[_FS] = 0xFFFF; + gdb_regs[_GS] = 0xFFFF; +} /* regs_to_gdb_regs */ + +static void +gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs) +{ + regs->eax = gdb_regs[_EAX]; + regs->ebx = gdb_regs[_EBX]; + regs->ecx = gdb_regs[_ECX]; + regs->edx = gdb_regs[_EDX]; + regs->esi = gdb_regs[_ESI]; + regs->edi = gdb_regs[_EDI]; + regs->ebp = gdb_regs[_EBP]; + regs->xds = gdb_regs[_DS]; + regs->xes = gdb_regs[_ES]; + regs->eflags = gdb_regs[_PS]; + regs->xcs = gdb_regs[_CS]; + regs->eip = gdb_regs[_PC]; + NEW_esp = gdb_regs[_ESP]; /* keep the value */ +#if 0 /* can't change these */ + regs->esp = gdb_regs[_ESP]; + regs->xss = gdb_regs[_SS]; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif + +} /* gdb_regs_to_regs */ + +int thread_list = 0; + +void +get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs) +{ + unsigned long stack_page; + int count = 0; + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(gdb_regs, regs); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task) { + regs_to_gdb_regs(gdb_regs, + kgdb_info.cpus_waiting[i].regs); + gdb_regs[_ESP] = + (int) &kgdb_info.cpus_waiting[i].regs->esp; + + return; + } + } +#endif + memset(gdb_regs, 0, NUMREGBYTES); + gdb_regs[_ESP] = p->thread.esp; + gdb_regs[_PC] = p->thread.eip; + gdb_regs[_EBP] = *(int *) gdb_regs[_ESP]; + gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4); + gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8); + +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. This code was shamelessly purloined from process.c. It was + * then enhanced to provide more registers than simply the program + * counter. + */ + + if (!thread_list) { + return; + } + + if (p->state == TASK_RUNNING) + return; + stack_page = (unsigned long) p->thread_info; + if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > + THREAD_SIZE - sizeof(long) + stack_page) + return; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + do { + if (gdb_regs[_EBP] < stack_page || + gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page) + return; + gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4); + gdb_regs[_ESP] = gdb_regs[_EBP] + 8; + gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP]; + if (!in_sched_functions(gdb_regs[_PC])) + return; + } while (count++ < 16); + return; +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; +static volatile int mem_err_expected = 0; +static volatile int mem_err_cnt = 0; +static int garbage_loc = -1; + +int +get_char(char *addr) +{ + return *addr; +} + +void +set_char(char *addr, int val, int may_fault) +{ + /* + * This code traps references to the area mapped to the kernel + * stack as given by the regs and, instead, stores to the + * fn_call_lookaside[cpu].array + */ + if (may_fault && + (unsigned int) addr < OLD_esp && + ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { + addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); + } + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + ch = get_char(mem++); + + /* printk("%02x\n", ch & 0xFF) ; */ + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", + (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return (buf); + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + set_char(mem++, ch, may_fault); + + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } + return NULL; +} +/* *INDENT-OFF* */ +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned addr; +} breakinfo[4] = { {enabled:0}, + {enabled:0}, + {enabled:0}, + {enabled:0}}; +/* *INDENT-ON* */ +unsigned hw_breakpoint_status; +void +correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned dr7; + + asm volatile ("movl %%db7, %0\n":"=r" (dr7) + :); + /* *INDENT-OFF* */ + do { + unsigned addr0, addr1, addr2, addr3; + asm volatile ("movl %%db0, %0\n" + "movl %%db1, %1\n" + "movl %%db2, %2\n" + "movl %%db3, %3\n" + :"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3) + :); + } while (0); + /* *INDENT-ON* */ + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movl %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movl %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movl %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movl %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movl %0, %%db7\n"::"r" (dr7)); + } +} + +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + +int +in_kgdb(struct pt_regs *regs) +{ + unsigned flags; + int cpu = smp_processor_id(); + in_kgdb_called = 1; + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + return 1; + } + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + kgdb_local_irq_restore(flags); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + ack_APIC_irq(); + in_kgdb(®s); +} +#else +int +in_kgdb(struct pt_regs *regs) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + unsigned dr6; + int i; + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (dr6 & 0x4000) { + sprintf(buffer, "Single step"); + return; + } + for (i = 0; i < 4; ++i) { + if (dr6 & (1 << i)) { + sprintf(buffer, "Hardware breakpoint %d", i); + return; + } + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ +int +kgdb_handle_exception(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs) +{ + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + int addr, length; + int breakno, breaktype; + char *ptr; + int newPC; + threadref thref; + int threadid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; + int gdb_regs[NUMREGBYTES / 4]; + int dr6; + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define regs (*linux_regs) +#define NUMREGS NUMREGBYTES/4 + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) { + printk("ignoring non-kernel exception\n"); + print_regs(®s); + return (0); + } + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + + if (kgdboe) + netpoll_set_trap(1); + + kgdb_local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + rdtscll(kgdb_info.entry_tsc); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + int time = 0, end_time, dum = 0; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + rdtsc(dum, time); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + + int wait = 100000; + while (wait--) ; + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct + *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + rdtsc(dum, time); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %d cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%d, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(®s); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ +/* *INDENT-OFF* */ + __asm__("movl %0,%%db7" + : /* no output */ + :"r"(0)); + + asm volatile ("movl %%db6, %0\n" + :"=r" (hw_breakpoint_status) + :); + +/* *INDENT-ON* */ + switch (exceptionVector) { + case 0: /* divide error */ + case 1: /* debug exception */ + case 2: /* NMI */ + case 3: /* breakpoint */ + case 4: /* overflow */ + case 5: /* bounds check */ + case 6: /* invalid opcode */ + case 7: /* device not available */ + case 8: /* double fault (errcode) */ + case 10: /* invalid TSS (errcode) */ + case 12: /* stack fault (errcode) */ + case 16: /* floating point error */ + case 17: /* alignment check (errcode) */ + default: /* any undocumented */ + break; + case 11: /* segment not present (errcode) */ + case 13: /* general protection (errcode) */ + case 14: /* page fault (special errcode) */ + case 19: /* cache flush denied */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + /* make valid address */ + regs.eax = (long) &garbage_loc; + /* make valid address */ + regs.edx = (long) &garbage_loc; + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(®s); + goto exit_kgdb; + } + break; + } + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_i386vector = exceptionVector; + gdb_i386errcode = err_code; + kgdb_info.called_from = __builtin_return_address(0); +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + trap_cpu = smp_processor_id(); + OLD_esp = NEW_esp = (int) (&linux_regs->esp); + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, ®s, gdb_regs); + mem2hex((char *) gdb_regs, + remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], + (char *) gdb_regs, NUMREGBYTES, 0); + if (!usethread || usethread == current) { + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). These may have + * meaning for ptrace, but for us it is safe to + * ignor them. We do this by dumping them into + * _GS which we also ignor, but do have memory for. + */ + int regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(gdb_regs, ®s); + if ((!usethread || usethread == current) && + hexToInt(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + regno = + (regno >= NUMREGS ? _GS : regno); + hex2mem(ptr, (char *) &gdb_regs[regno], + 4, 0); + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + mem2hex((char *) addr, + remcomOutBuffer, length, 1); + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { + hex2mem(ptr, (char *) addr, length, 1); + + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + strcpy(remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%x\n", addr); + + regs.eip = addr; + } + + newPC = regs.eip; + + /* clear the trace bit */ + regs.eflags &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + regs.eflags |= 0x100; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(®s); + } + asm volatile ("movl %%db6, %0\n":"=r" (dr6) + :); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + (breakinfo[breakno].type == 0)) { + /* Set restore flag */ + regs.eflags |= 0x10000; + break; + } + } + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + asm volatile ("movl %0, %%db6\n"::"r" (0)); + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + ptr++; + hexToInt(&ptr, &breaktype); + ptr++; + hexToInt(&ptr, &length); + ptr++; + hexToInt(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + case 'r': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + /* triplefault no return from here */ + { + static long no_idt[2]; + __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); + BREAKPOINT; + } + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: + /* + * Here is where we set up to trap a gdb function call. NEW_esp + * will be changed if we are trying to do this. We handle both + * adding and subtracting, thus allowing gdb to put grung on + * the stack which it removes later. + */ + if (NEW_esp != OLD_esp) { + int *ptr = END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) + ptr -= (OLD_esp - NEW_esp) / sizeof (int); + *--ptr = linux_regs->eflags; + *--ptr = linux_regs->xcs; + *--ptr = linux_regs->eip; + *--ptr = linux_regs->ecx; + *--ptr = linux_regs->ebx; + *--ptr = linux_regs->eax; + linux_regs->ecx = NEW_esp - (sizeof (int) * 6); + linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) { + linux_regs->eip = (unsigned int) fn_call_stub; + } else { + linux_regs->eip = (unsigned int) fn_rtn_stub; + linux_regs->eax = NEW_esp; + } + linux_regs->eflags &= ~(IF_BIT | TF_BIT); + } +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + if (!(ss_hold)) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + kgdb_local_irq_restore(flags); + return (0); + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + kgdb_local_irq_restore(flags); + return (0); +} + +/* this function is used to set up exception handlers for tracing and + * breakpoints. + * This function is not needed as the above line does all that is needed. + * We leave it for backward compatitability... + */ +void +set_debug_traps(void) +{ + /* + * linux_debug_hook is defined in traps.c. We store a pointer + * to our own exception handler into it. + + * But really folks, every hear of labeled common, an old Fortran + * concept. Lots of folks can reference it and it is define if + * anyone does. Only one can initialize it at link time. We do + * this with the hook. See the statement above. No need for any + * executable code and it is ready as soon as the kernel is + * loaded. Very desirable in kernel debugging. + + linux_debug_hook = handle_exception ; + */ + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. + putDebugChar ('+'); + + initialized = 1; + */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_i386vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + int flags; + kgdb_local_irq_save(flags); + spin_lock(&ts_spin); + rdtscll(kgdb_and_then->at_time); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + kgdb_local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + BREAKPOINT; + } +} + --- linux-2.6.8-rc1/arch/i386/kernel/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/Makefile 2004-07-13 17:09:25.735360504 -0700 @@ -14,6 +14,7 @@ obj-y += timers/ obj-$(CONFIG_ACPI_BOOT) += acpi/ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o --- linux-2.6.8-rc1/arch/i386/kernel/nmi.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/nmi.c 2004-07-13 17:09:25.000000000 -0700 @@ -31,7 +31,17 @@ #include #include +#ifdef CONFIG_KGDB +#include +#ifdef CONFIG_SMP +unsigned int nmi_watchdog = NMI_IO_APIC; +#else +unsigned int nmi_watchdog = NMI_LOCAL_APIC; +#endif +#else unsigned int nmi_watchdog = NMI_NONE; +#endif + static unsigned int nmi_hz = HZ; static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ static unsigned int nmi_p4_cccr_val; @@ -458,6 +468,9 @@ void touch_nmi_watchdog (void) for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } +#ifdef CONFIG_KGDB +int tune_watchdog = 5*HZ; +#endif void nmi_watchdog_tick (struct pt_regs * regs) { @@ -471,12 +484,24 @@ void nmi_watchdog_tick (struct pt_regs * sum = irq_stat[cpu].apic_timer_irqs; +#ifdef CONFIG_KGDB + if (!in_kgdb(regs) && last_irq_sums[cpu] == sum) { + +#else if (last_irq_sums[cpu] == sum) { +#endif /* * Ayiee, looks like this CPU is stuck ... * wait a few IRQs (5 seconds) before doing the oops ... */ alert_counter[cpu]++; +#ifdef CONFIG_KGDB + if (alert_counter[cpu] == tune_watchdog) { + kgdb_handle_exception(2, SIGPWR, 0, regs); + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +#endif if (alert_counter[cpu] == 5*nmi_hz) { spin_lock(&nmi_print_lock); /* --- linux-2.6.8-rc1/arch/i386/kernel/pci-dma.c 2004-04-03 20:39:10.000000000 -0800 +++ 25/arch/i386/kernel/pci-dma.c 2004-07-13 17:09:21.000000000 -0700 @@ -13,17 +13,40 @@ #include #include +struct dma_coherent_mem { + void *virt_base; + u32 device_base; + int size; + int flags; + unsigned long *bitmap; +}; + void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int gfp) { void *ret; + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + if (mem) { + int page = bitmap_find_free_region(mem->bitmap, mem->size, + order); + if (page >= 0) { + *dma_handle = mem->device_base + (page << PAGE_SHIFT); + ret = mem->virt_base + (page << PAGE_SHIFT); + memset(ret, 0, size); + return ret; + } + if (mem->flags & DMA_MEMORY_EXCLUSIVE) + return NULL; + } + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + ret = (void *)__get_free_pages(gfp, order); if (ret != NULL) { memset(ret, 0, size); @@ -35,5 +58,89 @@ void *dma_alloc_coherent(struct device * void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages((unsigned long)vaddr, get_order(size)); + struct dma_coherent_mem *mem = dev->dma_mem; + int order = get_order(size); + + if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + + bitmap_release_region(mem->bitmap, page, order); + } else + free_pages((unsigned long)vaddr, order); +} + +int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + void *mem_base; + int pages = size >> PAGE_SHIFT; + int bitmap_size = (pages + 31)/32; + + if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) + goto out; + if (!size) + goto out; + if (dev->dma_mem) + goto out; + + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + mem_base = ioremap(bus_addr, size); + if (!mem_base) + goto out; + + dev->dma_mem = kmalloc(GFP_KERNEL, sizeof(struct dma_coherent_mem)); + if (!dev->dma_mem) + goto out; + memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem)); + dev->dma_mem->bitmap = kmalloc(GFP_KERNEL, bitmap_size); + if (!dev->dma_mem->bitmap) + goto free1_out; + memset(dev->dma_mem->bitmap, 0, bitmap_size); + + dev->dma_mem->virt_base = mem_base; + dev->dma_mem->device_base = device_addr; + dev->dma_mem->size = pages; + dev->dma_mem->flags = flags; + + if (flags & DMA_MEMORY_MAP) + return DMA_MEMORY_MAP; + + return DMA_MEMORY_IO; + + free1_out: + kfree(dev->dma_mem->bitmap); + out: + return 0; +} +EXPORT_SYMBOL(dma_declare_coherent_memory); + +void dma_release_declared_memory(struct device *dev) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + + if(!mem) + return; + dev->dma_mem = NULL; + kfree(mem->bitmap); + kfree(mem); +} +EXPORT_SYMBOL(dma_release_declared_memory); + +void *dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) +{ + struct dma_coherent_mem *mem = dev->dma_mem; + int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; + int pos, err; + + if (!mem) + return ERR_PTR(-EINVAL); + + pos = (device_addr - mem->device_base) >> PAGE_SHIFT; + err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); + if (err != 0) + return ERR_PTR(err); + return mem->virt_base + (pos << PAGE_SHIFT); } +EXPORT_SYMBOL(dma_mark_declared_memory_occupied); --- linux-2.6.8-rc1/arch/i386/kernel/process.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/process.c 2004-07-13 17:35:10.000000000 -0700 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -298,12 +299,13 @@ void exit_thread(void) /* The process may have allocated an io port bitmap... nuke it. */ if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); kfree(tsk->thread.io_bitmap_ptr); tsk->thread.io_bitmap_ptr = NULL; tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } + perfctr_exit_thread(&tsk->thread); } void flush_thread(void) @@ -353,7 +355,7 @@ int copy_thread(int nr, unsigned long cl int err; childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1; - struct_cpy(childregs, regs); + *childregs = *regs; childregs->eax = 0; childregs->esp = esp; p->set_child_tid = p->clear_child_tid = NULL; @@ -366,6 +368,8 @@ int copy_thread(int nr, unsigned long cl savesegment(fs,p->thread.fs); savesegment(gs,p->thread.gs); + perfctr_copy_thread(&p->thread); + tsk = current; if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); @@ -507,10 +511,12 @@ struct task_struct fastcall * __switch_t struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ + perfctr_suspend_thread(prev); + __unlazy_fpu(prev_p); /* @@ -573,6 +579,9 @@ struct task_struct fastcall * __switch_t */ tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; } + + perfctr_resume_thread(next); + return prev_p; } --- linux-2.6.8-rc1/arch/i386/kernel/ptrace.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/i386/kernel/ptrace.c 2004-07-13 17:09:43.000000000 -0700 @@ -147,6 +147,7 @@ void ptrace_disable(struct task_struct * { long tmp; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -370,6 +371,7 @@ asmlinkage int sys_ptrace(long request, else { clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -391,6 +393,7 @@ asmlinkage int sys_ptrace(long request, if (child->state == TASK_ZOMBIE) /* already dead */ break; child->exit_code = SIGKILL; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); @@ -411,6 +414,7 @@ asmlinkage int sys_ptrace(long request, } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + set_tsk_thread_flag(child, TIF_SINGLESTEP); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -535,14 +539,15 @@ void do_syscall_trace(struct pt_regs *re audit_syscall_exit(current, regs->eax); } - if (!test_thread_flag(TIF_SYSCALL_TRACE)) + if (!test_thread_flag(TIF_SYSCALL_TRACE) && + !test_thread_flag(TIF_SINGLESTEP)) return; if (!(current->ptrace & PT_PTRACED)) return; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && + !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do --- linux-2.6.8-rc1/arch/i386/kernel/signal.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/signal.c 2004-07-13 17:09:13.000000000 -0700 @@ -116,11 +116,14 @@ sys_sigaction(int sig, const struct old_ } asmlinkage int -sys_sigaltstack(struct pt_regs regs) +sys_sigaltstack(unsigned long ebx) { - const stack_t __user *uss = (const stack_t __user *)regs.ebx; - stack_t __user *uoss = (stack_t __user *)regs.ecx; - return do_sigaltstack(uss, uoss, regs.esp); + /* This is needed to make gcc realize it doesn't own the "struct pt_regs" */ + struct pt_regs *regs = (struct pt_regs *)&ebx; + const stack_t __user *uss = (const stack_t __user *)ebx; + stack_t __user *uoss = (stack_t __user *)regs->ecx; + + return do_sigaltstack(uss, uoss, regs->esp); } @@ -333,12 +336,13 @@ get_sigframe(struct k_sigaction *ka, str /* These symbols are defined with the addresses in the vsyscall page. See vsyscall-sigreturn.S. */ -extern void __kernel_sigreturn, __kernel_rt_sigreturn; +extern void __user __kernel_sigreturn; +extern void __user __kernel_rt_sigreturn; static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - void *restorer; + void __user *restorer; struct sigframe __user *frame; int err = 0; @@ -415,7 +419,7 @@ give_sigsegv: static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { - void *restorer; + void __user *restorer; struct rt_sigframe __user *frame; int err = 0; --- linux-2.6.8-rc1/arch/i386/kernel/smpboot.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/smpboot.c 2004-07-13 17:09:36.000000000 -0700 @@ -800,16 +800,13 @@ static int __init do_boot_cpu(int apicid idle = fork_by_hand(); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(idle); - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ + /* Make this the idle thread */ init_idle(idle, cpu); idle->thread.eip = (unsigned long) start_secondary; + /* Remove it from the pidhash */ unhash_process(idle); /* start_eip had better be page-aligned! */ --- linux-2.6.8-rc1/arch/i386/kernel/smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/smp.c 2004-07-13 17:09:52.000000000 -0700 @@ -104,7 +104,7 @@ * about nothing of note with C stepping upwards. */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0, }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, }; /* * the following functions deal with sending IPIs between CPUs. @@ -255,9 +255,9 @@ static spinlock_t tlbstate_lock = SPIN_L */ static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -324,8 +324,8 @@ asmlinkage void smp_invalidate_interrupt * BUG(); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -457,7 +457,7 @@ static void do_flush_tlb_all(void* info) unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } @@ -465,7 +465,17 @@ void flush_tlb_all(void) { on_each_cpu(do_flush_tlb_all, NULL, 1, 1); } - +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing --- linux-2.6.8-rc1/arch/i386/kernel/sysenter.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/sysenter.c 2004-07-13 17:09:52.000000000 -0700 @@ -24,7 +24,7 @@ extern asmlinkage void sysenter_entry(vo void enable_sep_cpu(void *info) { int cpu = get_cpu(); - struct tss_struct *tss = init_tss + cpu; + struct tss_struct *tss = &per_cpu(init_tss, cpu); tss->ss1 = __KERNEL_CS; tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss; --- linux-2.6.8-rc1/arch/i386/kernel/traps.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/traps.c 2004-07-13 17:09:29.000000000 -0700 @@ -102,6 +102,40 @@ static int valid_stack_ptr(struct task_s return 1; } +#ifdef CONFIG_KGDB +extern void sysenter_past_esp(void); +#include +#include +void set_intr_gate(unsigned int n, void *addr); +static void set_intr_usr_gate(unsigned int n, void *addr); +/* + * Should be able to call this breakpoint() very early in + * bring up. Just hard code the call where needed. + * The breakpoint() code is here because set_?_gate() functions + * are local (static) to trap.c. They need be done only once, + * but it does not hurt to do them over. + */ +void breakpoint(void) +{ + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); + + BREAKPOINT; +} +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ + { \ + if (!user_mode(regs) ) \ + { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) +#endif + + #ifdef CONFIG_FRAME_POINTER static void print_context_stack(struct task_struct *task, unsigned long *stack, unsigned long ebp) @@ -216,7 +250,7 @@ void show_registers(struct pt_regs *regs ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx" + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\nEFLAGS: %08lx" " (%s) \n", smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags, UTS_RELEASE); @@ -234,23 +268,25 @@ void show_registers(struct pt_regs *regs * time of the fault.. */ if (in_kernel) { + u8 *eip; printk("\nStack: "); show_stack(NULL, (unsigned long*)esp); printk("Code: "); - if(regs->eip < PAGE_OFFSET) - goto bad; - for(i=0;i<20;i++) - { + eip = (u8 *)regs->eip - 43; + for (i = 0; i < 64; i++, eip++) { unsigned char c; - if(__get_user(c, &((unsigned char*)regs->eip)[i])) { -bad: + + if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) { printk(" Bad EIP value."); break; } - printk("%02x ", c); + if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); } } printk("\n"); @@ -318,6 +354,15 @@ void die(const char * str, struct pt_reg #endif if (nl) printk("\n"); +#ifdef CONFIG_KGDB + /* This is about the only place we want to go to kgdb even if in + * user mode. But we must go in via a trap so within kgdb we will + * always be in kernel mode. + */ + if (user_mode(regs)) + BREAKPOINT; +#endif + CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); @@ -387,6 +432,7 @@ static inline void do_trap(int trapnr, i #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ } @@ -397,14 +443,16 @@ asmlinkage void do_##name(struct pt_regs info.si_signo = signr; \ info.si_errno = 0; \ info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ + info.si_addr = (void __user *)siaddr; \ do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ } #define DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ + return; \ } #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ @@ -414,7 +462,7 @@ asmlinkage void do_##name(struct pt_regs info.si_signo = signr; \ info.si_errno = 0; \ info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ + info.si_addr = (void __user *)siaddr; \ do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ } @@ -451,8 +499,10 @@ gp_in_vm86: return; gp_in_kernel: - if (!fixup_exception(regs)) + if (!fixup_exception(regs)){ + CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) die("general protection fault", regs, error_code); + } } static void mem_parity_error(unsigned char reason, struct pt_regs * regs) @@ -614,8 +664,18 @@ asmlinkage void do_debug(struct pt_regs * allowing programs to debug themselves without the ptrace() * interface. */ +#ifdef CONFIG_KGDB + /* + * I think this is the only "real" case of a TF in the kernel + * that really belongs to user space. Others are + * "Ours all ours!" + */ + if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_past_esp)) + goto clear_TF_reenable; +#else if ((regs->xcs & 3) == 0) goto clear_TF_reenable; +#endif if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -627,11 +687,22 @@ asmlinkage void do_debug(struct pt_regs info.si_errno = 0; info.si_code = TRAP_BRKPT; +#ifdef CONFIG_KGDB + /* + * If this is a kernel mode trap, we need to reset db7 to allow us + * to continue sanely ALSO skip the signal delivery + */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* if not kernel, allow ints but only if they were on */ + if ( regs->eflags & 0x200) local_irq_enable(); +#endif /* If this is a kernel mode trap, save the user PC on entry to * the kernel, that's what the debugger can make sense of. */ - info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : - (void *)regs->eip; + info.si_addr = ((regs->xcs & 3) == 0) ? (void __user *)tsk->thread.eip + : (void __user *)regs->eip; force_sig_info(SIGTRAP, &info, tsk); /* Disable additional traps. They'll be re-enabled when @@ -641,6 +712,7 @@ clear_dr7: __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); + CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) return; debug_vm86: @@ -659,7 +731,7 @@ clear_TF: * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ -void math_error(void *eip) +void math_error(void __user *eip) { struct task_struct * task; siginfo_t info; @@ -718,10 +790,10 @@ void math_error(void *eip) asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { ignore_fpu_irq = 1; - math_error((void *)regs->eip); + math_error((void __user *)regs->eip); } -void simd_math_error(void *eip) +void simd_math_error(void __user *eip) { struct task_struct * task; siginfo_t info; @@ -775,7 +847,7 @@ asmlinkage void do_simd_coprocessor_erro if (cpu_has_xmm) { /* Handle SIMD FPU exceptions on PIII+ processors. */ ignore_fpu_irq = 1; - simd_math_error((void *)regs->eip); + simd_math_error((void __user *)regs->eip); } else { /* * Handle strange cache flush from user space exception @@ -889,6 +961,12 @@ static void __init set_call_gate(void *a { _set_gate(a,12,3,addr,__KERNEL_CS); } +#ifdef CONFIG_KGDB +void set_intr_usr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); +} +#endif static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) { @@ -911,7 +989,11 @@ void __init trap_init(void) set_trap_gate(0,÷_error); set_intr_gate(1,&debug); set_intr_gate(2,&nmi); +#ifndef CONFIG_KGDB set_system_gate(3,&int3); /* int3-5 can be called from all */ +#else + set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ +#endif set_system_gate(4,&overflow); set_system_gate(5,&bounds); set_trap_gate(6,&invalid_op); --- linux-2.6.8-rc1/arch/i386/kernel/vm86.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/kernel/vm86.c 2004-07-13 17:09:52.000000000 -0700 @@ -121,7 +121,7 @@ struct pt_regs * fastcall save_v86_state do_exit(SIGSEGV); } - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; load_esp0(tss, ¤t->thread); @@ -303,7 +303,7 @@ static void do_sys_vm86(struct kernel_vm asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs)); asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs)); - tss = init_tss + get_cpu(); + tss = &per_cpu(init_tss, get_cpu()); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; --- linux-2.6.8-rc1/arch/i386/lib/dec_and_lock.c 2003-11-09 16:45:04.000000000 -0800 +++ 25/arch/i386/lib/dec_and_lock.c 2004-07-13 17:09:29.261824400 -0700 @@ -10,6 +10,7 @@ #include #include +#ifndef ATOMIC_DEC_AND_LOCK int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -38,3 +39,5 @@ slow_path: spin_unlock(lock); return 0; } +#endif + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/i386/lib/kgdb_serial.c 2004-07-13 17:09:26.095305784 -0700 @@ -0,0 +1,499 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b) outb_p(b,a) + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_p(info->port + UART_LSR); + + if (it & UART_LSR_DR) + return (inb_p(info->port + UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; + + outb_p(chr, info->port + UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_p(port + UART_IER); + outb_px(port + UART_IER, 0); + outb_px(0xff, 0x080); + scratch2 = inb_p(port + UART_IER); + outb_px(port + UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_p(port + UART_LCR); + outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(port + UART_LCR, 0); + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_p(port + UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_p(port + UART_MCR); + outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); + outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_p(port + UART_MSR) & 0xF0; + outb_px(port + UART_MCR, scratch); + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + int port = info->port; + + (void) inb_p(port + UART_RX); + outb_px(port + UART_IER, 0); + + (void) inb_p(port + UART_RX); /* serial driver comments say */ + (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ + (void) inb_p(port + UART_MSR); + outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(port + UART_MCR, info->MCR); + + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr, dum, time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + rdtsc(dum, time); + end_time = time + 2; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + rdtsc(dum, time); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + +#ifdef CONFIG_DISCONTIGMEM +static inline int kgdb_mem_init_done(void) +{ + return highmem_start_page != NULL; +} +#else +static inline int kgdb_mem_init_done(void) +{ + return max_mapnr != 0; +} +#endif + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info->port + UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +module_init(kgdb_enable_ints); --- linux-2.6.8-rc1/arch/i386/lib/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/lib/Makefile 2004-07-13 17:09:25.740359744 -0700 @@ -8,3 +8,4 @@ lib-y = checksum.o delay.o usercopy.o ge lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o --- linux-2.6.8-rc1/arch/i386/lib/usercopy.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/lib/usercopy.c 2004-07-13 17:09:51.000000000 -0700 @@ -31,6 +31,7 @@ static inline int __movsl_is_ok(unsigned #define __do_strncpy_from_user(dst,src,count,res) \ do { \ int __d0, __d1, __d2; \ + might_sleep(); \ __asm__ __volatile__( \ " testl %1,%1\n" \ " jz 2f\n" \ @@ -119,6 +120,7 @@ strncpy_from_user(char *dst, const char #define __do_clear_user(addr,size) \ do { \ int __d0; \ + might_sleep(); \ __asm__ __volatile__( \ "0: rep; stosl\n" \ " movl %2,%0\n" \ --- linux-2.6.8-rc1/arch/i386/mach-voyager/voyager_smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/mach-voyager/voyager_smp.c 2004-07-13 17:09:52.000000000 -0700 @@ -35,7 +35,7 @@ int reboot_smp = 0; /* TLB state -- visible externally, indexed physically */ -struct tlb_state cpu_tlbstate[NR_CPUS] __cacheline_aligned = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; +DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; /* CPU IRQ affinity -- set to all ones initially */ static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; @@ -591,11 +591,12 @@ do_boot_cpu(__u8 cpu) if(IS_ERR(idle)) panic("failed fork for CPU%d", cpu); - wake_up_forked_process(idle); - + /* Make this the idle thread */ init_idle(idle, cpu); idle->thread.eip = (unsigned long) start_secondary; + + /* Remove it from the pidhash */ unhash_process(idle); /* init_tasks (in sched.c) is indexed logically */ stack_start.esp = (void *) idle->thread.esp; @@ -860,9 +861,9 @@ static spinlock_t tlbstate_lock = SPIN_L static inline void leave_mm (unsigned long cpu) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) BUG(); - cpu_clear(cpu, cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask); load_cr3(swapper_pg_dir); } @@ -883,8 +884,8 @@ smp_invalidate_interrupt(void) smp_processor_id())); */ - if (flush_mm == cpu_tlbstate[cpu].active_mm) { - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { if (flush_va == FLUSH_ALL) local_flush_tlb(); else @@ -1218,7 +1219,7 @@ do_flush_tlb_all(void* info) unsigned long cpu = smp_processor_id(); __flush_tlb_all(); - if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY) leave_mm(cpu); } --- linux-2.6.8-rc1/arch/i386/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/Makefile 2004-07-13 17:09:25.000000000 -0700 @@ -99,6 +99,9 @@ core-$(CONFIG_X86_ES7000) := arch/i386/m # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default +mflags-$(CONFIG_KGDB) += -gdwarf-2 +mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g') + head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o libs-y += arch/i386/lib/ --- linux-2.6.8-rc1/arch/i386/mm/fault.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/mm/fault.c 2004-07-13 17:09:52.000000000 -0700 @@ -107,7 +107,7 @@ static inline unsigned long get_segment_ desc = (void *)desc + (seg & ~7); } else { /* Must disable preemption while reading the GDT. */ - desc = (u32 *)&cpu_gdt_table[get_cpu()]; + desc = (u32 *)&per_cpu(cpu_gdt_table, get_cpu()); desc = (void *)desc + (seg & ~7); } @@ -389,7 +389,7 @@ bad_area_nosemaphore: info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ - info.si_addr = (void *)address; + info.si_addr = (void __user *)address; force_sig_info(SIGSEGV, &info, tsk); return; } @@ -427,6 +427,12 @@ no_context: * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ +#ifdef CONFIG_KGDB + if (!user_mode(regs)){ + kgdb_handle_exception(14,SIGBUS, error_code, regs); + return; + } +#endif bust_spinlocks(1); @@ -499,7 +505,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; + info.si_addr = (void __user *)address; force_sig_info(SIGBUS, &info, tsk); return; --- linux-2.6.8-rc1/arch/i386/mm/Makefile 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/i386/mm/Makefile 2004-07-13 17:09:38.544413232 -0700 @@ -2,7 +2,7 @@ # Makefile for the linux i386-specific parts of the memory manager. # -obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o +obj-y := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o mmap.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/i386/mm/mmap.c 2004-07-13 17:09:38.000000000 -0700 @@ -0,0 +1,70 @@ +/* + * linux/arch/i386/mm/mmap.c + * + * flexible mmap layout support + * + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Started by Ingo Molnar + */ + +#include +#include + +/* + * Top of mmap area (just below the process stack). + * + * Leave an at least ~128 MB hole. + */ +#define MIN_GAP (128*1024*1024) +#define MAX_GAP (TASK_SIZE/6*5) + +static inline unsigned long mmap_base(struct mm_struct *mm) +{ + unsigned long gap = current->rlim[RLIMIT_STACK].rlim_cur; + + if (gap < MIN_GAP) + gap = MIN_GAP; + else if (gap > MAX_GAP) + gap = MAX_GAP; + + return TASK_SIZE - (gap & PAGE_MASK); +} + +/* + * This function, called very early during the creation of a new + * process VM image, sets up which VM layout function to use: + */ +void arch_pick_mmap_layout(struct mm_struct *mm) +{ + /* + * Fall back to the standard layout if the personality + * bit is set, or if the expected stack growth is unlimited: + */ + if ((current->personality & ADDR_COMPAT_LAYOUT) || + current->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) { + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; + } else { + mm->mmap_base = mmap_base(mm); + mm->get_unmapped_area = arch_get_unmapped_area_topdown; + mm->unmap_area = arch_unmap_area_topdown; + } +} --- linux-2.6.8-rc1/arch/i386/power/cpu.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/i386/power/cpu.c 2004-07-13 17:09:52.000000000 -0700 @@ -83,10 +83,10 @@ do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = init_tss + cpu; + struct tss_struct * t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ - cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); /* This does ltr */ load_LDT(¤t->active_mm->context); /* This does lldt */ --- linux-2.6.8-rc1/arch/ia64/ia32/ia32_entry.S 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/ia32/ia32_entry.S 2004-07-13 17:09:13.000000000 -0700 @@ -32,7 +32,7 @@ ENTRY(ia32_execve) END(ia32_execve) ENTRY(ia32_clone) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc r16=ar.pfs,5,2,6,0 DO_SAVE_SWITCH_STACK mov loc0=rp @@ -110,7 +110,9 @@ GLOBAL_ENTRY(ia32_ret_from_clone) ld4 r2=[r2] ;; mov r8=0 - tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 + ;; + cmp.ne p6,p0=r2,r0 (p6) br.cond.spnt .ia32_strace_check_retval ;; // prevent RAW on r8 END(ia32_ret_from_clone) @@ -142,7 +144,7 @@ GLOBAL_ENTRY(ia32_trace_syscall) adds r2=IA64_PT_REGS_R8_OFFSET+16,sp ;; st8 [r2]=r3 // initialize return code to -ENOSYS - br.call.sptk.few rp=syscall_trace // give parent a chance to catch syscall args + br.call.sptk.few rp=syscall_trace_enter // give parent a chance to catch syscall args .ret2: // Need to reload arguments (they may be changed by the tracing process) adds r2=IA64_PT_REGS_R1_OFFSET+16,sp // r2 = &pt_regs.r1 adds r3=IA64_PT_REGS_R13_OFFSET+16,sp // r3 = &pt_regs.r13 @@ -170,7 +172,7 @@ GLOBAL_ENTRY(ia32_trace_syscall) adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 - br.call.sptk.few rp=syscall_trace // give parent a chance to catch return value + br.call.sptk.few rp=syscall_trace_leave // give parent a chance to catch return value .ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame br.cond.sptk.many ia64_leave_kernel END(ia32_trace_syscall) --- linux-2.6.8-rc1/arch/ia64/ia32/sys_ia32.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/ia32/sys_ia32.c 2004-07-13 17:09:13.000000000 -0700 @@ -1996,18 +1996,19 @@ sys32_sigaltstack (ia32_stack_t *uss32, int ret; mm_segment_t old_fs = get_fs(); - if (uss32) + if (uss32) { if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) return -EFAULT; - uss.ss_sp = (void *) (long) buf32.ss_sp; - uss.ss_flags = buf32.ss_flags; - /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the - check and set it to the user requested value later */ - if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { - ret = -ENOMEM; - goto out; + uss.ss_sp = (void *) (long) buf32.ss_sp; + uss.ss_flags = buf32.ss_flags; + /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the + check and set it to the user requested value later */ + if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { + ret = -ENOMEM; + goto out; + } + uss.ss_size = MINSIGSTKSZ; } - uss.ss_size = MINSIGSTKSZ; set_fs(KERNEL_DS); ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); current->sas_ss_size = buf32.ss_size; --- linux-2.6.8-rc1/arch/ia64/Kconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/Kconfig 2004-07-13 17:09:29.000000000 -0700 @@ -178,6 +178,210 @@ config DISCONTIGMEM or have huge holes in the physical address space for other reasons. See for more. +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb/kgdb.txt file. + +config KGDB_EARLY + bool + depends on KGDB + default n + prompt "KGDB Early" + help + Kgdb debugging in kernel can start shortly before/after setup_arch routine exits. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +choice + depends on KGDB + prompt "I/O port address" + default KGDB_USE_IOMEM + +config KGDB_USE_IOMEM + bool "use I/O port IOMEM address" + help + Say yes if your system uses IOMEM address for the port (e.g. rx2600). + +config KGDB_USE_PORT + bool "use I/O port address" + help + Say yes if your systems uses I/O ports (e.g. Novascale). +endchoice + +config KGDB_IOMEM + hex "hex I/O port IOMEM address" + depends on KGDB_USE_IOMEM + default 0xc0000000ff5e0000 + help + Some systems use IOMEM address for the port. This value is from + the rx2600 chassis console port. + +config KGDB_IOMEM_REG_SHIFT + hex "hex I/O port IOMEM reg shift" + depends on KGDB_USE_IOMEM + default 0x0 + help + This is the memory shift for IOMEM. + +config KGDB_PORT + hex "hex I/O port address" + default 0x3f8 + depends on KGDB + depends on KGDB_USE_PORT + help + Some systems use I/O port. + On Novascale use 0x3f8 for serial port 1 + or 0x2f8 for serial port 2. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 59 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. This value + is the rx2600 chassis's console port. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + config IA64_CYCLONE bool "Support Cyclone(EXA) Time Source" help @@ -480,6 +684,13 @@ config DEBUG_INFO Say Y here only if you plan to use gdb to debug the kernel. If you don't debug the kernel, you can say N. +config LOCKMETER + bool "Kernel lock metering" + depends on SMP + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + config SYSVIPC_COMPAT bool depends on COMPAT && SYSVIPC --- linux-2.6.8-rc1/arch/ia64/kernel/efi.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/efi.c 2004-07-13 17:09:13.000000000 -0700 @@ -43,18 +43,20 @@ static unsigned long mem_limit = ~0UL, m #define efi_call_virt(f, args...) (*(f))(args) -#define STUB_GET_TIME(prefix, adjust_arg) \ -static efi_status_t \ -prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ -{ \ - struct ia64_fpreg fr[6]; \ - efi_status_t ret; \ - \ - ia64_save_scratch_fpregs(fr); \ - ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm), \ - adjust_arg(tc)); \ - ia64_load_scratch_fpregs(fr); \ - return ret; \ +#define STUB_GET_TIME(prefix, adjust_arg) \ +static efi_status_t \ +prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ +{ \ + struct ia64_fpreg fr[6]; \ + efi_time_cap_t *atc = 0; \ + efi_status_t ret; \ + \ + if (tc) \ + atc = adjust_arg(tc); \ + ia64_save_scratch_fpregs(fr); \ + ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm), atc); \ + ia64_load_scratch_fpregs(fr); \ + return ret; \ } #define STUB_SET_TIME(prefix, adjust_arg) \ @@ -89,11 +91,14 @@ static efi_status_t \ prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \ { \ struct ia64_fpreg fr[6]; \ + efi_time_t *atm = 0; \ efi_status_t ret; \ \ + if (tm) \ + atm = adjust_arg(tm); \ ia64_save_scratch_fpregs(fr); \ ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time), \ - enabled, adjust_arg(tm)); \ + enabled, atm); \ ia64_load_scratch_fpregs(fr); \ return ret; \ } @@ -104,11 +109,14 @@ prefix##_get_variable (efi_char16_t *nam unsigned long *data_size, void *data) \ { \ struct ia64_fpreg fr[6]; \ + u32 *aattr = 0; \ efi_status_t ret; \ \ + if (attr) \ + aattr = adjust_arg(attr); \ ia64_save_scratch_fpregs(fr); \ ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable), \ - adjust_arg(name), adjust_arg(vendor), adjust_arg(attr), \ + adjust_arg(name), adjust_arg(vendor), aattr, \ adjust_arg(data_size), adjust_arg(data)); \ ia64_load_scratch_fpregs(fr); \ return ret; \ @@ -164,33 +172,41 @@ prefix##_reset_system (int reset_type, e unsigned long data_size, efi_char16_t *data) \ { \ struct ia64_fpreg fr[6]; \ + efi_char16_t *adata = 0; \ + \ + if (data) \ + adata = adjust_arg(data); \ \ ia64_save_scratch_fpregs(fr); \ efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system), \ - reset_type, status, data_size, adjust_arg(data)); \ + reset_type, status, data_size, adata); \ /* should not return, but just in case... */ \ ia64_load_scratch_fpregs(fr); \ } -STUB_GET_TIME(phys, __pa) -STUB_SET_TIME(phys, __pa) -STUB_GET_WAKEUP_TIME(phys, __pa) -STUB_SET_WAKEUP_TIME(phys, __pa) -STUB_GET_VARIABLE(phys, __pa) -STUB_GET_NEXT_VARIABLE(phys, __pa) -STUB_SET_VARIABLE(phys, __pa) -STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa) -STUB_RESET_SYSTEM(phys, __pa) - -STUB_GET_TIME(virt, ) -STUB_SET_TIME(virt, ) -STUB_GET_WAKEUP_TIME(virt, ) -STUB_SET_WAKEUP_TIME(virt, ) -STUB_GET_VARIABLE(virt, ) -STUB_GET_NEXT_VARIABLE(virt, ) -STUB_SET_VARIABLE(virt, ) -STUB_GET_NEXT_HIGH_MONO_COUNT(virt, ) -STUB_RESET_SYSTEM(virt, ) +#define phys_ptr(arg) ((__typeof__(arg)) ia64_tpa(arg)) + +STUB_GET_TIME(phys, phys_ptr) +STUB_SET_TIME(phys, phys_ptr) +STUB_GET_WAKEUP_TIME(phys, phys_ptr) +STUB_SET_WAKEUP_TIME(phys, phys_ptr) +STUB_GET_VARIABLE(phys, phys_ptr) +STUB_GET_NEXT_VARIABLE(phys, phys_ptr) +STUB_SET_VARIABLE(phys, phys_ptr) +STUB_GET_NEXT_HIGH_MONO_COUNT(phys, phys_ptr) +STUB_RESET_SYSTEM(phys, phys_ptr) + +#define id(arg) arg + +STUB_GET_TIME(virt, id) +STUB_SET_TIME(virt, id) +STUB_GET_WAKEUP_TIME(virt, id) +STUB_SET_WAKEUP_TIME(virt, id) +STUB_GET_VARIABLE(virt, id) +STUB_GET_NEXT_VARIABLE(virt, id) +STUB_SET_VARIABLE(virt, id) +STUB_GET_NEXT_HIGH_MONO_COUNT(virt, id) +STUB_RESET_SYSTEM(virt, id) void efi_gettimeofday (struct timespec *ts) --- linux-2.6.8-rc1/arch/ia64/kernel/entry.S 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/entry.S 2004-07-13 17:09:13.000000000 -0700 @@ -508,7 +508,7 @@ GLOBAL_ENTRY(ia64_trace_syscall) ;; stf.spill [r16]=f10 stf.spill [r17]=f11 - br.call.sptk.many rp=syscall_trace // give parent a chance to catch syscall args + br.call.sptk.many rp=syscall_trace_enter // give parent a chance to catch syscall args adds r16=PT(F6)+16,sp adds r17=PT(F7)+16,sp ;; @@ -548,7 +548,7 @@ GLOBAL_ENTRY(ia64_trace_syscall) .strace_save_retval: .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 - br.call.sptk.many rp=syscall_trace // give parent a chance to catch return value + br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value .ret3: br.cond.sptk ia64_leave_syscall strace_error: @@ -575,7 +575,7 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel) */ nop.m 0 nop.i 0 - br.call.sptk.many rp=syscall_trace // give parent a chance to catch return value + br.call.sptk.many rp=syscall_trace_leave // give parent a chance to catch return value } .ret4: br.cond.sptk ia64_leave_kernel END(ia64_strace_leave_kernel) @@ -601,7 +601,9 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ld4 r2=[r2] ;; mov r8=0 - tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 + ;; + cmp.ne p6,p0=r2,r0 (p6) br.cond.spnt .strace_check_retval ;; // added stop bits to prevent r8 dependency END(ia64_ret_from_clone) @@ -663,25 +665,31 @@ GLOBAL_ENTRY(ia64_leave_syscall) PT_REGS_UNWIND_INFO(0) /* * work.need_resched etc. mustn't get changed by this CPU before it returns to - * user- or fsys-mode, hence we disable interrupts early on: + * user- or fsys-mode, hence we disable interrupts early on. + * + * p6 controls whether current_thread_info()->flags needs to be check for + * extra work. We always check for extra work when returning to user-level. + * With CONFIG_PREEMPT, we also check for extra work when the preempt_count + * is 0. After extra work processing has been completed, execution + * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check + * needs to be redone. */ #ifdef CONFIG_PREEMPT rsm psr.i // disable interrupts -#else -(pUStk) rsm psr.i -#endif cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall -(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk -.work_processed_syscall: -#ifdef CONFIG_PREEMPT (pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; .pred.rel.mutex pUStk,pKStk (pKStk) ld4 r21=[r20] // r21 <- preempt_count (pUStk) mov r21=0 // r21 <- 0 ;; -(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) -#endif /* CONFIG_PREEMPT */ + cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) +#else /* !CONFIG_PREEMPT */ +(pUStk) rsm psr.i + cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk +#endif +.work_processed_syscall: adds r16=PT(LOADRS)+16,r12 adds r17=PT(AR_BSPSTORE)+16,r12 adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 @@ -776,26 +784,31 @@ GLOBAL_ENTRY(ia64_leave_kernel) PT_REGS_UNWIND_INFO(0) /* * work.need_resched etc. mustn't get changed by this CPU before it returns to - * user- or fsys-mode, hence we disable interrupts early on: + * user- or fsys-mode, hence we disable interrupts early on. + * + * p6 controls whether current_thread_info()->flags needs to be check for + * extra work. We always check for extra work when returning to user-level. + * With CONFIG_PREEMPT, we also check for extra work when the preempt_count + * is 0. After extra work processing has been completed, execution + * resumes at .work_processed_syscall with p6 set to 1 if the extra-work-check + * needs to be redone. */ #ifdef CONFIG_PREEMPT rsm psr.i // disable interrupts -#else -(pUStk) rsm psr.i -#endif cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel -(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk - ;; -.work_processed_kernel: -#ifdef CONFIG_PREEMPT - adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 +(pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; .pred.rel.mutex pUStk,pKStk (pKStk) ld4 r21=[r20] // r21 <- preempt_count (pUStk) mov r21=0 // r21 <- 0 ;; -(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) -#endif /* CONFIG_PREEMPT */ + cmp.eq p6,p0=r21,r0 // p6 <- pUStk || (preempt_count == 0) +#else +(pUStk) rsm psr.i + cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk +#endif +.work_processed_kernel: adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 ;; (p6) ld4 r31=[r17] // load current_thread_info()->flags @@ -1065,7 +1078,7 @@ skip_rbs_switch: br.cond.sptk.many .work_processed_kernel // re-check .notify: - br.call.spnt.many rp=notify_resume_user +(pUStk) br.call.spnt.many rp=notify_resume_user .ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 (pLvSys)br.cond.sptk.many .work_processed_syscall // don't re-check br.cond.sptk.many .work_processed_kernel // don't re-check --- linux-2.6.8-rc1/arch/ia64/kernel/fsys.S 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/fsys.S 2004-07-13 17:09:13.000000000 -0700 @@ -165,7 +165,6 @@ ENTRY(fsys_gettimeofday) add r9=TI_FLAGS+IA64_TASK_SIZE,r16 addl r3=THIS_CPU(cpu_info),r0 - mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc) #ifdef CONFIG_SMP movl r10=__per_cpu_offset movl r2=sal_platform_features @@ -240,12 +239,13 @@ EX(.fail_efault, probe.w.fault r10, 3) ;; ldf8 f8=[r21] // f8 now contains itm_next + mov.m r31=ar.itc // put time stamp into r31 (ITC) == now sub r28=r29, r28, 1 // r28 now contains "-(lost + 1)" - tbit.nz p9, p10=r23, 0 // p9 <- is_odd(r23), p10 <- is_even(r23) ;; ld8 r2=[r19] // r2 = sec = xtime.tv_sec ld8 r29=[r20] // r29 = nsec = xtime.tv_nsec + tbit.nz p9, p10=r23, 0 // p9 <- is_odd(r23), p10 <- is_even(r23) setf.sig f6=r28 // f6 <- -(lost + 1) (6 cyc) ;; @@ -260,7 +260,6 @@ EX(.fail_efault, probe.w.fault r10, 3) nop 0 ;; - mov r31=ar.itc // re-read ITC in case we .retry (35 cyc) xma.l f8=f11, f8, f12 // f8 (elapsed_cycles) <- (-1*last_tick + now) = (now - last_tick) nop 0 ;; --- linux-2.6.8-rc1/arch/ia64/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/irq.c 2004-07-13 17:09:26.000000000 -0700 @@ -538,6 +538,11 @@ unsigned int do_IRQ(unsigned long irq, s desc->handler->end(irq); spin_unlock(&desc->lock); } + +#ifdef CONFIG_KGDB + kgdb_process_breakpoint(); +#endif + return 1; } --- linux-2.6.8-rc1/arch/ia64/kernel/ivt.S 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/ivt.S 2004-07-13 17:09:26.000000000 -0700 @@ -68,6 +68,13 @@ # define DBG_FAULT(i) #endif +#ifdef CONFIG_KGDB +#define KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; or r31=r31,r30;; \ + mov psr.l=r31;; srlz.i;; +#else +#define KGDB_ENABLE_PSR_DB +#endif + #define MINSTATE_VIRT /* needed by minstate.h */ #include "minstate.h" @@ -473,6 +480,7 @@ ENTRY(page_fault) movl r14=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r14 ;; adds out2=16,r12 // out2 = pointer to pt_regs @@ -733,6 +741,8 @@ ENTRY(break_fault) ;; srlz.i // guarantee that interruption collection is on ;; + KGDB_ENABLE_PSR_DB + ;; (p15) ssm psr.i // restore psr.i ;; mov r3=NR_syscalls - 1 @@ -752,7 +762,9 @@ ENTRY(break_fault) ;; ld4 r2=[r2] // r2 = current_thread_info()->flags ;; - tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit + ;; + cmp.eq p8,p0=r2,r0 mov b6=r20 ;; (p8) br.call.sptk.many b6=b6 // ignore this return addr @@ -774,6 +786,7 @@ ENTRY(interrupt) srlz.i // ensure everybody knows psr.ic is back on ;; SAVE_REST + KGDB_ENABLE_PSR_DB ;; alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group mov out0=cr.ivr // pass cr.ivr as first arg @@ -1001,6 +1014,7 @@ ENTRY(non_syscall) movl r15=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r15 ;; br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr @@ -1034,6 +1048,7 @@ ENTRY(dispatch_unaligned_handler) adds r3=8,r2 // set up second base pointer ;; SAVE_REST + KGDB_ENABLE_PSR_DB movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -1076,6 +1091,7 @@ ENTRY(dispatch_to_fault_handler) adds r3=8,r2 // set up second base pointer for SAVE_REST ;; SAVE_REST + KGDB_ENABLE_PSR_DB movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -1573,10 +1589,11 @@ ENTRY(dispatch_to_ia32_handler) ld4 r2=[r2] // r2 = current_thread_info()->flags ;; ld8 r16=[r16] - tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit ;; mov b6=r16 movl r15=ia32_ret_from_syscall + cmp.eq p8,p0=r2,r0 ;; mov rp=r15 (p8) br.call.sptk.many b6=b6 --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ia64/kernel/kgdb_stub.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,3010 @@ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * IA64 ToDo: + * 1) more testing needs to be done when modifying registers. + * 2) probably could use cleanup in register get/put from unw_info but gdb work + * is on going (WIP) to reduce g-packet on wire for serial + * 3) until gdb work is complete and accepted by gdb folks, the serial interface + * isn't complete. the current g-packet is over 10,000 bytes which is too + * large for a serial line. without a g-packet a delay is used with large putpacket + requests. however, this won't solve a gdb sent packet which is a g-packet. + * 4) NMI for hung machine. Well we don't have real NMI! + */ + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +/* purloined from gdb ia64 config support */ +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) \ + + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#define REGISTER_INDEX(N) (REGISTER_BYTE(N) / sizeof (unsigned long)) +#define BUFMAX (REGISTER_BYTES*2+10) +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static short error; + + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES REGISTER_BYTES +#define BREAKNUM 0x00003333300LL +#define KGDBBREAKNUM 0x6665UL + +static void inline +kgdb_pc(struct pt_regs *regs, unsigned long pc) +{ + regs->cr_iip = pc & ~0xf; + ia64_psr(regs)->ri = pc & 0x3; + return; +} + +void +breakpoint(void) +{ + asm volatile ("break.m 0x6665"); +} + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +struct kgdb_state { + int exceptionVector; + int signo; + unsigned long err_code; + struct pt_regs *regs; + struct unw_frame_info + *unw; + int ret; +}; +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_itc; + int errcode; + unsigned long vector; + int print_debug_info; + unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)]; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)]; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1UL}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define MAX_HW_BREAKPOINT (20) +long hw_break_total_dbr, hw_break_total_ibr; +#define HW_BREAKPOINT (hw_break_total_dbr + hw_break_total_ibr) +#define WATCH_INSTRUCTION 0x0 +#define WATCH_WRITE 0x1 +#define WATCH_READ 0x2 +#define WATCH_ACCESS 0x3 + +#define HWCAP_DBR ((1 << WATCH_WRITE) | (1 << WATCH_READ)) +#define HWCAP_IBR (1 << WATCH_INSTRUCTION) +struct hw_breakpoint { + unsigned enabled; + unsigned long capable; + unsigned long type; + unsigned long mask; + unsigned long addr; +} *breakinfo; + +#define LOOKASIDE_SIZE (200 + (sizeof(struct hw_breakpoint) * MAX_HW_BREAKPOINT)) +#define MALLOC_MAX LOOKASIDE_SIZE /* Max malloc size */ +struct { + unsigned int esp; + int array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + char ch; + while (1) { + ch = tty_getDebugChar() & 0x7f; + if (ch != 0x7f) + return ch; + } + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +/*__asm__("fn_rtn_stub:\n\t" + "movl %eax,%esp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addl $-4,%ebx\n\t" + "movl (%ebx), %eax\n\t" + "pushl %eax\n\t" + "cmpl %esp,%ecx\n\t" + "jne 1b\n\t" + "popl %eax\n\t" + "popl %ebx\n\t" + "popl %ecx\n\t" + "iret \n\t"); +*/ +/* *INDENT-ON* */ +#define gdb_ia64vector kgdb_info.vector +#define gdb_ia64errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(linux_regs, unw_info);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) { + putDebugChar('-'); /* failed checksum */ + } + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("B0=0x%lx\n", regs->b0); + printk("IPSR=0x%lx\n", regs->cr_ipsr); + printk("IIP=0x%lx\n", regs->cr_iip); + printk("\n"); + +} /* print_regs */ + + + +static void +unw_ar_regs(struct unw_frame_info *unw, unsigned long *regs, int put) +{ + if (put) + unw_access_ar(unw, UNW_AR_BSP, ®s[REGISTER_INDEX(IA64_BSP_REGNUM)], put); + else + unw_get_bsp(unw, ®s[REGISTER_INDEX(IA64_BSP_REGNUM)]); + unw_access_ar(unw, UNW_AR_BSPSTORE, ®s[REGISTER_INDEX(IA64_BSPSTORE_REGNUM)], put); + unw_access_ar(unw, UNW_AR_PFS, ®s[REGISTER_INDEX(IA64_PFS_REGNUM)], put); + unw_access_ar(unw, UNW_AR_RNAT, ®s[REGISTER_INDEX(IA64_RNAT_REGNUM)], put); + unw_access_ar(unw, UNW_AR_UNAT, ®s[REGISTER_INDEX(IA64_UNAT_REGNUM)], put); + unw_access_ar(unw, UNW_AR_LC, ®s[REGISTER_INDEX(IA64_LC_REGNUM)], put); + unw_access_ar(unw, UNW_AR_EC, ®s[REGISTER_INDEX(IA64_EC_REGNUM)], put); + unw_access_ar(unw, UNW_AR_FPSR, ®s[REGISTER_INDEX(IA64_FPSR_REGNUM)], put); + unw_access_ar(unw, UNW_AR_RSC, ®s[REGISTER_INDEX(IA64_RSC_REGNUM)], put); + unw_access_ar(unw, UNW_AR_CCV, ®s[REGISTER_INDEX(IA64_CCV_REGNUM)], put); + unw_access_ar(unw, UNW_AR_CSD, ®s[REGISTER_INDEX(IA64_CSD_REGNUM)], put); + unw_access_ar(unw, UNW_AR_SSD, ®s[REGISTER_INDEX(IA64_SSD_REGNUM)], put); + return; +} + +static void +unw_get_regs(struct unw_frame_info *unw, unsigned long *regs, struct pt_regs *ptregs) +{ + int i, j; + char nat; + unsigned long *preg; + struct ia64_fpreg *fr, freg; + + memset(regs, 0, sizeof (kgdb_info.ia64_regs)); + + for (i = 1; i < 32; i++) { + if (ptregs && ((i >= 8 && i <= 11) || (i >= 12 && i <= 15))) + continue; + unw_access_gr(unw, i, ®s[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 0); + regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)] = nat; + } + + if (ptregs) { + for (preg = &ptregs->r8, i = 8; i < 12; i++, preg++) + regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)] = ptregs->r12; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)] = ptregs->r13; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)] = ptregs->r14; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)] = ptregs->r15; + } + + for (i = 1; i < 8; i++) { + if (ptregs && (i == 6 || i == 7)) + continue; + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 0); + } + + if (ptregs) { + regs[REGISTER_INDEX(IA64_BR0_REGNUM)] = ptregs->b0; + regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)] = ptregs->b6; + regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)] = ptregs->b7; + } else { + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + 6)], 0); + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + 7)], 0); + unw_access_br(unw, 0, ®s[REGISTER_INDEX(IA64_BR0_REGNUM)], 0); + } + + if (ptregs) + fr = &ptregs->f6; + else + fr = &freg; + + for (i = 6; i < 12; i++) { + if (!ptregs) + unw_access_fr(unw, i, fr, 0); + regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)] = fr->u.bits[0]; + regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)] = fr->u.bits[1]; + if (ptregs) + fr++; + } + + unw_ar_regs(unw, regs, 0); + + unw_access_pr(unw, ®s[REGISTER_INDEX(IA64_PR_REGNUM)], 0); + for (j = 1, i = 0; i < 64; i++, j <<= 1, i++) + regs[REGISTER_INDEX(IA64_PR0_REGNUM + i)] = + (regs[REGISTER_INDEX(IA64_PR_REGNUM)] & j) ? 1 : 0; + + + if (!ptregs) { + unw_get_ip(unw, ®s[REGISTER_INDEX(IA64_IP_REGNUM)]); + unw_get_cfm(unw, ®s[REGISTER_INDEX(IA64_CFM_REGNUM)]); + } else { + regs[REGISTER_INDEX(IA64_IP_REGNUM)] = ptregs->cr_iip; + regs[REGISTER_INDEX(IA64_PSR_REGNUM)] = ptregs->cr_ipsr; + regs[REGISTER_INDEX(IA64_CFM_REGNUM)] = ptregs->cr_ifs; + } + + return; +} + +static void +kgdb_get_block_task(struct task_struct *p, unsigned long *ia64regs) +{ + struct unw_frame_info info; + unsigned long ip; + int count = 0; + + unw_init_from_blocked_task(&info, p); + ip = 0UL; + do { + if (unw_unwind(&info) < 0) + return; + unw_get_ip(&info, &ip); + if (!in_sched_functions(ip)) + break; + } while (count++ < 16); + + if (!ip) + return; + + unw_get_regs(&info, ia64regs, (struct pt_regs *) 0); + + return; +} + +static void +regs_to_gdb_regs(struct kgdb_state *state) +{ + unw_get_regs(state->unw, kgdb_info.ia64_regs, state->regs); + return; +} /* regs_to_gdb_regs */ + +static void +gdb_regs_to_regs(struct kgdb_state *state) +{ + int i; + char nat; + unsigned long *regs, *preg; + struct ia64_fpreg *fr; + struct unw_frame_info *unw; + + unw = state->unw; + regs = kgdb_info.ia64_regs; + + for (i = 1; i < 32; i++) { + if ((i >= 8 && i <= 11) || (i >= 12 && i <= 15)) + continue; + nat = (char) regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)]; + unw_access_gr(unw, i, ®s[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 1); + } + + for (preg = &state->regs->r8, i = 8; i < 12; i++, preg++) + regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)]; + + for (i = 1; i < 8; i++) { + if ((i == 6 || i == 7)) + continue; + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 1); + } + state->regs->b0 = regs[REGISTER_INDEX(IA64_BR0_REGNUM)]; + state->regs->b6 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)]; + state->regs->b7 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)]; + + for (fr = &state->regs->f6, i = 6; i < 12; i++, fr++) { + fr->u.bits[0] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)]; + fr->u.bits[1] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)]; + } + + unw_ar_regs(unw, regs, 1); + + unw_access_pr(unw, ®s[IA64_PR_REGNUM], 1); + + state->regs->cr_iip = regs[REGISTER_INDEX(IA64_IP_REGNUM)]; + state->regs->cr_ipsr = regs[REGISTER_INDEX(IA64_PSR_REGNUM)]; + state->regs->cr_ifs = regs[REGISTER_INDEX(IA64_CFM_REGNUM)]; + + return; + +} /* gdb_regs_to_regs */ + +int thread_list = 0; + +void +get_gdb_regs(struct task_struct *p, struct kgdb_state *state) +{ + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(state); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task && + !user_mode(kgdb_info.cpus_waiting[i].regs)){ + memcpy(kgdb_info.ia64_regs, kgdb_info.cpus_waiting[i].ia64_regs, + sizeof(kgdb_info.ia64_regs)); + return; + } + } +#endif +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. Some of this code was purloined from get_wchan; + */ + + if (!thread_list) + return; + else if (p->state == TASK_RUNNING) + return; + + kgdb_get_block_task(p, kgdb_info.ia64_regs); + + return; + +} + +/* Indicate to caller of mem2hex or hex2mem that there has been an + error. */ +static volatile int mem_err = 0; +static volatile int mem_err_expected = 0; +static volatile int mem_err_cnt = 0; + +int +get_char(char *addr, unsigned char *data) +{ + mm_segment_t fs; + int ret; + + if ((unsigned long) addr < DEFAULT_TASK_SIZE) + return -EFAULT; + + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (get_user(*data, addr) != 0) + ret = -EFAULT; + else + ret = 0; + + set_fs(fs); + return ret; +} + +int +set_char(char *addr, int val) +{ + mm_segment_t fs; + int ret; + + if ((unsigned long) addr < DEFAULT_TASK_SIZE) + return -EFAULT; + + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (put_user(val, addr) != 0) + ret = -EFAULT; + else + ret = 0; + + set_fs(fs); + return ret; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + if (get_char(mem++, &ch)) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return buf; + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + if (set_char(mem++, ch)) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToLong(char **ptr, unsigned long *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0UL; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +#ifdef CONFIG_KGDB_EARLY +struct task_struct kgdb_task = {.comm = "kgdb-dummy"}; +#endif + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } +#ifdef CONFIG_KGDB_EARLY + if (!kgdb_pid_init_done) + return &kgdb_task; +#endif + return NULL; +} +/* *INDENT-OFF* */ + +enum instruction_type {A, I, M, F, B, L, X, u}; + +static enum instruction_type bundle_encoding[32][3] = { + { M, I, I }, /* 00 */ + { M, I, I }, /* 01 */ + { M, I, I }, /* 02 */ + { M, I, I }, /* 03 */ + { M, L, X }, /* 04 */ + { M, L, X }, /* 05 */ + { u, u, u }, /* 06 */ + { u, u, u }, /* 07 */ + { M, M, I }, /* 08 */ + { M, M, I }, /* 09 */ + { M, M, I }, /* 0A */ + { M, M, I }, /* 0B */ + { M, F, I }, /* 0C */ + { M, F, I }, /* 0D */ + { M, M, F }, /* 0E */ + { M, M, F }, /* 0F */ + { M, I, B }, /* 10 */ + { M, I, B }, /* 11 */ + { M, B, B }, /* 12 */ + { M, B, B }, /* 13 */ + { u, u, u }, /* 14 */ + { u, u, u }, /* 15 */ + { B, B, B }, /* 16 */ + { B, B, B }, /* 17 */ + { M, M, B }, /* 18 */ + { M, M, B }, /* 19 */ + { u, u, u }, /* 1A */ + { u, u, u }, /* 1B */ + { M, F, B }, /* 1C */ + { M, F, B }, /* 1D */ + { u, u, u }, /* 1E */ + { u, u, u }, /* 1F */ +}; + +#define MAX_BREAK_POINTS (20) + +struct z0_break_point { + unsigned long addr; + unsigned long bundle[2]; + unsigned int enabled; +} z0_break_point[MAX_BREAK_POINTS]; + +int kgdb_arch_set_breakpoint(unsigned long addr) +{ + unsigned long slot = addr & 0xf, bundle_addr; + unsigned long template; + struct bundle { + struct { + unsigned long long template : 5; + unsigned long long slot0 : 41; + unsigned long long slot1_p0 : 64-46; + } quad0; + struct { + unsigned long long slot1_p1 : 41 - (64-46); + unsigned long long slot2 : 41; + } quad1; + } bundle; + int i; + struct z0_break_point *z0 = NULL; + unsigned long valid; + + asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr) : "memory"); + if (!valid) + return 0; + asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr+8) : "memory"); + if (!valid) + return 0; + + + for (i = 0; i < MAX_BREAK_POINTS; i++) + if (!z0_break_point[i].enabled) { + z0 = &z0_break_point[i]; + break; + } + + if (!z0) + return 0; + + if (slot > 2) + slot = 0; + + bundle_addr = addr & ~0xFULL; + memcpy(&bundle, (unsigned long *)bundle_addr, sizeof(bundle)); + memcpy(z0->bundle, &bundle, sizeof(bundle)); + + template = bundle.quad0.template; + if (slot == 1 && bundle_encoding[template][1] == L) + slot = 2; + switch (slot) { + case 0: + bundle.quad0.slot0 = BREAKNUM; + break; + case 1: + bundle.quad0.slot1_p0 = BREAKNUM; + bundle.quad1.slot1_p1 = (BREAKNUM >> (64-46)); + break; + case 2: + bundle.quad1.slot2 = BREAKNUM; + break; + } + + memcpy((char *) bundle_addr, (char *) &bundle, sizeof(bundle)); + flush_icache_range(bundle_addr, bundle_addr + sizeof(bundle)); + z0->addr = addr; + z0->enabled = 1; + + return 1; +} + +int kgdb_arch_remove_breakpoint(unsigned long addr) +{ + struct z0_break_point *z0 = NULL; + int i; + + for (i = 0; i < MAX_BREAK_POINTS; i++) + if (z0_break_point[i].enabled && z0_break_point[i].addr == addr) { + z0 = &z0_break_point[i]; + break; + } + + if (!z0) + return 0; + + addr = addr & ~0xFULL; + (void) memcpy((char *) addr, (char *) z0->bundle, sizeof (z0->bundle)); + flush_icache_range(addr, addr + sizeof(z0->bundle)); + z0->enabled = 0; + return 1; +} + + +unsigned long hw_breakpoint_status; + +int hw_breakpoint_init; + +void +do_init_hw_break(void) +{ + s64 status; + int i; + + hw_breakpoint_init = 1; + +#ifdef CONFIG_IA64_HP_SIM + hw_break_total_ibr = 8; + hw_break_total_dbr = 8; + status = 0; +#else + status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr); +#endif + + if (status) { + printk(KERN_INFO "do_init_hw_break: pal call failed %d\n", (int) status); + return; + } + + if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) { + printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n", (int) HW_BREAKPOINT, + (int) MAX_HW_BREAKPOINT); + + while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT) && hw_break_total_ibr != 1) + hw_break_total_ibr--; + while (HW_BREAKPOINT > MAX_HW_BREAKPOINT) + hw_break_total_dbr--; + } + + breakinfo = malloc(HW_BREAKPOINT * sizeof(struct hw_breakpoint)); + + if (!breakinfo) { + printk(KERN_INFO "Failed to allocate hardware break array\n"); + return; + } + + memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint)); + + for (i = 0; i < hw_break_total_dbr; i++) + breakinfo[i].capable = HWCAP_DBR; + + for (; i < HW_BREAKPOINT; i++) + breakinfo[i].capable = HWCAP_IBR; + + return; +} + +void +correct_hw_break(void) +{ + int breakno; + + if (!breakinfo) + return; + + for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) { + if (breakinfo[breakno].enabled) { + if (breakinfo[breakno].capable & HWCAP_IBR) { + int ibreakno = breakno - hw_break_total_dbr; + ia64_set_ibr(ibreakno << 1, breakinfo[breakno].addr); + ia64_set_ibr((ibreakno << 1) + 1, + (~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) | + (1UL << 56UL) | (1UL << 63UL)); + } + else { + ia64_set_dbr(breakno << 1, breakinfo[breakno].addr); + ia64_set_dbr((breakno << 1) + 1, + (~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) | + (1UL << 56UL) | (breakinfo[breakno].type << 62UL)); + } + } + else { + if (breakinfo[breakno].capable & HWCAP_IBR) + ia64_set_ibr(((breakno - hw_break_total_dbr) << 1) + 1, 0); + else + ia64_set_dbr((breakno << 1) + 1, 0); + } + } + + return; +} + +int +hardware_breakpoint(unsigned long addr, int length, int type, int action) +{ + int breakno, found, watch; + unsigned long mask; + extern unsigned long _start[]; + + if (!hw_breakpoint_init) + do_init_hw_break(); + + if (!breakinfo) + return 0; + else if (addr == (unsigned long) _start) + return 1; + + if (type == WATCH_ACCESS) + mask = HWCAP_DBR; + else + mask = 1UL << type; + + for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT; breakno++) { + if (action) { + if (breakinfo[breakno].enabled || !(breakinfo[breakno].capable & mask)) + continue; + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].mask = length - 1; + breakinfo[breakno].addr = addr; + watch = breakno; + } else if (breakinfo[breakno].enabled && + ((length < 0 && breakinfo[breakno].addr == addr) || + ((breakinfo[breakno].capable & mask) && + (breakinfo[breakno].mask == (length - 1)) && + (breakinfo[breakno].addr == addr)))) { + breakinfo[breakno].enabled = 0; + breakinfo[breakno].type = 0UL; + } + else + continue; + found++; + if (type != WATCH_ACCESS) + break; + else if (found == 2) + break; + else + mask = HWCAP_IBR; + } + + if (type == WATCH_ACCESS && found == 1) { + breakinfo[watch].enabled = 0; + found = 0; + } + + return found; +} + +#ifdef oldbreak_protocol +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) + return -1; + + breakinfo[breakno].enabled = 0; + + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) + return -1; + + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].mask = len - 1; + breakinfo[breakno].addr = addr; + return 0; +} +#endif + +static void inline +normalize(struct unw_frame_info *running, struct pt_regs *regs) +{ + unsigned long sp; + + /* + * unwind to last frame before exception which will be an error + * and then fetch the bsp at exception time. + */ + + do { + unw_get_sp(running, &sp); + if ((sp + 0x10) >= (unsigned long) regs) + break; + } while (unw_unwind(running) >= 0); + + return; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + + +static void +snap_regs(struct unw_frame_info *unw_info, void *data) +{ + struct pt_regs *regs; + int cpu; + + regs = data; + normalize(unw_info, regs); + cpu = smp_processor_id(); + unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs); + + return; +} + +int +in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw_info) +{ + unsigned flags; + int cpu = smp_processor_id(); + in_kgdb_called = 1; + + preempt_disable(); + + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + preempt_enable_no_resched(); + return 1; + } + preempt_enable_no_resched(); + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + if (unw_info) + unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs); + else if (!user_mode(regs)) { + if (current->state == TASK_RUNNING) + unw_init_running(snap_regs, regs); + else + kgdb_get_block_task(current, kgdb_info.cpus_waiting[cpu].ia64_regs); + } + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + kgdb_local_irq_restore(flags); + preempt_enable_no_resched(); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + in_kgdb(®s, NULL); +} +#else +int +in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ + +static void do_kgdb_handle_exception(struct unw_frame_info *, void *data); + +int +kgdb_handle_exception(int exceptionVector, int signo, unsigned long err_code, struct pt_regs *linux_regs) +{ + struct kgdb_state info; + + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if (user_mode(linux_regs)) { + printk("ignoring non-kernel exception\n"); + print_regs(linux_regs); + return (0); + } + + preempt_disable(); + + kgdb_info.called_from = __builtin_return_address(0); + + info.exceptionVector = exceptionVector; + info.signo = signo; + info.err_code = err_code; + info.regs = linux_regs; + info.unw = (void *) 0; + unw_init_running(do_kgdb_handle_exception, &info); + + preempt_enable_no_resched(); + + return info.ret; +} + +static int kgdb_dbregs_enabled; + +static void +do_kgdb_handle_exception(struct unw_frame_info *unw_info, void *data) +{ + int exceptionVector, signo, have_regs = 0; + unsigned long err_code; + struct pt_regs *linux_regs; + struct kgdb_state *info; + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + int length; + unsigned long addr; + char *ptr; + int newPC; + threadref thref; + int threadid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; +#define gdb_regs kgdb_info.ia64_regs + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define ptregs (*linux_regs) +#define NUMREGS NUM_REGS + + info = data; + info->unw = unw_info; + exceptionVector = info->exceptionVector; + signo = info->signo; + err_code = info->err_code; + linux_regs = info->regs; + + normalize(unw_info, linux_regs); + + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + if (kgdboe) + netpoll_set_trap(1); + + kgdb_local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + kgdb_info.entry_itc = ia64_get_itc(); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + long time = 0, end_time; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + time = ia64_get_itc(); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && in_kgdb_here_log[j]) { + int wait = 100000; + while (wait-- && !waiting_cpus[j].task ); + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + time = ia64_get_itc(); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %ld cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%ld, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(&ptregs); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ + hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR); + if (hw_breakpoint_status & IA64_PSR_DB) + ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status ^ IA64_PSR_DB); + + + switch (exceptionVector) { + case -1: /* general death */ + case 11: /* break fix signo */ + switch (err_code) { /* break_num */ + case BREAKNUM: + signo = SIGTRAP; + break; + case KGDBBREAKNUM: + signo = SIGTRAP; + if (ia64_psr(linux_regs)->ri < 2) + kgdb_pc(linux_regs, linux_regs->cr_iip + + ia64_psr(linux_regs)->ri + 1); + else + kgdb_pc(linux_regs, linux_regs->cr_iip + 16); + break; + } + break; + case 29: /* hardware breakpoint ibr/dbr fault */ + case 36: /* single step trap */ + signo = SIGTRAP; + break; + case 6: /* ikey_miss */ + case 7: /* dkey_miss */ + case 24: /* general exception */ + case 31: /* unsupported data reference */ + signo = SIGSEGV; + break; + case 13: /* reserved */ + case 14: /* " "" */ + case 15: /* " "" */ + case 16: /* " "" */ + case 17: /* " "" */ + case 18: /* " "" */ + case 19: /* " "" */ + case 28: /* " "" */ + case 25: /* disable fp */ + case 32: /* floating point */ + case 33: /* floating point trap */ + case 34: /* lower privilege fault */ + case 35: /* taken branch trap */ + case 37: /* reserved */ + case 38: /* reserved */ + case 39: /* reserved */ + case 40: /* reserved */ + case 41: /* reserved */ + case 42: /* reserved */ + case 43: /* reserved */ + case 44: /* reserved */ + case 45: /* ia32_exception */ + case 47: /* ia32 interrupt */ + default: /* reserved and undefined */ + signo = SIGILL; + break; + case 5: /* kernel page fault */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + if (ia64_psr(linux_regs)->ri < 2) + kgdb_pc(linux_regs, linux_regs->cr_iip + + ia64_psr(linux_regs)->ri + 1); + else + kgdb_pc(linux_regs, linux_regs->cr_iip + 16); + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(&ptregs); + goto exit_kgdb; + } + break; + } + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_ia64vector = exceptionVector; + gdb_ia64errcode = err_code; +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'p': /* fetch register */ + { + int regnum; + + if (!have_regs) { + get_gdb_regs(usethread, info); + have_regs = 1; + } + + hex2mem(&remcomInBuffer[1], (char *) ®num, sizeof(regnum), 0); + if (regnum >= NUMREGS) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = 0; + break; + } + mem2hex((char *) &gdb_regs[REGISTER_INDEX(regnum)], remcomOutBuffer, + REGISTER_SIZE(regnum), 0); + remcomOutBuffer[REGISTER_SIZE(regnum) * 2] = 0; + break; + } + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, info); + mem2hex((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], (char *) gdb_regs, NUMREGBYTES, 0); + if (!usethread || usethread == current) { + gdb_regs_to_regs(info); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). These may have + * meaning for ptrace, but for us it is safe to + * ignor them. We do this by dumping them into + * _GS which we also ignor, but do have memory for. + */ + int regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(info); + if ((!usethread || usethread == current) && + hexToInt(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + regno = + (regno >= NUMREGS ? 0 : regno); + hex2mem(ptr, (char *) &gdb_regs[REGISTER_INDEX(regno)], + 4, 0); + gdb_regs_to_regs(info); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr) && + (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + mem2hex((char *) addr, + remcomOutBuffer, length, 1); + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { + extern unsigned long _start[]; + + if (addr == (unsigned long) _start) + strcpy(remcomOutBuffer, "OK"); + + else { + hex2mem(ptr, (char *) addr, length, 1); + + if (mem_err) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + if (kernel_text_address(addr)) + flush_icache_range(addr, addr + length); + strcpy(remcomOutBuffer, "OK"); + } + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%lx\n", addr); + + ptregs.cr_iip = addr; + } + + newPC = ptregs.cr_iip; + + /* clear the trace bit */ + ptregs.cr_ipsr &= ~IA64_PSR_SS; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + ptregs.cr_ipsr |= IA64_PSR_SS; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(&ptregs); + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + ptregs.cr_ipsr |= IA64_PSR_DB; + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + have_regs = 0; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + +#ifdef oldbreak_protocol + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + ptr++; + hexToInt(&ptr, &breaktype); + ptr++; + hexToInt(&ptr, &length); + ptr++; + hexToLong(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToInt(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; +#endif + /* + * Set/Remove watchpoint + * + */ + case 'Z': + case 'z': + if (!kgdb_dbregs_enabled) + break; + + switch (remcomInBuffer[1]) { + case '0': /* insert hwd break */ + case '1': /* hardware breakpoint */ + case '2': /* write watchpoint */ + case '3': /* read watchpoint */ + case '4': /* access watchpoint */ + { + int ret; + if (remcomInBuffer[2] != ',') { + strcpy(remcomOutBuffer, "ERROR"); + break; + } + ptr = &remcomInBuffer[3]; + if (hexToLong(&ptr, &addr)) { + ptr++; + if (!hexToInt(&ptr, &length)) { + strcpy(remcomOutBuffer, "ERROR"); + break; + } + } + else { + strcpy(remcomOutBuffer, "ERROR"); + break; + } + + if (remcomInBuffer[1] == '0') { + if (remcomInBuffer[0] == 'z') + ret = kgdb_arch_remove_breakpoint(addr); + else + ret = kgdb_arch_set_breakpoint(addr); + } + else ret = hardware_breakpoint(addr, length, + remcomInBuffer[1] - '1', + remcomInBuffer[0] == 'Z'); + if (ret) + strcpy(remcomOutBuffer, "OK"); + else + strcpy(remcomOutBuffer, "ERROR"); + break; + } + default: + strcpy(remcomOutBuffer, "ERROR"); + break; + } + break; + case 'R': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + machine_restart(NULL); + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (ptregs.cr_ipsr & IA64_PSR_SS) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (ptregs.cr_ipsr & IA64_PSR_SS)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + + if (!ss_hold) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + kgdb_local_irq_restore(flags); + info->ret = 0; + return; + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + kgdb_local_irq_restore(flags); + info->ret = 0; + return; +} + +/* this function is used to set up exception handlers for tracing and + * breakpoints. + * This function is not needed as the above line does all that is needed. + * We leave it for backward compatitability... + */ +void +set_debug_traps(void) +{ + /* + * linux_debug_hook is defined in traps.c. We store a pointer + * to our own exception handler into it. + + * But really folks, every hear of labeled common, an old Fortran + * concept. Lots of folks can reference it and it is define if + * anyone does. Only one can initialize it at link time. We do + * this with the hook. See the statement above. No need for any + * executable code and it is ready as soon as the kernel is + * loaded. Very desirable in kernel debugging. + + linux_debug_hook = handle_exception ; + */ + + /* In case GDB is started before us, ack any packets (presumably + "$?#xx") sitting there. + putDebugChar ('+'); + + initialized = 1; + */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_ia64vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +int __init +kgdb_enable_dbregs(char *str) +{ + kgdb_dbregs_enabled = 1; + return 1; +} + +__setup("kgdb_debug_regs=", kgdb_enable_dbregs); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + int flags; + kgdb_local_irq_save(flags); + spin_lock(&ts_spin); + kgdb_and_then->at_time = ia64_get_itc(); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + kgdb_local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + BREAKPOINT; + } +} + --- linux-2.6.8-rc1/arch/ia64/kernel/machvec.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/machvec.c 2004-07-13 17:09:13.000000000 -0700 @@ -44,12 +44,6 @@ machvec_init (const char *name) #endif /* CONFIG_IA64_GENERIC */ void -machvec_noop (void) -{ -} -EXPORT_SYMBOL(machvec_noop); - -void machvec_setup (char **arg) { } --- linux-2.6.8-rc1/arch/ia64/kernel/Makefile 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/Makefile 2004-07-13 17:09:26.000000000 -0700 @@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o obj-$(CONFIG_IA64_CYCLONE) += cyclone.o +obj-$(CONFIG_KGDB) += kgdb_stub.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o --- linux-2.6.8-rc1/arch/ia64/kernel/mca.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/mca.c 2004-07-13 17:09:13.000000000 -0700 @@ -247,7 +247,9 @@ ia64_mca_log_sal_error_record(int sal_in u8 *buffer; u64 size; int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; +#ifdef IA64_MCA_DEBUG_INFO static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; +#endif size = ia64_log_get(sal_info_type, &buffer, irq_safe); if (!size) @@ -596,7 +598,7 @@ ia64_mca_cmc_vector_disable (void *dummy cmcv = (cmcv_reg_t)ia64_getreg(_IA64_REG_CR_CMCV); cmcv.cmcv_mask = 1; /* Mask/disable interrupt */ - ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval) + ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval); IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x disabled.\n", @@ -623,7 +625,7 @@ ia64_mca_cmc_vector_enable (void *dummy) cmcv = (cmcv_reg_t)ia64_getreg(_IA64_REG_CR_CMCV); cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ - ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval) + ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval); IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x enabled.\n", --- linux-2.6.8-rc1/arch/ia64/kernel/module.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/module.c 2004-07-13 17:09:13.000000000 -0700 @@ -656,26 +656,18 @@ do_reloc (struct module *mod, uint8_t r_ case RV_PCREL: switch (r_type) { case R_IA64_PCREL21B: - if (in_init(mod, val)) { - /* Calls to init code from core are bad news */ - if (in_core(mod, (uint64_t)location)) { - printk(KERN_ERR "%s: init symbol 0x%lx used in module code at %p\n", - mod->name, val, location); - return -ENOEXEC; - } - } else if (in_core(mod, val)) { + if ((in_init(mod, val) && in_core(mod, (uint64_t)location)) || + (in_core(mod, val) && in_init(mod, (uint64_t)location))) { /* * Init section may have been allocated far away from core, * if the branch won't reach, then allocate a plt for it. */ - if (in_init(mod, (uint64_t)location)) { - uint64_t delta = ((int64_t)val - (int64_t)location) / 16; - if (delta + (1 << 20) >= (1 << 21)) { - val = get_fdesc(mod, val, &ok); - val = get_plt(mod, location, val, &ok); - } + uint64_t delta = ((int64_t)val - (int64_t)location) / 16; + if (delta + (1 << 20) >= (1 << 21)) { + val = get_fdesc(mod, val, &ok); + val = get_plt(mod, location, val, &ok); } - } else + } else if (!is_internal(mod, val)) val = get_plt(mod, location, val, &ok); /* FALL THROUGH */ default: --- linux-2.6.8-rc1/arch/ia64/kernel/pal.S 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/pal.S 2004-07-13 17:09:13.000000000 -0700 @@ -54,7 +54,7 @@ END(ia64_pal_default_handler) * */ GLOBAL_ENTRY(ia64_pal_call_static) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) alloc loc1 = ar.pfs,5,5,0,0 movl loc2 = pal_entry_point 1: { @@ -100,7 +100,7 @@ END(ia64_pal_call_static) * in2 - in3 Remaning PAL arguments */ GLOBAL_ENTRY(ia64_pal_call_stacked) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4) alloc loc1 = ar.pfs,4,4,4,0 movl loc2 = pal_entry_point @@ -147,7 +147,7 @@ END(ia64_pal_call_stacked) GLOBAL_ENTRY(ia64_pal_call_phys_static) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4) alloc loc1 = ar.pfs,4,7,0,0 movl loc2 = pal_entry_point 1: { --- linux-2.6.8-rc1/arch/ia64/kernel/perfmon.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/perfmon.c 2004-07-13 17:09:13.000000000 -0700 @@ -4702,21 +4702,22 @@ static int pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags) { struct task_struct *task; - int state; + int state, old_state; +recheck: state = ctx->ctx_state; + task = ctx->ctx_task; - task = PFM_CTX_TASK(ctx); if (task == NULL) { DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, state)); return 0; } DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n", - ctx->ctx_fd, - state, - task->pid, - task->state, PFM_CMD_STOPPED(cmd))); + ctx->ctx_fd, + state, + task->pid, + task->state, PFM_CMD_STOPPED(cmd))); /* * self-monitoring always ok. @@ -4728,31 +4729,61 @@ pfm_check_task_state(pfm_context_t *ctx, if (task == current || ctx->ctx_fl_system) return 0; /* - * context is UNLOADED, MASKED we are safe to go + * no command can operate on a zombie context */ - if (state != PFM_CTX_LOADED) return 0; + if (state == PFM_CTX_ZOMBIE) { + DPRINT(("cmd %d state zombie cannot operate on context\n", cmd)); + return -EINVAL; + } - if (state == PFM_CTX_ZOMBIE) return -EINVAL; + /* + * if context is UNLOADED, MASKED we are safe to go + */ + if (state != PFM_CTX_LOADED) return 0; /* - * context is loaded, we must make sure the task is stopped + * context is LOADED, we must make sure the task is stopped * We could lift this restriction for UP but it would mean that * the user has no guarantee the task would not run between * two successive calls to perfmonctl(). That's probably OK. * If this user wants to ensure the task does not run, then * the task must be stopped. */ - if (PFM_CMD_STOPPED(cmd) && task->state != TASK_STOPPED) { - DPRINT(("[%d] task not in stopped state\n", task->pid)); - return -EBUSY; - } + if (PFM_CMD_STOPPED(cmd)) { + if (task->state != TASK_STOPPED) { + DPRINT(("[%d] task not in stopped state\n", task->pid)); + return -EBUSY; + } + /* + * task is now stopped, wait for ctxsw out + * + * This is an interesting point in the code. + * We need to unprotect the context because + * the pfm_save_regs() routines needs to grab + * the same lock. There are danger in doing + * this because it leaves a window open for + * another task to get access to the context + * and possibly change its state. The one thing + * that is not possible is for the context to disappear + * because we are protected by the VFS layer, i.e., + * get_fd()/put_fd(). + */ + old_state = state; - UNPROTECT_CTX(ctx, flags); + UNPROTECT_CTX(ctx, flags); - wait_task_inactive(task); + wait_task_inactive(task); - PROTECT_CTX(ctx, flags); + PROTECT_CTX(ctx, flags); + /* + * we must recheck to verify if state has changed + */ + if (ctx->ctx_state != old_state) { + DPRINT(("old_state=%d new_state=%d\n", old_state, ctx->ctx_state)); + goto recheck; + } + } return 0; } --- linux-2.6.8-rc1/arch/ia64/kernel/process.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/process.c 2004-07-13 17:09:26.000000000 -0700 @@ -407,6 +407,9 @@ copy_thread (int nr, unsigned long clone */ child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); +#ifdef CONFIG_KGDB + child_ptregs->cr_ipsr |= IA64_PSR_DB; +#endif /* * NOTE: The calling convention considers all floating point @@ -643,6 +646,9 @@ kernel_thread (int (*fn)(void *), void * regs.pt.r11 = (unsigned long) arg; /* 2nd argument */ /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */ regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; +#ifdef CONFIG_KGDB + regs.pt.cr_ipsr |= IA64_PSR_DB; +#endif regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; --- linux-2.6.8-rc1/arch/ia64/kernel/ptrace.c 2004-03-10 20:41:25.000000000 -0800 +++ 25/arch/ia64/kernel/ptrace.c 2004-07-13 17:09:13.000000000 -0700 @@ -1447,9 +1447,8 @@ sys_ptrace (long request, pid_t pid, uns return ret; } -/* "asmlinkage" so the input arguments are preserved... */ -asmlinkage void +void syscall_trace (void) { if (!test_thread_flag(TIF_SYSCALL_TRACE)) @@ -1472,3 +1471,38 @@ syscall_trace (void) current->exit_code = 0; } } + +/* "asmlinkage" so the input arguments are preserved... */ + +asmlinkage void +syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + long syscall; + + if (unlikely(current->audit_context)) { + if (IS_IA32_PROCESS(regs)) + syscall = regs->r1; + else + syscall = regs->r15; + + audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3); + } + + if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) + syscall_trace(); +} + +/* "asmlinkage" so the input arguments are preserved... */ + +asmlinkage void +syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + if (unlikely(current->audit_context)) + audit_syscall_exit(current, ((struct pt_regs *) &stack)->r8); + + if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace & PT_PTRACED)) + syscall_trace(); +} --- linux-2.6.8-rc1/arch/ia64/kernel/sal.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/sal.c 2004-07-13 17:09:13.000000000 -0700 @@ -188,6 +188,27 @@ sal_desc_ap_wakeup (void *p) break; } } + +static void __init +chk_nointroute_opt(void) +{ + char *cp; + extern char saved_command_line[]; + + for (cp = saved_command_line; *cp; ) { + if (memcmp(cp, "nointroute", 10) == 0) { + no_int_routing = 1; + printk ("no_int_routing on\n"); + break; + } else { + while (*cp != ' ' && *cp) + ++cp; + while (*cp == ' ') + ++cp; + } + } +} + #else static void __init sal_desc_ap_wakeup(void *p) { } #endif @@ -207,6 +228,9 @@ ia64_sal_init (struct ia64_sal_systab *s printk(KERN_ERR "bad signature in system table!"); check_versions(systab); +#ifdef CONFIG_SMP + chk_nointroute_opt(); +#endif /* revisions are coded in BCD, so %x does the job for us */ printk(KERN_INFO "SAL %x.%x: %.32s %.32s%sversion %x.%x\n", --- linux-2.6.8-rc1/arch/ia64/kernel/setup.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/setup.c 2004-07-13 17:09:26.000000000 -0700 @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) # error "struct cpuinfo_ia64 too big!" @@ -374,11 +375,36 @@ setup_arch (char **cmdline_p) # endif } #endif +#ifndef CONFIG_IA64_HP_SIM +#ifdef CONFIG_KGDB + { + unsigned long total_ibr, total_dbr; + long status; + int dbr; + + status = ia64_pal_debug_info(&total_ibr, &total_dbr); + + if (!status) { + printk(KERN_INFO "kgdb has DBR = %d IBR = %d\n", + (int) total_dbr, (int) total_ibr); + + for (dbr = 0; dbr < total_dbr; dbr++) + ia64_set_dbr((dbr << 1) + 1, 0); + for (dbr = 0; dbr < total_ibr; dbr++) + ia64_set_ibr((dbr << 1) + 1, 0); + } + } +#endif +#endif + /* enable IA-64 Machine Check Abort Handling */ ia64_mca_init(); platform_setup(cmdline_p); +#ifdef CONFIG_KGDB_EARLY + kgdb_serial_init(); +#endif paging_init(); } --- linux-2.6.8-rc1/arch/ia64/kernel/smpboot.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/smpboot.c 2004-07-13 17:09:36.000000000 -0700 @@ -400,14 +400,11 @@ do_boot_cpu (int sapicid, int cpu) if (IS_ERR(c_idle.idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(c_idle.idle); - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ + /* Make this the idle thread */ init_idle(c_idle.idle, cpu); + /* Remove it from the pidhash */ unhash_process(c_idle.idle); task_for_booting_cpu = c_idle.idle; --- linux-2.6.8-rc1/arch/ia64/kernel/smp.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/smp.c 2004-07-13 17:09:26.000000000 -0700 @@ -47,6 +47,7 @@ #include #include #include +#include /* * Structure and data for smp_call_function(). This is designed to minimise static memory @@ -66,6 +67,9 @@ static volatile struct call_data_struct #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 +#ifdef CONFIG_KGDB +#define IPI_KGDB_INTERRUPT 2 +#endif /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned; @@ -156,6 +160,12 @@ handle_IPI (int irq, void *dev_id, struc stop_this_cpu(); break; +#ifdef CONFIG_KGDB + case IPI_KGDB_INTERRUPT: + (void) in_kgdb(regs, NULL); + break; +#endif + default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -361,6 +371,14 @@ smp_call_function (void (*func) (void *i } EXPORT_SYMBOL(smp_call_function); +#ifdef CONFIG_KGDB +void +smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(IPI_KGDB_INTERRUPT); +} +#endif + /* * this function calls the 'stop' function on all other CPUs in the system. */ --- linux-2.6.8-rc1/arch/ia64/kernel/traps.c 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/kernel/traps.c 2004-07-13 17:09:26.000000000 -0700 @@ -35,6 +35,19 @@ trap_init (void) fpswa_interface = __va(ia64_boot_param->fpswa); } +#ifdef CONFIG_KGDB +extern int kgdb_handle_exception(int, int, int, struct pt_regs *); +#define CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after) \ + { \ + if (!user_mode(regs)) { \ + kgdb_handle_exception(trapnr, signr, error_code, regs); \ + after; \ + } \ + } +#else +#define CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after) +#endif + /* * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock * is acquired through the console unblank code) @@ -85,6 +98,8 @@ die (const char *str, struct pt_regs *re bust_spinlocks(1); } + CHK_REMOTE_DEBUG(-1, SIGTRAP, err, regs,) + if (++die.lock_owner_depth < 3) { printk("%s[%d]: %s %ld [%d]\n", current->comm, current->pid, str, err, ++die_counter); @@ -117,9 +132,13 @@ ia64_bad_break (unsigned long break_num, siginfo.si_flags = 0; /* clear __ISR_VALID */ siginfo.si_isr = 0; + + switch (break_num) { case 0: /* unknown error (used by GCC for __builtin_abort()) */ +#ifndef CONFIG_KGDB die_if_kernel("bugcheck!", regs, break_num); +#endif sig = SIGILL; code = ILL_ILLOPC; break; @@ -172,8 +191,10 @@ ia64_bad_break (unsigned long break_num, break; default: +#ifndef CONFIG_KGDB if (break_num < 0x40000 || break_num > 0x100000) die_if_kernel("Bad break", regs, break_num); +#endif if (break_num < 0x80000) { sig = SIGILL; code = __ILL_BREAK; @@ -181,6 +202,13 @@ ia64_bad_break (unsigned long break_num, sig = SIGTRAP; code = TRAP_BRKPT; } } +#ifdef CONFIG_KGDB + /* + * We don't want to trap simulator system calls. + */ + if (break_num != 0x80001) + CHK_REMOTE_DEBUG(11, sig, break_num, regs, return) +#endif siginfo.si_signo = sig; siginfo.si_errno = 0; siginfo.si_code = code; @@ -488,8 +516,9 @@ ia64_fault (unsigned long vector, unsign break; case 29: /* Debug */ - case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ + CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs, return) + case 35: /* Taken Branch Trap */ if (fsys_mode(current, regs)) { extern char __kernel_syscall_via_break[]; /* @@ -603,6 +632,7 @@ ia64_fault (unsigned long vector, unsign sprintf(buf, "Fault %lu", vector); break; } + CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs,) die_if_kernel(buf, regs, error); force_sig(SIGILL, current); } --- linux-2.6.8-rc1/arch/ia64/kernel/unwind.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/kernel/unwind.c 2004-07-13 17:09:26.000000000 -0700 @@ -75,10 +75,69 @@ # define STAT(x...) #endif + +#ifdef CONFIG_KGDB_EARLY +#define KGDB_EARLY_SIZE 100 +static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE]; +static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE]; +void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free; + +static void __init +kgdb_malloc_init(void) +{ + int i; + + kgdb_reg_state_free = kgdb_reg_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free; + kgdb_reg_state_free = &kgdb_reg_state[i]; + } + + kgdb_labeled_state_free = kgdb_labeled_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_labeled_state[i]) = + (unsigned long) kgdb_labeled_state_free; + kgdb_labeled_state_free = &kgdb_labeled_state[i]; + } + +} + +static void * __init +kgdb_malloc(void **mem) +{ + void *p; + + p = *mem; + *mem = *((void **) p); + return p; +} + +static void __init +kgdb_free(void **mem, void *p) +{ + *((void **)p) = *mem; + *mem = p; +} + +#define alloc_reg_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_reg_state_free) : \ + kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)) +#define free_reg_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_reg_state_free, usr) : \ + kfree(usr)) +#define alloc_labeled_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_labeled_state_free) : \ + kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)) +#define free_labeled_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_labeled_state_free, usr) : \ + kfree(usr)) + +#else #define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) +#endif typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; @@ -2267,6 +2326,10 @@ unw_init (void) init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp, __start_unwind, __end_unwind); + +#ifdef CONFIG_KGDB_EARLY + kgdb_malloc_init(); +#endif } /* --- linux-2.6.8-rc1/arch/ia64/lib/dec_and_lock.c 2004-01-09 00:04:31.000000000 -0800 +++ 25/arch/ia64/lib/dec_and_lock.c 2004-07-13 17:09:29.000000000 -0700 @@ -13,6 +13,7 @@ #include #include +#ifndef CONFIG_LOCKMETER /* * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock. Both of these * operations have to be done atomically, so that the count doesn't drop to zero without @@ -40,3 +41,4 @@ atomic_dec_and_lock (atomic_t *refcount, } EXPORT_SYMBOL(atomic_dec_and_lock); +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ia64/lib/kgdb_serial.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,607 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b,c) kgdb_serial_out(a, b, c) +#define outb_py(a, b, c) kgdb_serial_out(b, c, a) +#define inb_py(ASYNC, OFF) kgdb_serial_in(ASYNC, OFF) + +static void inline +kgdb_serial_out(struct async_struct *serial, unsigned long offset, char ch) +{ + offset <<= serial->iomem_reg_shift; + + switch(serial->io_type) { + case SERIAL_IO_MEM: + writeb(ch, serial->iomem_base + offset); + break; + default: + /* fix parameter order */ + outb( ch, serial->port + offset); + break; + } + return; +} + +static inline unsigned int +kgdb_serial_in(struct async_struct *serial, unsigned long offset) +{ + unsigned int ch; + + offset <<= serial->iomem_reg_shift; + + switch(serial->io_type) { + case SERIAL_IO_MEM: + ch = readb(serial->iomem_base + offset); + break; + default: + ch = inb(serial->port + offset); + break; + } + + return ch; +} + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_py(info, UART_LSR); + + if (it & UART_LSR_DR) + return (inb_py(info, UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_py(info, UART_LSR) & UART_LSR_THRE)) ; + + outb_py(chr, info, UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_py(info, UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_py(info, UART_IER); + outb_px(info, UART_IER, 0); + scratch2 = inb_py(info, UART_IER); + outb_px(info, UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_py(info, UART_LCR); + outb_px(info, UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(info, UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(info, UART_LCR, 0); + outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_py(info, UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_py(info, UART_MCR); + outb_px(info, UART_MCR, UART_MCR_LOOP | scratch); + outb_px(info, UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_py(info, UART_MSR) & 0xF0; + outb_px(info, UART_MCR, scratch); +#ifndef CONFIG_SERIAL_8250_HCDP /* HCDP seems to skip this test */ + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + (void) inb_py(info, UART_RX); + outb_px(info, UART_IER, 0); + + (void) inb_py(info, UART_RX); /* serial driver comments say */ + (void) inb_py(info, UART_IIR); /* this clears the interrupt regs */ + (void) inb_py(info, UART_MSR); + outb_px(info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(info, UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(info, UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(info, UART_MCR, info->MCR); + printk("UART_LCR = 0x%x\n", inb_py(info, UART_LCR)); + + outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info, UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr; + volatile long time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + time = ia64_get_itc(); + end_time = time + local_cpu_data->itm_delta * (HZ / 10); + if (!local_cpu_data->itm_delta) + end_time = time + 500; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + time = ia64_get_itc(); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + udelay(10000); +// program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +static int mem_init_done = 1; + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + + +static inline int kgdb_mem_init_done(void) +{ + return mem_init_done; +} + +#ifdef CONFIG_KGDB_EARLY +static struct irqaction kgdb_action; +#endif + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif +#ifndef CONFIG_KGDB_EARLY + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); +#else +{ + irq_desc_t *desc; + kgdb_action.handler = gdb_interrupt; + kgdb_action.flags = IRQ_T(gdb_async_info); + kgdb_action.mask = CPU_MASK_NONE; + kgdb_action.name = "KGDB-stub"; + kgdb_action.next = NULL; + kgdb_action.dev_id = NULL; + desc = irq_descp(gdb_async_info->state->irq); + if (desc->handler != &no_irq_type) { + desc->action = &kgdb_action; + ints_disabled = 0; + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | + IRQ_WAITING | IRQ_INPROGRESS); + desc->handler->startup(gdb_async_info->state->irq); + } + if (ints_disabled) + printk("kgdb_enable_ints_now: setup_irq failed\n"); + else + printk("kgdb early access enabled\n"); +} +#endif + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info, UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info, UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +void __init +kgdb_serial_init(void) +{ + extern char saved_command_line[]; + char *cp, *str; + int kgdbbreak = 0; + + for (cp = saved_command_line; *cp; cp++) { + if (memcmp(cp, "kgdb=1", 6) == 0) { + kgdbbreak = 1; + } + else if (memcmp(cp,"kgdbio=", 7) == 0) { + int baud; + + cp += 7; + baud = simple_strtoul(cp, &str, 10); + state.custom_divisor = SB_BASE/baud; + if (*str == ',') { + str++; + state.irq = simple_strtoul(str, &str, 10); + if (*str == ',') { + str++; + local_info.iomem_base = state.iomem_base = (char *) + simple_strtoul(str, &str, 0); + local_info.io_type = state.io_type = SERIAL_IO_MEM; + } + } + printk("kgdb_serial_init: irq = %d iomem_base = 0x%lx baud = %d\n", + state.irq, state.iomem_base, baud); + } + } + + kgdb_enable_ints(); + if (!ints_disabled && kgdbbreak) + BREAKPOINT; +} + +#ifndef CONFIG_IA64_HP_SIM +late_initcall(kgdb_enable_ints); +#endif --- linux-2.6.8-rc1/arch/ia64/lib/Makefile 2004-06-15 23:29:40.000000000 -0700 +++ 25/arch/ia64/lib/Makefile 2004-07-13 17:09:26.000000000 -0700 @@ -16,6 +16,7 @@ lib-$(CONFIG_MCKINLEY) += copy_page_mck. lib-$(CONFIG_PERFMON) += carta_random.o lib-$(CONFIG_MD_RAID5) += xor.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o AFLAGS___divdi3.o = AFLAGS___udivdi3.o = -DUNSIGNED --- linux-2.6.8-rc1/arch/ia64/mm/fault.c 2004-04-03 20:39:10.000000000 -0800 +++ 25/arch/ia64/mm/fault.c 2004-07-13 17:09:26.000000000 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include extern void die (char *, struct pt_regs *, long); @@ -232,6 +233,11 @@ ia64_do_page_fault (unsigned long addres */ bust_spinlocks(1); +#ifdef CONFIG_KGDB + kgdb_handle_exception(5, SIGBUS, isr, regs); + return; +#endif + if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address); else --- linux-2.6.8-rc1/arch/ia64/sn/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ia64/sn/kernel/irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -72,7 +72,7 @@ sn_enable_irq(unsigned int irq) { } -static inline void move_irq(int irq) +static inline void sn_move_irq(int irq) { /* note - we hold desc->lock */ cpumask_t tmp; @@ -110,7 +110,7 @@ sn_ack_irq(unsigned int irq) } HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask ); __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); - move_irq(irq); + sn_move_irq(irq); } static void --- linux-2.6.8-rc1/arch/ia64/sn/kernel/sn2/sn2_smp.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/arch/ia64/sn/kernel/sn2/sn2_smp.c 2004-07-13 17:09:13.000000000 -0700 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,13 @@ wait_piowc(void) } +void +sn_tlb_migrate_finish(struct mm_struct *mm) +{ + if (mm == current->mm) + flush_tlb_mm(mm); +} + /** * sn2_global_tlb_purge - globally purge translation cache of virtual address range @@ -114,6 +122,13 @@ sn2_global_tlb_purge (unsigned long star return; } + if (atomic_read(&mm->mm_users) == 1) { + flush_tlb_mm(mm); + preempt_enable(); + return; + } + + nix = 0; for (cnode=find_first_bit(&nodes_flushed, NR_NODES); cnode < NR_NODES; cnode=find_next_bit(&nodes_flushed, NR_NODES, ++cnode)) --- linux-2.6.8-rc1/arch/mips/kernel/smp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/mips/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -279,14 +279,10 @@ static int __init do_boot_cpu(int cpu) if (IS_ERR(idle)) panic("failed fork for CPU %d\n", cpu); - wake_up_forked_process(idle); - - /* - * We remove it from the pidhash and the runqueue once we've - * got the process: - */ + /* Make this the idle thread */ init_idle(idle, cpu); + /* Remove it from the pidhash */ unhash_process(idle); prom_boot_secondary(cpu, idle); --- linux-2.6.8-rc1/arch/parisc/kernel/smp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/parisc/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -543,7 +543,6 @@ int __init smp_boot_one_cpu(int cpuid, i if (IS_ERR(idle)) panic("SMP: fork failed for CPU:%d", cpuid); - wake_up_forked_process(idle); init_idle(idle, cpunum); unhash_process(idle); idle->thread_info->cpu = cpunum; --- linux-2.6.8-rc1/arch/ppc64/kernel/smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc64/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -804,7 +804,6 @@ static void __init smp_create_idle(unsig if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - wake_up_forked_process(p); init_idle(p, cpu); unhash_process(p); --- linux-2.6.8-rc1/arch/ppc/boot/common/misc-common.c 2003-09-27 18:57:43.000000000 -0700 +++ 25/arch/ppc/boot/common/misc-common.c 2004-07-13 17:09:23.000000000 -0700 @@ -59,7 +59,7 @@ static int _cvt(unsigned long val, char void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap); unsigned char *ISA_io = NULL; -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) extern unsigned long com_port; extern int serial_tstc(unsigned long com_port); @@ -80,7 +80,7 @@ void exit(void) int tstc(void) { -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) if(keyb_present) return (CRT_tstc() || serial_tstc(com_port)); else @@ -93,7 +93,7 @@ int tstc(void) int getc(void) { while (1) { -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) if (serial_tstc(com_port)) return (serial_getc(com_port)); #endif /* serial console */ @@ -108,7 +108,7 @@ putc(const char c) { int x,y; -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) serial_putc(com_port, c); if ( c == '\n' ) serial_putc(com_port, '\r'); @@ -155,7 +155,7 @@ void puts(const char *s) y = orig_y; while ( ( c = *s++ ) != '\0' ) { -#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPC52xx_CONSOLE) serial_putc(com_port, c); if ( c == '\n' ) serial_putc(com_port, '\r'); #endif /* serial console */ --- linux-2.6.8-rc1/arch/ppc/boot/simple/Makefile 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/ppc/boot/simple/Makefile 2004-07-13 17:09:23.000000000 -0700 @@ -113,6 +113,12 @@ zimageinitrd-$(CONFIG_SPRUCE) := zImage entrypoint-$(CONFIG_SPRUCE) := 0x00800000 misc-$(CONFIG_SPRUCE) += misc-spruce.o + zimage-$(CONFIG_LITE5200) := zImage-STRIPELF +zimageinitrd-$(CONFIG_LITE5200) := zImage.initrd-STRIPELF + end-$(CONFIG_LITE5200) := lite5200 + cacheflag-$(CONFIG_LITE5200) := -include $(clear_L2_L3) + + # SMP images should have a '.smp' suffix. end-$(CONFIG_SMP) := $(end-y).smp @@ -144,6 +150,7 @@ boot-$(CONFIG_8xx) += m8xx_tty.o boot-$(CONFIG_8260) += m8260_tty.o boot-$(CONFIG_GT64260_CONSOLE) += gt64260_tty.o endif +boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o LIBS := $(common)/lib.a $(bootlib)/lib.a ifeq ($(CONFIG_PPC_PREP),y) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/boot/simple/mpc52xx_tty.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,138 @@ +/* + * arch/ppc/boot/simple/mpc52xx_tty.c + * + * Minimal serial functions needed to send messages out a MPC52xx + * Programmable Serial Controller (PSC). + * + * Author: Dale Farnsworth + * + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is licensed + * "as is" without any warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#if MPC52xx_PF_CONSOLE_PORT == 0 +#define MPC52xx_CONSOLE MPC52xx_PSC1 +#define MPC52xx_PSC_CONFIG_SHIFT 0 +#elif MPC52xx_PF_CONSOLE_PORT == 1 +#define MPC52xx_CONSOLE MPC52xx_PSC2 +#define MPC52xx_PSC_CONFIG_SHIFT 4 +#elif MPC52xx_PF_CONSOLE_PORT == 2 +#define MPC52xx_CONSOLE MPC52xx_PSC3 +#define MPC52xx_PSC_CONFIG_SHIFT 8 +#else +#error "MPC52xx_PF_CONSOLE_PORT not defined" +#endif + +static struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE; + +/* The decrementer counts at the system bus clock frequency + * divided by four. The most accurate time base is connected to the + * rtc. We read the decrementer change during one rtc tick (one second) + * and multiply by 4 to get the system bus clock frequency. + */ +int +mpc52xx_ipbfreq(void) +{ + struct mpc52xx_rtc *rtc = (struct mpc52xx_rtc*)MPC52xx_RTC; + struct mpc52xx_cdm *cdm = (struct mpc52xx_cdm*)MPC52xx_CDM; + int current_time, previous_time; + int tbl_start, tbl_end; + int xlbfreq, ipbfreq; + + out_be32(&rtc->dividers, 0x8f1f0000); /* Set RTC 64x faster */ + previous_time = in_be32(&rtc->time); + while ((current_time = in_be32(&rtc->time)) == previous_time) ; + tbl_start = get_tbl(); + previous_time = current_time; + while ((current_time = in_be32(&rtc->time)) == previous_time) ; + tbl_end = get_tbl(); + out_be32(&rtc->dividers, 0xffff0000); /* Restore RTC */ + + xlbfreq = (tbl_end - tbl_start) << 8; + ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? xlbfreq / 2 : xlbfreq; + + return ipbfreq; +} + +unsigned long +serial_init(int ignored, void *ignored2) +{ + struct mpc52xx_gpio *gpio = (struct mpc52xx_gpio *)MPC52xx_GPIO; + int divisor; + int mode1; + int mode2; + u32 val32; + + static int been_here = 0; + + if (been_here) + return 0; + + been_here = 1; + + val32 = in_be32(&gpio->port_config); + val32 &= ~(0x7 << MPC52xx_PSC_CONFIG_SHIFT); + val32 |= MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD + << MPC52xx_PSC_CONFIG_SHIFT; + out_be32(&gpio->port_config, val32); + + out_8(&psc->command, MPC52xx_PSC_RST_TX + | MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command, MPC52xx_PSC_RST_RX); + + out_be32(&psc->sicr, 0x0); + out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); + out_be16(&psc->tfalarm, 0xf8); + + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1 + | MPC52xx_PSC_RX_ENABLE + | MPC52xx_PSC_TX_ENABLE); + + divisor = ((mpc52xx_ipbfreq() + / (CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD * 16)) + 1) >> 1; + + mode1 = MPC52xx_PSC_MODE_8_BITS | MPC52xx_PSC_MODE_PARNONE + | MPC52xx_PSC_MODE_ERR; + mode2 = MPC52xx_PSC_MODE_ONE_STOP; + + out_8(&psc->ctur, divisor>>8); + out_8(&psc->ctlr, divisor); + out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&psc->mode, mode1); + out_8(&psc->mode, mode2); + + return 0; /* ignored */ +} + +void +serial_putc(void *ignored, const char c) +{ + serial_init(0, 0); + + while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ; + out_8(&psc->mpc52xx_psc_buffer_8, c); + while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ; +} + +char +serial_getc(void *ignored) +{ + while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY)) ; + + return in_8(&psc->mpc52xx_psc_buffer_8); +} + +int +serial_tstc(void *ignored) +{ + return (in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY) != 0; +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/configs/lite5200_defconfig 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,436 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y +# +# Processor +# +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E500 is not set +# CONFIG_ALTIVEC is not set +# CONFIG_TAU is not set +# CONFIG_CPU_FREQ is not set +CONFIG_FSL_OCP=y +CONFIG_PPC_STD_MMU=y +# +# Platform options +# +# CONFIG_PPC_MULTIPLATFORM is not set +# CONFIG_APUS is not set +# CONFIG_WILLOW is not set +# CONFIG_PCORE is not set +# CONFIG_POWERPMC250 is not set +# CONFIG_EV64260 is not set +# CONFIG_SPRUCE is not set +# CONFIG_LOPEC is not set +# CONFIG_MCPN765 is not set +# CONFIG_MVME5100 is not set +# CONFIG_PPLUS is not set +# CONFIG_PRPMC750 is not set +# CONFIG_PRPMC800 is not set +# CONFIG_SANDPOINT is not set +# CONFIG_ADIR is not set +# CONFIG_K2 is not set +# CONFIG_PAL4 is not set +# CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set +# CONFIG_SBC82xx is not set +# CONFIG_SBS8260 is not set +# CONFIG_RPX6 is not set +# CONFIG_TQM8260 is not set +# CONFIG_ADS8272 is not set +CONFIG_LITE5200=y +CONFIG_PPC_MPC52xx=y +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HIGHMEM is not set +CONFIG_KERNEL_ELF=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0 root=/dev/ram0 rw" +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_LEGACY_PROC is not set +# CONFIG_PCI_NAMES is not set +# +# Advanced setup +# +CONFIG_ADVANCED_OPTIONS=y +CONFIG_HIGHMEM_START=0xfe000000 +# CONFIG_LOWMEM_SIZE_BOOL is not set +CONFIG_LOWMEM_SIZE=0x30000000 +# CONFIG_KERNEL_START_BOOL is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_TASK_SIZE_BOOL is not set +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_BOOT_LOAD_BOOL is not set +CONFIG_BOOT_LOAD=0x00800000 +# +# Device Drivers +# +# +# Generic Driver Options +# +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# +# Plug and Play support +# +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_LBD is not set +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# +# SCSI device support +# +# CONFIG_SCSI is not set +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# +# Fusion MPT device support +# +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set +# +# I2O device support +# +# CONFIG_I2O is not set +# +# Macintosh device drivers +# +# +# Networking support +# +# CONFIG_NET is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# +# ISDN subsystem +# +# +# Telephony Support +# +# CONFIG_PHONE is not set +# +# Input device support +# +CONFIG_INPUT=y +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_MPC52xx=y +CONFIG_SERIAL_MPC52xx_CONSOLE=y +CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=9600 +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set +# +# I2C support +# +# CONFIG_I2C is not set +# +# Misc devices +# +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# +# Digital Video Broadcasting Devices +# +# +# Graphics support +# +# CONFIG_FB is not set +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +# +# Sound +# +# CONFIG_SOUND is not set +# +# USB support +# +# CONFIG_USB is not set +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set +# +# Library routines +# +# CONFIG_CRC16 is not set +# CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set +# +# Profiling support +# +# CONFIG_PROFILING is not set +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_SPINLOCK_SLEEP=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set +# CONFIG_BDI_SWITCH is not set +CONFIG_DEBUG_INFO=y +CONFIG_SERIAL_TEXT_DEBUG=y +CONFIG_PPC_OCP=y +# +# Security options +# +# CONFIG_SECURITY is not set +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set --- linux-2.6.8-rc1/arch/ppc/defconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/defconfig 2004-07-13 17:09:27.000000000 -0700 @@ -689,7 +689,7 @@ CONFIG_SERIO_SERPORT=y # Input Device Drivers # CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_ATKBD is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set @@ -724,8 +724,8 @@ CONFIG_SERIAL_8250_NR_UARTS=4 # # Non-8250 serial port support # -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_PMACZILOG=y +# CONFIG_SERIAL_CORE is not set +# CONFIG_SERIAL_PMACZILOG is not set # CONFIG_SERIAL_PMACZILOG_CONSOLE is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y --- linux-2.6.8-rc1/arch/ppc/Kconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/Kconfig 2004-07-13 17:09:34.000000000 -0700 @@ -44,18 +44,18 @@ choice default 6xx config 6xx - bool "6xx/7xx/74xx/8260" + bool "6xx/7xx/74xx/52xx/8260" help There are four types of PowerPC chips supported. The more common types (601, 603, 604, 740, 750, 7400), the Motorola embedded - versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions - (403 and 405) and the high end 64 bit Power processors (POWER 3, - POWER4, and IBM 970 also known as G5) + versions (821, 823, 850, 855, 860, 52xx, 8260), the IBM embedded + versions (403 and 405) and the high end 64 bit Power processors + (POWER 3, POWER4, and IBM 970 also known as G5) Unless you are building a kernel for one of the embedded processor systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx. Note that the kernel runs in 32-bit mode even on 64-bit chips. - Also note that because the 82xx family has a 603e core, specific - support for that chipset is asked later on. + Also note that because the 52xx & 82xx family has a 603e core, + specific support for that chipset is asked later on. config 40x bool "40x" @@ -243,6 +243,8 @@ config NOT_COHERENT_CACHE depends on 4xx || 8xx default y +source "drivers/perfctr/Kconfig" + endmenu menu "Platform options" @@ -601,6 +603,15 @@ config TQM8260 config ADS8272 bool "ADS8272" +config LITE5200 + bool "Freescale LITE5200 / (IceCube)" + select PPC_MPC52xx + help + Support for the LITE5200 dev board for the MPC5200 from Freescale. + This is for the LITE5200 version 2.0 board. Don't know if it changes + much but it's only been tested on this board version. I think this + board is also known as IceCube. + endchoice config PQ2ADS @@ -617,6 +628,9 @@ config EMBEDDEDBOOT bool depends on 8xx || 8260 default y + +config PPC_MPC52xx + bool config 8260 bool "CPM2 Support" if WILLOW @@ -707,7 +721,7 @@ config MPC10X_BRIDGE config FSL_OCP bool - depends on MPC10X_BRIDGE + depends on MPC10X_BRIDGE || PPC_MPC52xx default y config MPC10X_OPENPIC @@ -1363,7 +1377,7 @@ config BOOTX_TEXT config SERIAL_TEXT_DEBUG bool "Support for early boot texts over serial port" - depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 + depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550 || PPC_MPC52xx config PPC_OCP bool --- linux-2.6.8-rc1/arch/ppc/kernel/cputable.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/kernel/cputable.c 2004-07-13 17:09:23.000000000 -0700 @@ -351,8 +351,8 @@ struct cpu_spec cpu_specs[] = { 32, 32, __setup_cpu_603 }, - { /* 8280 is a G2_LE (603e core, plus some) */ - 0x7fff0000, 0x00820000, "8280", + { /* 8280 is a G2_LE (603e core, plus some), MPC52xx is a G2_LE too */ + 0x7fff0000, 0x00820000, "8280/MPC52xx", CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP | CPU_FTR_HAS_HIGH_BATS, COMMON_PPC, --- linux-2.6.8-rc1/arch/ppc/kernel/misc.S 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/kernel/misc.S 2004-07-13 17:09:34.000000000 -0700 @@ -1450,3 +1450,9 @@ _GLOBAL(sys_call_table) .long sys_mq_notify .long sys_mq_getsetattr .long sys_ni_syscall /* 268 reserved for sys_kexec_load */ + .long sys_perfctr_info + .long sys_vperfctr_open /* 270 */ + .long sys_vperfctr_control + .long sys_vperfctr_unlink + .long sys_vperfctr_iresume + .long sys_vperfctr_read --- linux-2.6.8-rc1/arch/ppc/kernel/process.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/kernel/process.c 2004-07-13 17:09:34.000000000 -0700 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -301,7 +302,9 @@ struct task_struct *__switch_to(struct t #endif /* CONFIG_SPE */ new_thread = &new->thread; old_thread = ¤t->thread; + perfctr_suspend_thread(&prev->thread); last = _switch(old_thread, new_thread); + perfctr_resume_thread(¤t->thread); local_irq_restore(s); return last; } @@ -370,6 +373,7 @@ void exit_thread(void) last_task_used_math = NULL; if (last_task_used_altivec == current) last_task_used_altivec = NULL; + perfctr_exit_thread(¤t->thread); } void flush_thread(void) @@ -460,6 +464,8 @@ copy_thread(int nr, unsigned long clone_ p->thread.last_syscall = -1; + perfctr_copy_thread(&p->thread); + return 0; } --- linux-2.6.8-rc1/arch/ppc/kernel/smp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/ppc/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -375,8 +375,6 @@ int __cpu_up(unsigned int cpu) p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - wake_up_forked_process(p); - init_idle(p, cpu); unhash_process(p); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/platforms/lite5200.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,152 @@ +/* + * arch/ppc/platforms/lite5200.c + * + * Platform support file for the Freescale LITE5200 based on MPC52xx. + * A maximum of this file should be moved to syslib/mpc52xx_????? + * so that new platform based on MPC52xx need a minimal platform file + * ( avoid code duplication ) + * + * + * Maintainer : Sylvain Munaut + * + * Based on the 2.4 code written by Kent Borg, + * Dale Farnsworth and + * Wolfgang Denk + * + * Copyright 2004 Sylvain Munaut + * Copyright 2003 Motorola Inc. + * Copyright 2003 MontaVista Software Inc. + * Copyright 2003 DENX Software Engineering (wd@denx.de) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Board data given by U-Boot */ +bd_t __res; +EXPORT_SYMBOL(__res); /* For modules */ + + +/* ======================================================================== */ +/* OCP device definition */ +/* For board/shared resources like PSCs */ +/* ======================================================================== */ +/* Be sure not to load conficting devices : e.g. loading the UART drivers for + * PSC1 and then also loading a AC97 for this same PSC. + * For details about how to create an entry, look in the doc of the concerned + * driver ( eg drivers/serial/mpc52xx_uart.c for the PSC in uart mode ) + */ + +struct ocp_def board_ocp[] = { + { + .vendor = OCP_VENDOR_FREESCALE, + .function = OCP_FUNC_PSC_UART, + .index = 0, + .paddr = MPC52xx_PSC1, + .irq = MPC52xx_PSC1_IRQ, + .pm = OCP_CPM_NA, + }, + { /* Terminating entry */ + .vendor = OCP_VENDOR_INVALID + } +}; + + +/* ======================================================================== */ +/* Platform specific code */ +/* ======================================================================== */ + +static int +icecube_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: Freescale LITE5200\n"); + return 0; +} + +static void __init +icecube_setup_arch(void) +{ + + /* Add board OCP definitions */ + mpc52xx_add_board_devices(board_ocp); +} + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* Generic MPC52xx platform initialization */ + /* TODO Create one and move a max of stuff in it. + Put this init in the syslib */ + + struct bi_record *bootinfo = find_bootinfo(); + + if (bootinfo) + parse_bootinfo(bootinfo); + else { + /* Load the bd_t board info structure */ + if (r3) + memcpy((void*)&__res,(void*)(r3+KERNELBASE), + sizeof(bd_t)); + +#ifdef CONFIG_BLK_DEV_INITRD + /* Load the initrd */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif + + /* Load the command line */ + if (r6) { + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + } + + /* BAT setup */ + mpc52xx_set_bat(); + + /* No ISA bus AFAIK */ + isa_io_base = 0; + isa_mem_base = 0; + + /* Setup the ppc_md struct */ + ppc_md.setup_arch = icecube_setup_arch; + ppc_md.show_cpuinfo = icecube_show_cpuinfo; + ppc_md.show_percpuinfo = NULL; + ppc_md.init_IRQ = mpc52xx_init_irq; + ppc_md.get_irq = mpc52xx_get_irq; + + ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory; + ppc_md.setup_io_mappings = mpc52xx_map_io; + + ppc_md.restart = mpc52xx_restart; + ppc_md.power_off = mpc52xx_power_off; + ppc_md.halt = mpc52xx_halt; + + /* No time keeper on the IceCube */ + ppc_md.time_init = NULL; + ppc_md.get_rtc_time = NULL; + ppc_md.set_rtc_time = NULL; + + ppc_md.calibrate_decr = mpc52xx_calibrate_decr; +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = mpc52xx_progress; +#endif +} + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/platforms/lite5200.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,23 @@ +/* + * arch/ppc/platforms/lite5200.h + * + * Definitions for Freescale LITE5200 : MPC52xx Standard Development + * Platform board support + * + * Maintainer : Sylvain Munaut + * + * Copyright (C) 2004 Sylvain Munaut + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __PLATFORMS_LITE5200_H__ +#define __PLATFORMS_LITE5200_H__ + +/* Serial port used for low-level debug */ +#define MPC52xx_PF_CONSOLE_PORT 0 /* PSC1 */ + + +#endif /* __PLATFORMS_LITE5200_H__ */ --- linux-2.6.8-rc1/arch/ppc/platforms/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/platforms/Makefile 2004-07-13 17:09:23.000000000 -0700 @@ -48,6 +48,7 @@ obj-$(CONFIG_PRPMC800) += prpmc800.o obj-$(CONFIG_SANDPOINT) += sandpoint.o obj-$(CONFIG_SBC82xx) += sbc82xx.o obj-$(CONFIG_SPRUCE) += spruce.o +obj-$(CONFIG_LITE5200) += lite5200.o mpc5200.o ifeq ($(CONFIG_SMP),y) obj-$(CONFIG_PPC_PMAC) += pmac_smp.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/platforms/mpc5200.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,29 @@ +/* + * arch/ppc/platforms/mpc5200.c + * + * OCP Definitions for the boards based on MPC5200 processor. Contains + * definitions for every common peripherals. (Mostly all but PSCs) + * + * Maintainer : Sylvain Munaut + * + * Copyright 2004 Sylvain Munaut + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include + +/* Here is the core_ocp struct. + * With all the devices common to all board. Even if port multiplexing is + * not setup for them (if the user don't want them, just don't select the + * config option). The potentially conflicting devices (like PSCs) goes in + * board specific file. + */ +struct ocp_def core_ocp[] = { + { /* Terminating entry */ + .vendor = OCP_VENDOR_INVALID + } +}; --- linux-2.6.8-rc1/arch/ppc/syslib/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/ppc/syslib/Makefile 2004-07-13 17:09:23.000000000 -0700 @@ -86,3 +86,4 @@ obj-$(CONFIG_85xx) += open_pic.o ppc85x ifeq ($(CONFIG_85xx),y) obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o endif +obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/syslib/mpc52xx_pic.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,252 @@ +/* + * arch/ppc/syslib/mpc52xx_pic.c + * + * Programmable Interrupt Controller functions for the Freescale MPC52xx + * embedded CPU. + * + * + * Maintainer : Sylvain Munaut + * + * Based on (well, mostly copied from) the code from the 2.4 kernel by + * Dale Farnsworth and Kent Borg. + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +static struct mpc52xx_intr *intr; +static struct mpc52xx_sdma *sdma; + +static void +mpc52xx_ic_disable(unsigned int irq) +{ + u32 val; + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val &= ~(1 << 11); + out_be32(&intr->ctrl, val); + } + else if (irq < MPC52xx_IRQ1) { + BUG(); + } + else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val &= ~(1 << (10 - (irq - MPC52xx_IRQ1))); + out_be32(&intr->ctrl, val); + } + else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)); + out_be32(&intr->main_mask, val); + } + else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE); + out_be32(&sdma->IntMask, val); + } + else { + val = in_be32(&intr->per_mask); + val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_enable(unsigned int irq) +{ + u32 val; + + if (irq == MPC52xx_IRQ0) { + val = in_be32(&intr->ctrl); + val |= 1 << 11; + out_be32(&intr->ctrl, val); + } + else if (irq < MPC52xx_IRQ1) { + BUG(); + } + else if (irq <= MPC52xx_IRQ3) { + val = in_be32(&intr->ctrl); + val |= 1 << (10 - (irq - MPC52xx_IRQ1)); + out_be32(&intr->ctrl, val); + } + else if (irq < MPC52xx_SDMA_IRQ_BASE) { + val = in_be32(&intr->main_mask); + val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE))); + out_be32(&intr->main_mask, val); + } + else if (irq < MPC52xx_PERP_IRQ_BASE) { + val = in_be32(&sdma->IntMask); + val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + out_be32(&sdma->IntMask, val); + } + else { + val = in_be32(&intr->per_mask); + val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE))); + out_be32(&intr->per_mask, val); + } +} + +static void +mpc52xx_ic_ack(unsigned int irq) +{ + u32 val; + + /* + * Only some irqs are reset here, others in interrupting hardware. + */ + + switch (irq) { + case MPC52xx_IRQ0: + val = in_be32(&intr->ctrl); + val |= 0x08000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_CCS_IRQ: + val = in_be32(&intr->enc_status); + val |= 0x00000400; + out_be32(&intr->enc_status, val); + break; + case MPC52xx_IRQ1: + val = in_be32(&intr->ctrl); + val |= 0x04000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ2: + val = in_be32(&intr->ctrl); + val |= 0x02000000; + out_be32(&intr->ctrl, val); + break; + case MPC52xx_IRQ3: + val = in_be32(&intr->ctrl); + val |= 0x01000000; + out_be32(&intr->ctrl, val); + break; + default: + if (irq >= MPC52xx_SDMA_IRQ_BASE + && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) { + out_be32(&sdma->IntPend, + 1 << (irq - MPC52xx_SDMA_IRQ_BASE)); + } + break; + } +} + +static void +mpc52xx_ic_disable_and_ack(unsigned int irq) +{ + mpc52xx_ic_disable(irq); + mpc52xx_ic_ack(irq); +} + +static void +mpc52xx_ic_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + mpc52xx_ic_enable(irq); +} + +static struct hw_interrupt_type mpc52xx_ic = { + "MPC52xx", + NULL, /* startup(irq) */ + NULL, /* shutdown(irq) */ + mpc52xx_ic_enable, /* enable(irq) */ + mpc52xx_ic_disable, /* disable(irq) */ + mpc52xx_ic_disable_and_ack, /* disable_and_ack(irq) */ + mpc52xx_ic_end, /* end(irq) */ + 0 /* set_affinity(irq, cpumask) SMP. */ +}; + +void __init +mpc52xx_init_irq(void) +{ + int i; + + /* Remap the necessary zones */ + intr = (struct mpc52xx_intr *) + ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr)); + sdma = (struct mpc52xx_sdma *) + ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma)); + + if ((intr==NULL) || (sdma==NULL)) + panic("Can't ioremap PIC/SDMA register for init_irq !"); + + /* Disable all interrupt sources. */ + out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ + out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ + out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ + out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ + out_be32(&intr->ctrl, + 0x0f000000 | /* clear IRQ 0-3 */ + 0x00c00000 | /* IRQ0: level-sensitive, active low */ + 0x00001000 | /* MEE master external enable */ + 0x00000000 | /* 0 means disable IRQ 0-3 */ + 0x00000001); /* CEb route critical normally */ + + /* Zero a bunch of the priority settings. */ + out_be32(&intr->per_pri1, 0); + out_be32(&intr->per_pri2, 0); + out_be32(&intr->per_pri3, 0); + out_be32(&intr->main_pri1, 0); + out_be32(&intr->main_pri2, 0); + + /* Initialize irq_desc[i].handler's with mpc52xx_ic. */ + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].handler = &mpc52xx_ic; + irq_desc[i].status = IRQ_LEVEL; + } +} + +int +mpc52xx_get_irq(struct pt_regs *regs) +{ + u32 status; + int irq = -1; + + status = in_be32(&intr->enc_status); + + if (status & 0x00000400) { /* critical */ + irq = (status >> 8) & 0x3; + if (irq == 2) /* high priority peripheral */ + goto peripheral; + irq += MPC52xx_CRIT_IRQ_BASE; + } + else if (status & 0x00200000) { /* main */ + irq = (status >> 16) & 0x1f; + if (irq == 4) /* low priority peripheral */ + goto peripheral; + irq += MPC52xx_MAIN_IRQ_BASE; + } + else if (status & 0x20000000) { /* peripheral */ +peripheral: + irq = (status >> 24) & 0x1f; + if (irq == 0) { /* bestcomm */ + status = in_be32(&sdma->IntPend); + irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1; + } + else + irq += MPC52xx_PERP_IRQ_BASE; + } + + return irq; +} + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/ppc/syslib/mpc52xx_setup.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,228 @@ +/* + * arch/ppc/syslib/mpc52xx_common.c + * + * Common code for the boards based on Freescale MPC52xx embedded CPU. + * + * + * Maintainer : Sylvain Munaut + * + * Support for other bootloaders than UBoot by Dale Farnsworth + * + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 Montavista Software, Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include + +#include +#include +#include +#include +#include + +extern bd_t __res; + +static int cpu_52xx[] = { + 0, 0, 0, 10, 20, 20, 25, 45, + 30, 55, 40, 50, 0, 60, 35, 0, + 30, 25, 65, 10, 70, 20, 75, 45, + 0, 55, 40, 50, 80, 60, 35, 0 +}; + +void +mpc52xx_restart(char *cmd) +{ + struct mpc52xx_gpt* gpt0 = (struct mpc52xx_gpt*) MPC52xx_GPTx(0); + + local_irq_disable(); + + /* Turn on the watchdog and wait for it to expire. It effectively + does a reset */ + if (gpt0 != NULL) { + out_be32(&gpt0->count, 0x000000ff); + out_be32(&gpt0->mode, 0x00009004); + } else + printk(KERN_ERR "mpc52xx_restart: Unable to ioremap GPT0 registers, -> looping ..."); + + while (1); +} + +void +mpc52xx_halt(void) +{ + local_irq_disable(); + + while (1); +} + +void +mpc52xx_power_off(void) +{ + /* By default we don't have any way of shut down. + If a specific board wants to, it can set the power down + code to any hardware implementation dependent code */ + mpc52xx_halt(); +} + + +void __init +mpc52xx_set_bat(void) +{ + /* Set BAT 2 to map the 0xf0000000 area */ + /* This mapping is used during mpc52xx_progress, + * mpc52xx_find_end_of_memory, and UARTs/GPIO access for debug + */ + mb(); + mtspr(DBAT2U, 0xf0001ffe); + mtspr(DBAT2L, 0xf000002a); + mb(); +} + +void __init +mpc52xx_map_io(void) +{ + /* Here we only map the MBAR */ + io_block_mapping( + MPC52xx_MBAR_VIRT, MPC52xx_MBAR, MPC52xx_MBAR_SIZE, _PAGE_IO); +} + + +#ifdef CONFIG_SERIAL_TEXT_DEBUG +#ifdef MPC52xx_PF_CONSOLE_PORT +#define MPC52xx_CONSOLE MPC52xx_PSCx(MPC52xx_PF_CONSOLE_PORT) +#else +#error "mpc52xx PSC for console not selected" +#endif + +void +mpc52xx_progress(char *s, unsigned short hex) +{ + struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE; + char c; + + /* Don't we need to disable serial interrupts ? */ + + while ((c = *s++) != 0) { + if (c == '\n') { + while (!(in_be16(&psc->mpc52xx_psc_status) & + MPC52xx_PSC_SR_TXRDY)) ; + out_8(&psc->mpc52xx_psc_buffer_8, '\r'); + } + while (!(in_be16(&psc->mpc52xx_psc_status) & + MPC52xx_PSC_SR_TXRDY)) ; + out_8(&psc->mpc52xx_psc_buffer_8, c); + } +} + +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ + + +unsigned long __init +mpc52xx_find_end_of_memory(void) +{ + u32 ramsize = __res.bi_memsize; + + /* + * if bootloader passed a memsize, just use it + * else get size from sdram config registers + */ + if (ramsize == 0) { + struct mpc52xx_mmap_ctl *mmap_ctl; + u32 sdram_config_0, sdram_config_1; + + /* Temp BAT2 mapping active when this is called ! */ + mmap_ctl = (struct mpc52xx_mmap_ctl*) MPC52xx_MMAP_CTL; + + sdram_config_0 = in_be32(&mmap_ctl->sdram0); + sdram_config_1 = in_be32(&mmap_ctl->sdram1); + + if ((sdram_config_0 & 0x1f) >= 0x13) + ramsize = 1 << ((sdram_config_0 & 0xf) + 17); + + if (((sdram_config_1 & 0x1f) >= 0x13) && + ((sdram_config_1 & 0xfff00000) == ramsize)) + ramsize += 1 << ((sdram_config_1 & 0xf) + 17); + + iounmap(mmap_ctl); + } + + return ramsize; +} + +void __init +mpc52xx_calibrate_decr(void) +{ + int current_time, previous_time; + int tbl_start, tbl_end; + unsigned int xlbfreq, cpufreq, ipbfreq, pcifreq, divisor; + + xlbfreq = __res.bi_busfreq; + /* if bootloader didn't pass bus frequencies, calculate them */ + if (xlbfreq == 0) { + /* Get RTC & Clock manager modules */ + struct mpc52xx_rtc *rtc; + struct mpc52xx_cdm *cdm; + + rtc = (struct mpc52xx_rtc*) + ioremap(MPC52xx_RTC, sizeof(struct mpc52xx_rtc)); + cdm = (struct mpc52xx_cdm*) + ioremap(MPC52xx_CDM, sizeof(struct mpc52xx_cdm)); + + if ((rtc==NULL) || (cdm==NULL)) + panic("Can't ioremap RTC/CDM while computing bus freq"); + + /* Count bus clock during 1/64 sec */ + out_be32(&rtc->dividers, 0x8f1f0000); /* Set RTC 64x faster */ + previous_time = in_be32(&rtc->time); + while ((current_time = in_be32(&rtc->time)) == previous_time) ; + tbl_start = get_tbl(); + previous_time = current_time; + while ((current_time = in_be32(&rtc->time)) == previous_time) ; + tbl_end = get_tbl(); + out_be32(&rtc->dividers, 0xffff0000); /* Restore RTC */ + + /* Compute all frequency from that & CDM settings */ + xlbfreq = (tbl_end - tbl_start) << 8; + cpufreq = (xlbfreq * cpu_52xx[in_be32(&cdm->rstcfg) & 0x1f])/10; + ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? + xlbfreq / 2 : xlbfreq; + switch (in_8(&cdm->pci_clk_sel) & 3) { + case 0: + pcifreq = ipbfreq; + break; + case 1: + pcifreq = ipbfreq / 2; + break; + default: + pcifreq = xlbfreq / 4; + break; + } + __res.bi_busfreq = xlbfreq; + __res.bi_intfreq = cpufreq; + __res.bi_ipbfreq = ipbfreq; + __res.bi_pcifreq = pcifreq; + + /* Release mapping */ + iounmap((void*)rtc); + iounmap((void*)cdm); + } + + divisor = 4; + + tb_ticks_per_jiffy = xlbfreq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000); +} + + +void __init +mpc52xx_add_board_devices(struct ocp_def board_ocp[]) { + while (board_ocp->vendor != OCP_VENDOR_INVALID) + if(ocp_add_one_device(board_ocp++)) + printk("mpc5200-ocp: Failed to add board device !\n"); +} + --- linux-2.6.8-rc1/arch/s390/kernel/smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/s390/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -574,9 +574,12 @@ static void __init smp_create_idle(unsig if (IS_ERR(p)) panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - wake_up_forked_process(p); + /* Make this the idle thread */ init_idle(p, cpu); + + /* Remove it from the pidhash */ unhash_process(p); + current_set[cpu] = p; } --- linux-2.6.8-rc1/arch/sh/kernel/smp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sh/kernel/smp.c 2004-07-13 17:09:36.000000000 -0700 @@ -106,8 +106,6 @@ int __cpu_up(unsigned int cpu) if (IS_ERR(tsk)) panic("Failed forking idle task for cpu %d\n", cpu); - wake_up_forked_process(tsk); - init_idle(tsk, cpu); unhash_process(tsk); --- linux-2.6.8-rc1/arch/sparc64/defconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc64/defconfig 2004-07-13 17:09:13.000000000 -0700 @@ -26,6 +26,7 @@ CONFIG_HOTPLUG=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -158,7 +159,6 @@ CONFIG_FB_FFB=y # CONFIG_PROM_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y CONFIG_FONTS=y # CONFIG_FONT_8x8 is not set # CONFIG_FONT_8x16 is not set @@ -333,7 +333,6 @@ CONFIG_AIC79XX_RESET_DELAY_MS=15000 # CONFIG_AIC79XX_DEBUG_ENABLE is not set CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_AIC79XX_REG_PRETTY_PRINT is not set -# CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_MEGARAID is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_SVW=m @@ -687,7 +686,6 @@ CONFIG_NET_SCHED=y CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_CSZ=m CONFIG_NET_SCH_ATM=y CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_RED=m @@ -696,7 +694,7 @@ CONFIG_NET_SCH_TEQL=m CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_GRED=m CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_DELAY=m +CONFIG_NET_SCH_NETEM=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_QOS=y CONFIG_NET_ESTIMATOR=y @@ -782,7 +780,6 @@ CONFIG_IRDA_FAST_RR=y # # CONFIG_USB_IRDA is not set CONFIG_SIGMATEL_FIR=m -# CONFIG_TOSHIBA_FIR is not set # CONFIG_VLSI_FIR is not set CONFIG_BT=m CONFIG_BT_L2CAP=m @@ -793,6 +790,7 @@ CONFIG_BT_BNEP=m CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m # # Bluetooth device drivers @@ -1202,6 +1200,7 @@ CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_ZISOFS is not set CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y # # DOS/FAT/NT Filesystems @@ -1605,6 +1604,7 @@ CONFIG_USB_HPUSBSCSI=m # CONFIG_USB_IBMCAM is not set # CONFIG_USB_KONICAWC is not set # CONFIG_USB_OV511 is not set +CONFIG_USB_PWC=m # CONFIG_USB_SE401 is not set # CONFIG_USB_STV680 is not set CONFIG_USB_W9968CF=m @@ -1775,6 +1775,7 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m @@ -1784,6 +1785,7 @@ CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_CRC_CCITT=m CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y --- linux-2.6.8-rc1/arch/sparc64/Kconfig 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/Kconfig 2004-07-13 17:09:29.000000000 -0700 @@ -687,12 +687,19 @@ config DEBUG_BOOTMEM depends on DEBUG_KERNEL bool "Debug BOOTMEM initialization" +config LOCKMETER + bool "Kernel lock metering" + depends on SMP && !PREEMPT + help + Say Y to enable kernel lock metering, which adds overhead to SMP locks, + but allows you to see various statistics using the lockstat command. + # We have a custom atomic_dec_and_lock() implementation but it's not # compatible with spinlock debugging so we need to fall back on # the generic version in that case. config HAVE_DEC_LOCK bool - depends on SMP && !DEBUG_SPINLOCK + depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER default y config MCOUNT --- linux-2.6.8-rc1/arch/sparc64/kernel/auxio.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/sparc64/kernel/auxio.c 2004-07-13 17:09:13.000000000 -0700 @@ -113,7 +113,7 @@ void auxio_set_lte(int on) void __init auxio_probe(void) { struct sbus_bus *sbus; - struct sbus_dev *sdev = 0; + struct sbus_dev *sdev = NULL; for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { @@ -131,7 +131,7 @@ found_sdev: #ifdef CONFIG_PCI else { struct linux_ebus *ebus; - struct linux_ebus_device *edev = 0; + struct linux_ebus_device *edev = NULL; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { --- linux-2.6.8-rc1/arch/sparc64/kernel/ebus.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/ebus.c 2004-07-13 17:09:13.000000000 -0700 @@ -267,7 +267,7 @@ void ebus_dma_enable(struct ebus_dma_inf } EXPORT_SYMBOL(ebus_dma_enable); -struct linux_ebus *ebus_chain = 0; +struct linux_ebus *ebus_chain = NULL; #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); @@ -503,7 +503,7 @@ probe_interrupts: dev->children = ebus_alloc(sizeof(struct linux_ebus_child)); child = dev->children; - child->next = 0; + child->next = NULL; child->parent = dev; child->bus = dev->bus; fill_ebus_child(node, ®s[0], @@ -513,7 +513,7 @@ probe_interrupts: child->next = ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; - child->next = 0; + child->next = NULL; child->parent = dev; child->bus = dev->bus; fill_ebus_child(node, ®s[0], @@ -563,7 +563,7 @@ void __init ebus_init(void) ebusnd = cookie->prom_node; ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); - ebus->next = 0; + ebus->next = NULL; ebus->is_rio = is_rio; while (ebusnd) { @@ -606,8 +606,8 @@ void __init ebus_init(void) ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); dev = ebus->devices; - dev->next = 0; - dev->children = 0; + dev->next = NULL; + dev->children = NULL; dev->bus = ebus; fill_ebus_device(nd, dev); @@ -615,8 +615,8 @@ void __init ebus_init(void) dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; - dev->next = 0; - dev->children = 0; + dev->next = NULL; + dev->children = NULL; dev->bus = ebus; fill_ebus_device(nd, dev); } @@ -633,7 +633,7 @@ void __init ebus_init(void) ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; - ebus->next = 0; + ebus->next = NULL; ebus->is_rio = is_rio; ++num_ebus; } --- linux-2.6.8-rc1/arch/sparc64/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc64/kernel/irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -1256,6 +1256,6 @@ static void register_irq_proc (unsigned void init_irq_proc (void) { /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); } --- linux-2.6.8-rc1/arch/sparc64/kernel/power.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/arch/sparc64/kernel/power.c 2004-07-13 17:09:13.000000000 -0700 @@ -134,7 +134,7 @@ found: printk("power: Control reg at %016lx ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ if (has_button_interrupt(edev)) { - if (kernel_thread(powerd, 0, CLONE_FS) < 0) { + if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); return; } --- linux-2.6.8-rc1/arch/sparc64/kernel/signal32.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/signal32.c 2004-07-13 17:09:13.000000000 -0700 @@ -461,7 +461,7 @@ asmlinkage void do_rt_sigreturn32(struct err |= restore_fpu_state32(regs, &sf->fpu_state); err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t)); err |= __get_user(u_ss_sp, &sf->stack.ss_sp); - st.ss_sp = (void *) (long) u_ss_sp; + st.ss_sp = compat_ptr(u_ss_sp); err |= __get_user(st.ss_flags, &sf->stack.ss_flags); err |= __get_user(st.ss_size, &sf->stack.ss_size); if (err) @@ -520,7 +520,7 @@ setup_frame32(struct sigaction *sa, stru struct sigcontext32 __user *sc; unsigned int seta[_COMPAT_NSIG_WORDS]; int err = 0; - void *sig_address; + void __user *sig_address; int sig_code; unsigned long pc = regs->tpc; unsigned long npc = regs->tnpc; @@ -1031,7 +1031,7 @@ asmlinkage int svr4_setcontext(svr4_ucon set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32); err |= __get_user(u_ss_sp, &c->stack.sp); - st.ss_sp = (void *) (long) u_ss_sp; + st.ss_sp = compat_ptr(u_ss_sp); err |= __get_user(st.ss_flags, &c->stack.flags); err |= __get_user(st.ss_size, &c->stack.size); if (err) @@ -1360,7 +1360,7 @@ asmlinkage long do_sys32_sigaltstack(u32 __get_user(uss.ss_flags, &((stack_t32 __user *)(long)ussa)->ss_flags) || __get_user(uss.ss_size, &((stack_t32 __user *)(long)ussa)->ss_size))) return -EFAULT; - uss.ss_sp = (void *) (long) u_ss_sp; + uss.ss_sp = compat_ptr(u_ss_sp); old_fs = get_fs(); set_fs(KERNEL_DS); ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL, --- linux-2.6.8-rc1/arch/sparc64/kernel/sys_sparc32.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/sys_sparc32.c 2004-07-13 17:09:13.000000000 -0700 @@ -1293,9 +1293,9 @@ asmlinkage long compat_sys_sigaction(int u32 u_handler, u_restorer; ret = get_user(u_handler, &act->sa_handler); - new_ka.sa.sa_handler = (void *) (long) u_handler; + new_ka.sa.sa_handler = compat_ptr(u_handler); ret |= __get_user(u_restorer, &act->sa_restorer); - new_ka.sa.sa_restorer = (void *) (long) u_restorer; + new_ka.sa.sa_restorer = compat_ptr(u_restorer); ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(mask, &act->sa_mask); if (ret) @@ -1340,7 +1340,7 @@ asmlinkage long compat_sys_rt_sigaction( new_ka.ka_restorer = restorer; ret = get_user(u_handler, &act->sa_handler); - new_ka.sa.sa_handler = (void *) (long) u_handler; + new_ka.sa.sa_handler = compat_ptr(u_handler); ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); switch (_NSIG_WORDS) { case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); @@ -1350,7 +1350,7 @@ asmlinkage long compat_sys_rt_sigaction( } ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(u_restorer, &act->sa_restorer); - new_ka.sa.sa_restorer = (void *) (long) u_restorer; + new_ka.sa.sa_restorer = compat_ptr(u_restorer); if (ret) return -EFAULT; } --- linux-2.6.8-rc1/arch/sparc64/kernel/sys_sparc.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/sys_sparc.c 2004-07-13 17:09:13.000000000 -0700 @@ -448,7 +448,7 @@ asmlinkage void sparc_breakpoint(struct info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGTRAP, &info, current); #ifdef DEBUG_SPARC_BREAKPOINT --- linux-2.6.8-rc1/arch/sparc64/kernel/sys_sunos32.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/sys_sunos32.c 2004-07-13 17:09:13.000000000 -0700 @@ -465,7 +465,7 @@ asmlinkage int sunos_nosys(void) info.si_signo = SIGSYS; info.si_errno = 0; info.si_code = __SI_FAULT|0x100; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = regs->u_regs[UREG_G1]; send_sig_info(SIGSYS, &info, current); if (cnt++ < 4) { @@ -1280,7 +1280,7 @@ asmlinkage int sunos_sigaction (int sig, if (get_user(u_handler, &act->sa_handler) || __get_user(new_ka.sa.sa_flags, &act->sa_flags)) return -EFAULT; - new_ka.sa.sa_handler = (void *) (long) u_handler; + new_ka.sa.sa_handler = compat_ptr(u_handler); __get_user(mask, &act->sa_mask); new_ka.sa.sa_restorer = NULL; new_ka.ka_restorer = NULL; --- linux-2.6.8-rc1/arch/sparc64/kernel/traps.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc64/kernel/traps.c 2004-07-13 17:09:13.000000000 -0700 @@ -93,7 +93,7 @@ void bad_trap (struct pt_regs *regs, lon info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLTRP; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = lvl; force_sig_info(SIGILL, &info, current); } @@ -133,7 +133,7 @@ void instruction_access_exception(struct info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGSEGV, &info, current); } @@ -176,7 +176,7 @@ void data_access_exception (struct pt_re info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; - info.si_addr = (void *)sfar; + info.si_addr = (void __user *)sfar; info.si_trapno = 0; force_sig_info(SIGSEGV, &info, current); } @@ -1617,7 +1617,7 @@ void do_fpe_common(struct pt_regs *regs) } info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; info.si_code = __SI_FAULT; if ((fsr & 0x1c000) == (1 << 14)) { @@ -1672,7 +1672,7 @@ void do_tof(struct pt_regs *regs) info.si_signo = SIGEMT; info.si_errno = 0; info.si_code = EMT_TAGOVF; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGEMT, &info, current); } @@ -1690,7 +1690,7 @@ void do_div0(struct pt_regs *regs) info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = FPE_INTDIV; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGFPE, &info, current); } @@ -1850,7 +1850,7 @@ void do_illegal_instruction(struct pt_re info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; force_sig_info(SIGILL, &info, current); } @@ -1872,7 +1872,7 @@ void mem_address_unaligned(struct pt_reg info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRALN; - info.si_addr = (void *)sfar; + info.si_addr = (void __user *)sfar; info.si_trapno = 0; force_sig_info(SIGBUS, &info, current); } @@ -1888,7 +1888,7 @@ void do_privop(struct pt_regs *regs) info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_PRVOPC; - info.si_addr = (void *)regs->tpc; + info.si_addr = (void __user *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGILL, &info, current); } --- linux-2.6.8-rc1/arch/sparc64/lib/rwlock.S 2003-11-23 19:03:00.000000000 -0800 +++ 25/arch/sparc64/lib/rwlock.S 2004-07-13 17:09:29.000000000 -0700 @@ -85,5 +85,20 @@ __write_trylock_succeed: __write_trylock_fail: retl mov 0, %o0 + + .globl __read_trylock +__read_trylock: /* %o0 = lock_ptr */ + ldsw [%o0], %g5 + brlz,pn %g5, 100f + add %g5, 1, %g7 + cas [%o0], %g5, %g7 + cmp %g5, %g7 + bne,pn %icc, __read_trylock + membar #StoreLoad | #StoreStore + retl + mov 1, %o0 +100: retl + mov 0, %o0 + rwlock_impl_end: --- linux-2.6.8-rc1/arch/sparc64/mm/fault.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc64/mm/fault.c 2004-07-13 17:09:13.000000000 -0700 @@ -218,9 +218,9 @@ static void do_fault_siginfo(int code, i info.si_signo = sig; info.si_errno = 0; if (fault_code & FAULT_CODE_ITLB) - info.si_addr = (void *) regs->tpc; + info.si_addr = (void __user *) regs->tpc; else - info.si_addr = (void *) + info.si_addr = (void __user *) compute_effective_address(regs, insn, 0); info.si_trapno = 0; force_sig_info(sig, &info, current); --- linux-2.6.8-rc1/arch/sparc/defconfig 2004-04-03 20:39:11.000000000 -0800 +++ 25/arch/sparc/defconfig 2004-07-13 17:09:13.000000000 -0700 @@ -19,18 +19,22 @@ CONFIG_BROKEN_ON_SMP=y # CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -171,7 +175,6 @@ CONFIG_CHR_DEV_SG=m # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_REPORT_LUNS=y # CONFIG_SCSI_CONSTANTS is not set # CONFIG_SCSI_LOGGING is not set @@ -190,11 +193,11 @@ CONFIG_SCSI_SPI_ATTRS=m # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set @@ -203,6 +206,7 @@ CONFIG_SCSI_SPI_ATTRS=m # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set @@ -263,8 +267,6 @@ CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set # CONFIG_NETFILTER is not set CONFIG_XFRM=y CONFIG_XFRM_USER=m @@ -279,7 +281,9 @@ CONFIG_SCTP_DBG_OBJCNT=y # CONFIG_SCTP_HMAC_SHA1 is not set CONFIG_SCTP_HMAC_MD5=y # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -300,12 +304,12 @@ CONFIG_SCTP_HMAC_MD5=y # Network testing # CONFIG_NET_PKTGEN=m +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -313,6 +317,11 @@ CONFIG_TUN=m # CONFIG_ETHERTAP is not set # +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -342,7 +351,6 @@ CONFIG_SUNQE=m # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set -# CONFIG_SIS190 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set @@ -350,46 +358,29 @@ CONFIG_SUNQE=m # Ethernet (10000 Mbit) # # CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set +# CONFIG_S2IO is not set # # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support +# Wireless LAN (non-hamradio) # -# CONFIG_IRDA is not set +# CONFIG_NET_RADIO is not set # -# Bluetooth support +# Wan interfaces # -# CONFIG_BT is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set # # Unix98 PTY support @@ -486,6 +477,7 @@ CONFIG_ISO9660_FS=m # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS_XATTR=y # CONFIG_DEVPTS_FS_SECURITY is not set @@ -527,9 +519,9 @@ CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m # CONFIG_SMB_FS is not set CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set CONFIG_AFS_FS=m CONFIG_RXRPC=m @@ -641,11 +633,13 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m # CONFIG_CRYPTO_TEST is not set # # Library routines # CONFIG_CRC32=y +CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y --- linux-2.6.8-rc1/arch/sparc/kernel/ioport.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/arch/sparc/kernel/ioport.c 2004-07-13 17:09:13.000000000 -0700 @@ -41,7 +41,7 @@ #include #include #include -#include +#include #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ @@ -725,7 +725,7 @@ _sparc_find_resource(struct resource *ro void register_proc_sparc_ioport(void) { #ifdef CONFIG_PROC_FS - create_proc_read_entry("io_map",0,0,_sparc_io_get_info,&sparc_iomap); - create_proc_read_entry("dvma_map",0,0,_sparc_io_get_info,&_sparc_dvma); + create_proc_read_entry("io_map",0,NULL,_sparc_io_get_info,&sparc_iomap); + create_proc_read_entry("dvma_map",0,NULL,_sparc_io_get_info,&_sparc_dvma); #endif } --- linux-2.6.8-rc1/arch/sparc/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc/kernel/irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -336,7 +336,7 @@ void handler_irq(int irq, struct pt_regs kstat_cpu(cpu).irqs[irq]++; do { if (!action || !action->handler) - unexpected_irq(irq, 0, regs); + unexpected_irq(irq, NULL, regs); action->handler(irq, action->dev_id, regs); action = action->next; } while (action); --- linux-2.6.8-rc1/arch/sparc/kernel/process.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/kernel/process.c 2004-07-13 17:09:13.000000000 -0700 @@ -628,7 +628,7 @@ int dump_fpu (struct pt_regs * regs, elf ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); if (regs != NULL) { regs->psr &= ~(PSR_EF); - last_task_used_math = 0; + last_task_used_math = NULL; } } #endif --- linux-2.6.8-rc1/arch/sparc/kernel/setup.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc/kernel/setup.c 2004-07-13 17:09:13.000000000 -0700 @@ -234,7 +234,6 @@ extern void sun4c_probe_vac(void); extern char cputypval; extern unsigned long start, end; extern void panic_setup(char *, int *); -extern void srmmu_end_memory(unsigned long, unsigned long *); extern unsigned short root_flags; extern unsigned short root_dev; --- linux-2.6.8-rc1/arch/sparc/kernel/signal.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/kernel/signal.c 2004-07-13 17:09:13.000000000 -0700 @@ -198,7 +198,7 @@ restore_fpu_state(struct pt_regs *regs, regs->psr &= ~PSR_EF; #else if (current == last_task_used_math) { - last_task_used_math = 0; + last_task_used_math = NULL; regs->psr &= ~PSR_EF; } #endif @@ -439,7 +439,7 @@ setup_frame(struct sigaction *sa, struct unsigned long pc = regs->pc; unsigned long npc = regs->npc; struct thread_info *tp = current_thread_info(); - void *sig_address; + void __user *sig_address; int sig_code; synchronize_user_stack(); @@ -570,7 +570,7 @@ save_fpu_state(struct pt_regs *regs, __s put_psr(get_psr() | PSR_EF); fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); - last_task_used_math = 0; + last_task_used_math = NULL; regs->psr &= ~(PSR_EF); } #endif --- linux-2.6.8-rc1/arch/sparc/kernel/sun4c_irq.c 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/sparc/kernel/sun4c_irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -50,7 +50,7 @@ static struct resource sun4c_intr_eb = { * * so don't go making it static, like I tried. sigh. */ -unsigned char *interrupt_enable = 0; +unsigned char *interrupt_enable = NULL; static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 }; --- linux-2.6.8-rc1/arch/sparc/kernel/sun4d_irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc/kernel/sun4d_irq.c 2004-07-13 17:09:13.000000000 -0700 @@ -216,7 +216,7 @@ void sun4d_handler_irq(int irq, struct p if (!sbusl) { action = *(irq + irq_action); if (!action) - unexpected_irq(irq, 0, regs); + unexpected_irq(irq, NULL, regs); do { action->handler(irq, action->dev_id, regs); action = action->next; @@ -243,7 +243,7 @@ void sun4d_handler_irq(int irq, struct p action = actionp->action; if (!action) - unexpected_irq(irq, 0, regs); + unexpected_irq(irq, NULL, regs); do { action->handler(irq, action->dev_id, regs); action = action->next; --- linux-2.6.8-rc1/arch/sparc/kernel/sys_sparc.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/kernel/sys_sparc.c 2004-07-13 17:09:13.000000000 -0700 @@ -375,7 +375,7 @@ sparc_breakpoint (struct pt_regs *regs) info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *)regs->pc; + info.si_addr = (void __user *)regs->pc; info.si_trapno = 0; force_sig_info(SIGTRAP, &info, current); --- linux-2.6.8-rc1/arch/sparc/kernel/sys_sunos.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/kernel/sys_sunos.c 2004-07-13 17:09:13.000000000 -0700 @@ -97,7 +97,7 @@ asmlinkage unsigned long sunos_mmap(unsi iminor(file->f_dentry->d_inode) == 5) { flags |= MAP_ANONYMOUS; fput(file); - file = 0; + file = NULL; } } ret_type = flags & _MAP_NEW; @@ -505,7 +505,7 @@ asmlinkage int sunos_nosys(void) info.si_signo = SIGSYS; info.si_errno = 0; info.si_code = __SI_FAULT|0x100; - info.si_addr = (void *)regs->pc; + info.si_addr = (void __user *)regs->pc; info.si_trapno = regs->u_regs[UREG_G1]; send_sig_info(SIGSYS, &info, current); if (cnt++ < 4) { @@ -755,7 +755,7 @@ sunos_mount(char __user *type, char __us { int linux_flags = 0; int ret = -EINVAL; - char *dev_fname = 0; + char *dev_fname = NULL; char *dir_page, *type_page; if (!capable (CAP_SYS_ADMIN)) --- linux-2.6.8-rc1/arch/sparc/kernel/time.c 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/sparc/kernel/time.c 2004-07-13 17:09:13.000000000 -0700 @@ -54,7 +54,7 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED enum sparc_clock_type sp_clock_typ; spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; unsigned long mstk48t02_regs = 0UL; -static struct mostek48t08 *mstk48t08_regs = 0; +static struct mostek48t08 *mstk48t08_regs = NULL; static int set_rtc_mmss(unsigned long); static int sbus_do_settimeofday(struct timespec *tv); @@ -251,9 +251,9 @@ static __inline__ void sun4_clock_probe( sp_clock_typ = MSTK48T02; r.start = sun4_clock_physaddr; mstk48t02_regs = sbus_ioremap(&r, 0, - sizeof(struct mostek48t02), 0); - mstk48t08_regs = 0; /* To catch weirdness */ - intersil_clock = 0; /* just in case */ + sizeof(struct mostek48t02), NULL); + mstk48t08_regs = NULL; /* To catch weirdness */ + intersil_clock = NULL; /* just in case */ /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) @@ -266,7 +266,7 @@ static __inline__ void sun4_clock_probe( intersil_clock = (struct intersil *) sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil"); mstk48t02_regs = 0; /* just be sure */ - mstk48t08_regs = 0; /* ditto */ + mstk48t08_regs = NULL; /* ditto */ /* initialise the clock */ intersil_intr(intersil_clock,INTERSIL_INT_100HZ); @@ -340,7 +340,7 @@ static __inline__ void clock_probe(void) r.start = clk_reg[0].phys_addr; mstk48t02_regs = sbus_ioremap(&r, 0, sizeof(struct mostek48t02), "mk48t02"); - mstk48t08_regs = 0; /* To catch weirdness */ + mstk48t08_regs = NULL; /* To catch weirdness */ } else if (strcmp(model, "mk48t08") == 0) { sp_clock_typ = MSTK48T08; if(prom_getproperty(node, "reg", (char *) clk_reg, --- linux-2.6.8-rc1/arch/sparc/kernel/traps.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/arch/sparc/kernel/traps.c 2004-07-13 17:09:13.000000000 -0700 @@ -147,7 +147,7 @@ void do_hw_interrupt(struct pt_regs *reg info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLTRP; - info.si_addr = (void *)regs->pc; + info.si_addr = (void __user *)regs->pc; info.si_trapno = type - 0x80; force_sig_info(SIGILL, &info, current); } @@ -170,7 +170,7 @@ void do_illegal_instruction(struct pt_re info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGILL, &info, current); } @@ -185,7 +185,7 @@ void do_priv_instruction(struct pt_regs info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_PRVOPC; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGILL, &info, current); } @@ -354,7 +354,7 @@ void do_fpe_trap(struct pt_regs *regs, u fsr = fpt->thread.fsr; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; info.si_code = __SI_FAULT; if ((fsr & 0x1c000) == (1 << 14)) { @@ -388,7 +388,7 @@ void handle_tag_overflow(struct pt_regs info.si_signo = SIGEMT; info.si_errno = 0; info.si_code = EMT_TAGOVF; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGEMT, &info, current); } @@ -417,7 +417,7 @@ void handle_reg_access(struct pt_regs *r info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_OBJERR; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; force_sig_info(SIGBUS, &info, current); } @@ -430,7 +430,7 @@ void handle_cp_disabled(struct pt_regs * info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_COPROC; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGILL, &info, current); } @@ -447,7 +447,7 @@ void handle_cp_exception(struct pt_regs info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_COPROC; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGILL, &info, current); } @@ -460,7 +460,7 @@ void handle_hw_divzero(struct pt_regs *r info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = FPE_INTDIV; - info.si_addr = (void *)pc; + info.si_addr = (void __user *)pc; info.si_trapno = 0; send_sig_info(SIGFPE, &info, current); } --- linux-2.6.8-rc1/arch/sparc/kernel/unaligned.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/kernel/unaligned.c 2004-07-13 17:09:13.000000000 -0700 @@ -473,7 +473,7 @@ void user_mna_trap_fault(struct pt_regs info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRALN; - info.si_addr = (void *)safe_compute_effective_address(regs, insn); + info.si_addr = (void __user *)safe_compute_effective_address(regs, insn); info.si_trapno = 0; send_sig_info(SIGBUS, &info, current); } --- linux-2.6.8-rc1/arch/sparc/mm/fault.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/mm/fault.c 2004-07-13 17:09:13.000000000 -0700 @@ -326,7 +326,7 @@ bad_area_nosemaphore: info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *) compute_si_addr(regs, text_fault); + info.si_addr = (void __user *)compute_si_addr(regs, text_fault); info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -380,7 +380,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) compute_si_addr(regs, text_fault); + info.si_addr = (void __user *) compute_si_addr(regs, text_fault); info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); if (!from_user) @@ -549,7 +549,7 @@ bad_area: info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -559,7 +559,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *) address; + info.si_addr = (void __user *) address; info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); } --- linux-2.6.8-rc1/arch/sparc/mm/init.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/sparc/mm/init.c 2004-07-13 17:09:13.000000000 -0700 @@ -100,7 +100,7 @@ void __init sparc_context_init(int numct clist = (ctx_list_pool + ctx); clist->ctx_number = ctx; - clist->ctx_mm = 0; + clist->ctx_mm = NULL; } ctx_free.next = ctx_free.prev = &ctx_free; ctx_used.next = ctx_used.prev = &ctx_used; --- linux-2.6.8-rc1/arch/sparc/mm/iommu.c 2004-01-09 00:04:31.000000000 -0800 +++ 25/arch/sparc/mm/iommu.c 2004-07-13 17:09:13.000000000 -0700 @@ -25,6 +25,7 @@ #include #include #include +#include /* * This can be sized dynamically, but we will do this --- linux-2.6.8-rc1/arch/sparc/mm/io-unit.c 2004-01-09 00:04:31.000000000 -0800 +++ 25/arch/sparc/mm/io-unit.c 2004-07-13 17:09:13.000000000 -0700 @@ -22,6 +22,7 @@ #include #include #include +#include /* #define IOUNIT_DEBUG */ #ifdef IOUNIT_DEBUG --- linux-2.6.8-rc1/arch/sparc/mm/nosrmmu.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/sparc/mm/nosrmmu.c 2004-07-13 17:09:13.000000000 -0700 @@ -9,10 +9,12 @@ #include #include #include +#include static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n"; enum mbus_module srmmu_modtype; +void *srmmu_nocache_pool; int vac_cache_size = 0; @@ -46,11 +48,6 @@ void srmmu_unmapioaddr(unsigned long vir { } -void __init srmmu_end_memory(unsigned long memory_size, unsigned long *mem_end_p) -{ - return 0; -} - __u32 iounit_map_dma_init(struct sbus_bus *sbus, int size) { return 0; --- linux-2.6.8-rc1/arch/sparc/mm/sun4c.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/sparc/mm/sun4c.c 2004-07-13 17:09:13.000000000 -0700 @@ -497,7 +497,7 @@ static void __init sun4c_probe_mmu(void) patch_kernel_fault_handler(); } -volatile unsigned long *sun4c_memerr_reg = 0; +volatile unsigned long *sun4c_memerr_reg = NULL; void __init sun4c_probe_memerr_reg(void) { @@ -599,13 +599,13 @@ static void __init sun4c_init_mmu_entry_ for (i=0; i < SUN4C_MAX_SEGMAPS; i++) { mmu_entry_pool[i].pseg = i; - mmu_entry_pool[i].next = 0; - mmu_entry_pool[i].prev = 0; + mmu_entry_pool[i].next = NULL; + mmu_entry_pool[i].prev = NULL; mmu_entry_pool[i].vaddr = 0; mmu_entry_pool[i].locked = 0; mmu_entry_pool[i].ctx = 0; - mmu_entry_pool[i].lru_next = 0; - mmu_entry_pool[i].lru_prev = 0; + mmu_entry_pool[i].lru_next = NULL; + mmu_entry_pool[i].lru_prev = NULL; } mmu_entry_pool[invalid_segment].locked = 1; } @@ -1170,7 +1170,7 @@ abend: local_irq_restore(flags); printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size); panic("Out of iobuffer table"); - return 0; + return NULL; } static void sun4c_unlockarea(char *vaddr, unsigned long size) --- linux-2.6.8-rc1/arch/um/config.release 2003-08-08 22:55:11.000000000 -0700 +++ 25/arch/um/config.release 2004-07-13 17:09:44.000000000 -0700 @@ -228,7 +228,6 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m CONFIG_UDF_FS=m -# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set --- linux-2.6.8-rc1/arch/um/defconfig 2003-08-08 22:55:11.000000000 -0700 +++ 25/arch/um/defconfig 2004-07-13 17:09:44.000000000 -0700 @@ -3,29 +3,19 @@ # CONFIG_USERMODE=y CONFIG_MMU=y -CONFIG_SWAP=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_CONFIG_LOG_BUF_SHIFT=14 # -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General Setup +# UML-specific options # CONFIG_MODE_TT=y CONFIG_MODE_SKAS=y CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_HOSTFS=y +CONFIG_HPPFS=y CONFIG_MCONSOLE=y CONFIG_MAGIC_SYSRQ=y # CONFIG_HOST_2G_2G is not set @@ -36,12 +26,43 @@ CONFIG_KERNEL_HALF_GIGS=1 # CONFIG_HIGHMEM is not set CONFIG_PROC_MM=y CONFIG_KERNEL_STACK_ORDER=2 +CONFIG_UML_REAL_TIME_CLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support # -CONFIG_MODULES=y -# CONFIG_KMOD is not set +# CONFIG_MODULES is not set + +# +# Generic Driver Options +# # # Character Devices @@ -69,6 +90,7 @@ CONFIG_HOSTAUDIO=y # CONFIG_BLK_DEV_UBD=y # CONFIG_BLK_DEV_UBD_SYNC is not set +CONFIG_BLK_DEV_COW_COMMON=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y @@ -78,7 +100,7 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_NETDEVICES=y # -# Network Devices +# UML Network Devices # CONFIG_UML_NET=y CONFIG_UML_NET_ETHERTAP=y @@ -88,22 +110,6 @@ CONFIG_UML_NET_DAEMON=y CONFIG_UML_NET_MCAST=y # CONFIG_UML_NET_PCAP is not set CONFIG_UML_NET_SLIRP=y -CONFIG_DUMMY=y -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=y -# CONFIG_ETHERTAP is not set -CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set -# CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPPOE is not set -CONFIG_SLIP=y -# CONFIG_SLIP_COMPRESSED is not set -# CONFIG_SLIP_SMART is not set -# CONFIG_SLIP_MODE_SLIP6 is not set # # Networking support @@ -115,8 +121,6 @@ CONFIG_SLIP=y CONFIG_PACKET=y CONFIG_PACKET_MMAP=y # CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -130,8 +134,11 @@ CONFIG_INET=y # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set -# CONFIG_XFRM_USER is not set +# CONFIG_INET_IPCOMP is not set # CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER is not set # # SCTP Configuration (EXPERIMENTAL) @@ -140,9 +147,9 @@ CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_NET_DIVERT is not set @@ -160,6 +167,10 @@ CONFIG_IPV6_SCTP__=y # Network testing # # CONFIG_NET_PKTGEN is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y # # Ethernet (10 or 100Mbit) @@ -171,12 +182,28 @@ CONFIG_IPV6_SCTP__=y # # +# Ethernet (10000 Mbit) +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +# CONFIG_SLIP_COMPRESSED is not set +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set + +# # Wireless LAN (non-hamradio) # # CONFIG_NET_RADIO is not set # -# Token Ring devices (depends on LLC=y) +# Token Ring devices # # CONFIG_SHAPER is not set @@ -186,68 +213,100 @@ CONFIG_IPV6_SCTP__=y # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# # File systems # +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +CONFIG_MINIX_FS=y +# CONFIG_ROMFS_FS is not set CONFIG_QUOTA=y # CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V2 is not set CONFIG_QUOTACTL=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set CONFIG_JFFS_FS=y CONFIG_JFFS_FS_VERBOSE=0 -CONFIG_JFFS_PROC_FS=y # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -CONFIG_RAMFS=y -CONFIG_ISO9660_FS=m -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_JFS_FS is not set -CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set -# CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set # CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_XFS_FS is not set # # Network File Systems # -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_NFS_FS is not set # CONFIG_NFSD is not set # CONFIG_EXPORTFS is not set -# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set # CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # @@ -255,11 +314,11 @@ CONFIG_EXT2_FS=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set @@ -317,28 +376,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # # SCSI support # -CONFIG_SCSI=y -CONFIG_GENERIC_ISA_DMA=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_SR_EXTRA_DEVS=2 -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -CONFIG_SCSI_DEBUG_QUEUES=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_DEBUG=y +# CONFIG_SCSI is not set # # Multi-device support (RAID and LVM) @@ -360,6 +398,7 @@ CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set +# CONFIG_INFTL is not set # # RAM/ROM/Flash chip drivers @@ -374,20 +413,21 @@ CONFIG_MTD_BLOCK=y # # Mapping drivers for chip access # +# CONFIG_MTD_COMPLEX_MAPPINGS is not set # # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set -CONFIG_MTD_BLKMTD=m +CONFIG_MTD_BLKMTD=y # # Disk-On-Chip Device Drivers # -# CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set # # NAND Flash Device Drivers --- linux-2.6.8-rc1/arch/um/drivers/chan_kern.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/arch/um/drivers/chan_kern.c 2004-07-13 17:09:47.000000000 -0700 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "chan_kern.h" @@ -16,6 +17,7 @@ #include "irq_user.h" #include "sigio.h" #include "line.h" +#include "os.h" static void *not_configged_init(char *str, int device, struct chan_opts *opts) { @@ -86,6 +88,52 @@ static struct chan_ops not_configged_ops .winch = 0, }; +void generic_close(int fd, void *unused) +{ + os_close_file(fd); +} + +int generic_read(int fd, char *c_out, void *unused) +{ + int n; + + n = os_read_file(fd, c_out, sizeof(*c_out)); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-EIO); + return(n); +} + +int generic_write(int fd, const char *buf, int n, void *unused) +{ + return(os_write_file(fd, buf, n)); +} + +int generic_window_size(int fd, void *unused, unsigned short *rows_out, + unsigned short *cols_out) +{ + int rows, cols; + int ret; + + ret = os_window_size(fd, &rows, &cols); + if(ret < 0) + return(ret); + + ret = ((*rows_out != rows) || (*cols_out != cols)); + + *rows_out = rows; + *cols_out = cols; + + return(ret); +} + +void generic_free(void *data) +{ + kfree(data); +} + static void tty_receive_char(struct tty_struct *tty, char ch) { if(tty == NULL) return; @@ -265,6 +313,11 @@ static int one_chan_config_string(struct { int n = 0; + if(chan == NULL){ + CONFIG_CHUNK(str, size, n, "none", 1); + return(n); + } + CONFIG_CHUNK(str, size, n, chan->ops->type, 0); if(chan->dev == NULL){ @@ -420,7 +473,8 @@ int parse_chan_pair(char *str, struct li INIT_LIST_HEAD(chans); } - if((out = strchr(str, ',')) != NULL){ + out = strchr(str, ','); + if(out != NULL){ in = str; *out = '\0'; out++; @@ -475,12 +529,15 @@ void chan_interrupt(struct list_head *ch goto out; } err = chan->ops->read(chan->fd, &c, chan->data); - if(err > 0) tty_receive_char(tty, c); + if(err > 0) + tty_receive_char(tty, c); } while(err > 0); + if(err == 0) reactivate_fd(chan->fd, irq); if(err == -EIO){ if(chan->primary){ - if(tty != NULL) tty_hangup(tty); + if(tty != NULL) + tty_hangup(tty); line_disable(dev, irq); close_chan(chans); free_chan(chans); --- linux-2.6.8-rc1/arch/um/drivers/chan_user.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/drivers/chan_user.c 2004-07-13 17:09:47.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -22,33 +21,6 @@ #include "choose-mode.h" #include "mode.h" -void generic_close(int fd, void *unused) -{ - close(fd); -} - -int generic_read(int fd, char *c_out, void *unused) -{ - int n; - - n = read(fd, c_out, sizeof(*c_out)); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-EIO); - return(1); -} - -int generic_write(int fd, const char *buf, int n, void *unused) -{ - int count; - - count = write(fd, buf, n); - if(count < 0) return(-errno); - return(count); -} - int generic_console_write(int fd, const char *buf, int n, void *unused) { struct termios save, new; @@ -65,26 +37,6 @@ int generic_console_write(int fd, const return(err); } -int generic_window_size(int fd, void *unused, unsigned short *rows_out, - unsigned short *cols_out) -{ - struct winsize size; - int ret = 0; - - if(ioctl(fd, TIOCGWINSZ, &size) == 0){ - ret = ((*rows_out != size.ws_row) || - (*cols_out != size.ws_col)); - *rows_out = size.ws_row; - *cols_out = size.ws_col; - } - return(ret); -} - -void generic_free(void *data) -{ - kfree(data); -} - static void winch_handler(int sig) { } @@ -100,14 +52,16 @@ static int winch_thread(void *arg) struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; + int count, err; char c = 1; - close(data->close_me); + os_close_file(data->close_me); pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to write synchronization " - "byte, errno = %d\n", errno); + "byte, err = %d\n", -count); signal(SIGWINCH, winch_handler); sigfillset(&sigs); @@ -123,26 +77,24 @@ static int winch_thread(void *arg) exit(1); } - if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){ - printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno); - exit(1); - } - if(tcsetpgrp(pty_fd, os_getpid()) < 0){ - printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno); + err = os_new_tty_pgrp(pty_fd, os_getpid()); + if(err < 0){ + printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); exit(1); } - if(read(pipe_fd, &c, sizeof(c)) != sizeof(c)) + count = os_read_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " - "errno = %d\n", errno); + "err = %d\n", -count); while(1){ pause(); - if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){ - printk("winch_thread : write failed, errno = %d\n", - errno); - } + count = os_write_file(pipe_fd, &c, sizeof(c)); + if(count != sizeof(c)) + printk("winch_thread : write failed, err = %d\n", + -count); } } @@ -154,8 +106,8 @@ static int winch_tramp(int fd, void *dev char c; err = os_pipe(fds, 1, 1); - if(err){ - printk("winch_tramp : os_pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("winch_tramp : os_pipe failed, err = %d\n", -err); return(err); } @@ -168,12 +120,12 @@ static int winch_tramp(int fd, void *dev return(pid); } - close(fds[1]); + os_close_file(fds[1]); *fd_out = fds[0]; - n = read(fds[0], &c, sizeof(c)); + n = os_read_file(fds[0], &c, sizeof(c)); if(n != sizeof(c)){ printk("winch_tramp : failed to read synchronization byte\n"); - printk("read returned %d, errno = %d\n", n, errno); + printk("read failed, err = %d\n", -n); printk("fd %d will not support SIGWINCH\n", fd); *fd_out = -1; } @@ -183,20 +135,24 @@ static int winch_tramp(int fd, void *dev void register_winch(int fd, void *device_data) { int pid, thread, thread_fd; + int count; char c = 1; - if(!isatty(fd)) return; + if(!isatty(fd)) + return; pid = tcgetpgrp(fd); - if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && - (pid == -1)){ + if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, + device_data) && (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); if(fd != -1){ register_winch_irq(thread_fd, fd, thread, device_data); - if(write(thread_fd, &c, sizeof(c)) != sizeof(c)) + count = os_write_file(thread_fd, &c, sizeof(c)); + if(count != sizeof(c)) printk("register_winch : failed to write " - "synchronization byte\n"); + "synchronization byte, err = %d\n", + -count); } } } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/drivers/cow.h 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,41 @@ +#ifndef __COW_H__ +#define __COW_H__ + +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +# define ntohll(x) (x) +# define htonll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define ntohll(x) bswap_64(x) +# define htonll(x) bswap_64(x) +#else +#error "__BYTE_ORDER not defined" +#endif + +extern int init_cow_file(int fd, char *cow_file, char *backing_file, + int sectorsize, int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out); + +extern int file_reader(__u64 offset, char *buf, int len, void *arg); +extern int read_cow_header(int (*reader)(__u64, char *, int, void *), + void *arg, __u32 *version_out, + char **backing_file_out, time_t *mtime_out, + __u64 *size_out, int *sectorsize_out, + __u32 *align_out, int *bitmap_offset_out); + +extern int write_cow_header(char *cow_file, int fd, char *backing_file, + int sectorsize, int alignment, long long *size); + +extern void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out); + +#endif + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/drivers/cow_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,630 @@ +#define COW_MAJOR 60 +#define MAJOR_NR COW_MAJOR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "2_5compat.h" +#include "cow.h" +#include "ubd_user.h" + +#define COW_SHIFT 4 + +struct cow { + int count; + char *cow_path; + dev_t cow_dev; + struct block_device *cow_bdev; + char *backing_path; + dev_t backing_dev; + struct block_device *backing_bdev; + int sectorsize; + unsigned long *bitmap; + unsigned long bitmap_len; + int bitmap_offset; + int data_offset; + devfs_handle_t devfs; + struct semaphore sem; + struct semaphore io_sem; + atomic_t working; + spinlock_t io_lock; + struct buffer_head *bh; + struct buffer_head *bhtail; + void *end_io; +}; + +#define DEFAULT_COW { \ + .count = 0, \ + .cow_path = NULL, \ + .cow_dev = 0, \ + .backing_path = NULL, \ + .backing_dev = 0, \ + .bitmap = NULL, \ + .bitmap_len = 0, \ + .bitmap_offset = 0, \ + .data_offset = 0, \ + .devfs = NULL, \ + .working = ATOMIC_INIT(0), \ + .io_lock = SPIN_LOCK_UNLOCKED, \ +} + +#define MAX_DEV (8) +#define MAX_MINOR (MAX_DEV << COW_SHIFT) + +struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW }; + +/* Not modified by this driver */ +static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE }; +static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 }; + +/* Protected by cow_lock */ +static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 }; + +static struct hd_struct cow_part[MAX_MINOR] = + { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } }; + +/* Protected by io_request_lock */ +static request_queue_t *cow_queue; + +static int cow_open(struct inode *inode, struct file *filp); +static int cow_release(struct inode * inode, struct file * file); +static int cow_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +static int cow_revalidate(kdev_t rdev); + +static struct block_device_operations cow_blops = { + .open = cow_open, + .release = cow_release, + .ioctl = cow_ioctl, + .revalidate = cow_revalidate, +}; + +/* Initialized in an initcall, and unchanged thereafter */ +devfs_handle_t cow_dir_handle; + +#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \ +{ \ + .major = maj, \ + .major_name = name, \ + .minor_shift = shift, \ + .max_p = 1 << shift, \ + .part = parts, \ + .sizes = bsizes, \ + .nr_real = max, \ + .real_devices = NULL, \ + .next = NULL, \ + .fops = blops, \ + .de_arr = NULL, \ + .flags = 0 \ +} + +static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED; + +static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part, + COW_SHIFT, sizes, MAX_DEV, + &cow_blops); + +static int cow_add(int n) +{ + struct cow *dev = &cow_dev[n]; + char name[sizeof("nnnnnn\0")]; + int err = -ENODEV; + + if(dev->cow_path == NULL) + goto out; + + sprintf(name, "%d", n); + dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE, + MAJOR_NR, n << COW_SHIFT, S_IFBLK | + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + &cow_blops, NULL); + + init_MUTEX_LOCKED(&dev->sem); + init_MUTEX(&dev->io_sem); + + return(0); + + out: + return(err); +} + +/* + * Add buffer_head to back of pending list + */ +static void cow_add_bh(struct cow *cow, struct buffer_head *bh) +{ + unsigned long flags; + + spin_lock_irqsave(&cow->io_lock, flags); + if(cow->bhtail != NULL){ + cow->bhtail->b_reqnext = bh; + cow->bhtail = bh; + } + else { + cow->bh = bh; + cow->bhtail = bh; + } + spin_unlock_irqrestore(&cow->io_lock, flags); +} + +/* +* Grab first pending buffer +*/ +static struct buffer_head *cow_get_bh(struct cow *cow) +{ + struct buffer_head *bh; + + spin_lock_irq(&cow->io_lock); + bh = cow->bh; + if(bh != NULL){ + if(bh == cow->bhtail) + cow->bhtail = NULL; + cow->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + } + spin_unlock_irq(&cow->io_lock); + + return(bh); +} + +static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, + struct buffer_head **cow_bh, int ncow_bh) +{ + int i; + + if(ncow_bh > 0) + ll_rw_block(WRITE, ncow_bh, cow_bh); + + for(i = 0; i < ncow_bh ; i++){ + wait_on_buffer(cow_bh[i]); + brelse(cow_bh[i]); + } + + ll_rw_block(WRITE, 1, &bh); + brelse(bh); +} + +static struct buffer_head *cow_new_bh(struct cow *dev, int sector) +{ + struct buffer_head *bh; + + sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize; + bh = getblk(dev->cow_dev, sector, dev->sectorsize); + memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])), + dev->sectorsize); + return(bh); +} + +/* Copied from loop.c, needed to avoid deadlocking in make_request. */ + +static int cow_thread(void *data) +{ + struct cow *dev = data; + struct buffer_head *bh; + + daemonize(); + exit_files(current); + + sprintf(current->comm, "cow%d", dev - cow_dev); + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + + atomic_inc(&dev->working); + + current->policy = SCHED_OTHER; + current->nice = -20; + + current->flags |= PF_NOIO; + + /* + * up sem, we are running + */ + up(&dev->sem); + + for(;;){ + int start, len, nbh, i, update_bitmap = 0; + struct buffer_head *cow_bh[2]; + + down_interruptible(&dev->io_sem); + /* + * could be upped because of tear-down, not because of + * pending work + */ + if(!atomic_read(&dev->working)) + break; + + bh = cow_get_bh(dev); + if(bh == NULL){ + printk(KERN_ERR "cow: missing bh\n"); + continue; + } + + start = bh->b_blocknr * bh->b_size / dev->sectorsize; + len = bh->b_size / dev->sectorsize; + for(i = 0; i < len ; i++){ + if(ubd_test_bit(start + i, + (unsigned char *) dev->bitmap)) + continue; + + update_bitmap = 1; + ubd_set_bit(start + i, (unsigned char *) dev->bitmap); + } + + cow_bh[0] = NULL; + cow_bh[1] = NULL; + nbh = 0; + if(update_bitmap){ + cow_bh[0] = cow_new_bh(dev, start); + nbh++; + if(start / dev->sectorsize != + (start + len) / dev->sectorsize){ + cow_bh[1] = cow_new_bh(dev, start + len); + nbh++; + } + } + + bh->b_dev = dev->cow_dev; + bh->b_blocknr += dev->data_offset / dev->sectorsize; + + cow_handle_bh(dev, bh, cow_bh, nbh); + + /* + * upped both for pending work and tear-down, lo_pending + * will hit zero then + */ + if(atomic_dec_and_test(&dev->working)) + break; + } + + up(&dev->sem); + return(0); +} + +static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh) +{ + struct cow *dev; + int n, minor; + + minor = MINOR(bh->b_rdev); + n = minor >> COW_SHIFT; + dev = &cow_dev[n]; + + dev->end_io = NULL; + if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){ + bh->b_rdev = dev->cow_dev; + bh->b_rsector += dev->data_offset / dev->sectorsize; + } + else if(rw == WRITE){ + bh->b_dev = dev->cow_dev; + bh->b_blocknr += dev->data_offset / dev->sectorsize; + + cow_add_bh(dev, bh); + up(&dev->io_sem); + return(0); + } + else { + bh->b_rdev = dev->backing_dev; + } + + return(1); +} + +int cow_init(void) +{ + int i; + + cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL); + if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) { + printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR); + return -1; + } + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + blksize_size[MAJOR_NR] = blk_sizes; + blk_size[MAJOR_NR] = sizes; + INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes); + + cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR); + blk_init_queue(cow_queue, NULL); + INIT_ELV(cow_queue, &cow_queue->elevator); + blk_queue_make_request(cow_queue, cow_make_request); + + add_gendisk(&cow_gendisk); + + for(i=0;i 0){ + n = (left > blocksize) ? blocksize : left; + + bh = bread(dev, block, (n < 512) ? 512 : n); + if(bh == NULL) + return(-EIO); + + n -= offset; + memcpy(&buf[cur], bh->b_data + offset, n); + block++; + left -= n; + cur += n; + offset = 0; + brelse(bh); + } + + return(count); +} + +static int cow_open(struct inode *inode, struct file *filp) +{ + int (*dev_ioctl)(struct inode *, struct file *, unsigned int, + unsigned long); + mm_segment_t fs; + struct cow *dev; + __u64 size; + __u32 version, align; + time_t mtime; + char *backing_file; + int n, offset, err = 0; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + offset = n << COW_SHIFT; + + spin_lock(&cow_lock); + + if(dev->count == 0){ + dev->cow_dev = name_to_kdev_t(dev->cow_path); + if(dev->cow_dev == 0){ + printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") " + "failed\n", dev->cow_path); + err = -ENODEV; + } + + dev->backing_dev = name_to_kdev_t(dev->backing_path); + if(dev->backing_dev == 0){ + printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") " + "failed\n", dev->backing_path); + err = -ENODEV; + } + + if(err) + goto out; + + dev->cow_bdev = bdget(dev->cow_dev); + if(dev->cow_bdev == NULL){ + printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", + dev->cow_path); + err = -ENOMEM; + } + dev->backing_bdev = bdget(dev->backing_dev); + if(dev->backing_bdev == NULL){ + printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", + dev->backing_path); + err = -ENOMEM; + } + + if(err) + goto out; + + err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, + BDEV_RAW); + if(err){ + printk("cow_open - blkdev_get of COW device failed, " + "error = %d\n", err); + goto out; + } + + err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW); + if(err){ + printk("cow_open - blkdev_get of backing device " + "failed, error = %d\n", err); + goto out; + } + + err = read_cow_header(reader, &dev->cow_dev, &version, + &backing_file, &mtime, &size, + &dev->sectorsize, &align, + &dev->bitmap_offset); + if(err){ + printk(KERN_ERR "cow_open - read_cow_header failed, " + "err = %d\n", err); + goto out; + } + + cow_sizes(version, size, dev->sectorsize, align, + dev->bitmap_offset, &dev->bitmap_len, + &dev->data_offset); + dev->bitmap = (void *) vmalloc(dev->bitmap_len); + if(dev->bitmap == NULL){ + err = -ENOMEM; + printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); + goto out; + } + flush_tlb_kernel_vm(); + + err = reader(dev->bitmap_offset, (char *) dev->bitmap, + dev->bitmap_len, &dev->cow_dev); + if(err < 0){ + printk(KERN_ERR "Failed to read COW bitmap\n"); + vfree(dev->bitmap); + goto out; + } + + dev_ioctl = dev->backing_bdev->bd_op->ioctl; + fs = get_fs(); + set_fs(KERNEL_DS); + err = (*dev_ioctl)(inode, filp, BLKGETSIZE, + (unsigned long) &sizes[offset]); + set_fs(fs); + if(err){ + printk(KERN_ERR "cow_open - BLKGETSIZE failed, " + "error = %d\n", err); + goto out; + } + + kernel_thread(cow_thread, dev, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + down(&dev->sem); + } + dev->count++; + out: + spin_unlock(&cow_lock); + return(err); +} + +static int cow_release(struct inode * inode, struct file * file) +{ + struct cow *dev; + int n, err; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + + spin_lock(&cow_lock); + + if(--dev->count > 0) + goto out; + + err = blkdev_put(dev->cow_bdev, BDEV_RAW); + if(err) + printk("cow_release - blkdev_put of cow device failed, " + "error = %d\n", err); + bdput(dev->cow_bdev); + dev->cow_bdev = 0; + + err = blkdev_put(dev->backing_bdev, BDEV_RAW); + if(err) + printk("cow_release - blkdev_put of backing device failed, " + "error = %d\n", err); + bdput(dev->backing_bdev); + dev->backing_bdev = 0; + + out: + spin_unlock(&cow_lock); + return(0); +} + +static int cow_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct cow *dev; + int (*dev_ioctl)(struct inode *, struct file *, unsigned int, + unsigned long); + int n; + + n = DEVICE_NR(inode->i_rdev); + if(n >= MAX_DEV) + return(-ENODEV); + dev = &cow_dev[n]; + + dev_ioctl = dev->backing_bdev->bd_op->ioctl; + return((*dev_ioctl)(inode, file, cmd, arg)); +} + +static int cow_revalidate(kdev_t rdev) +{ + printk(KERN_ERR "Need to implement cow_revalidate\n"); + return(0); +} + +static int parse_unit(char **ptr) +{ + char *str = *ptr, *end; + int n = -1; + + if(isdigit(*str)) { + n = simple_strtoul(str, &end, 0); + if(end == str) + return(-1); + *ptr = end; + } + else if (('a' <= *str) && (*str <= 'h')) { + n = *str - 'a'; + str++; + *ptr = str; + } + return(n); +} + +static int cow_setup(char *str) +{ + struct cow *dev; + char *cow_name, *backing_name; + int unit; + + unit = parse_unit(&str); + if(unit < 0){ + printk(KERN_ERR "cow_setup - Couldn't parse unit number\n"); + return(1); + } + + if(*str != '='){ + printk(KERN_ERR "cow_setup - Missing '=' after unit " + "number\n"); + return(1); + } + str++; + + cow_name = str; + backing_name = strchr(str, ','); + if(backing_name == NULL){ + printk(KERN_ERR "cow_setup - missing backing device name\n"); + return(0); + } + *backing_name = '\0'; + backing_name++; + + spin_lock(&cow_lock); + + dev = &cow_dev[unit]; + dev->cow_path = cow_name; + dev->backing_path = backing_name; + + spin_unlock(&cow_lock); + return(0); +} + +__setup("cow", cow_setup); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/drivers/cow_sys.h 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,48 @@ +#ifndef __COW_SYS_H__ +#define __COW_SYS_H__ + +#include "kern_util.h" +#include "user_util.h" +#include "os.h" +#include "user.h" + +static inline void *cow_malloc(int size) +{ + return(um_kmalloc(size)); +} + +static inline void cow_free(void *ptr) +{ + kfree(ptr); +} + +#define cow_printf printk + +static inline char *cow_strdup(char *str) +{ + return(uml_strdup(str)); +} + +static inline int cow_seek_file(int fd, __u64 offset) +{ + return(os_seek_file(fd, offset)); +} + +static inline int cow_file_size(char *file, __u64 *size_out) +{ + return(os_file_size(file, size_out)); +} + +static inline int cow_write_file(int fd, char *buf, int size) +{ + return(os_write_file(fd, buf, size)); +} + +#endif + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/drivers/cow_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "os.h" + +#include "cow.h" +#include "cow_sys.h" + +#define PATH_LEN_V1 256 + +struct cow_header_v1 { + int magic; + int version; + char backing_file[PATH_LEN_V1]; + time_t mtime; + __u64 size; + int sectorsize; +}; + +#define PATH_LEN_V2 MAXPATHLEN + +struct cow_header_v2 { + unsigned long magic; + unsigned long version; + char backing_file[PATH_LEN_V2]; + time_t mtime; + __u64 size; + int sectorsize; +}; + +/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in + * case other systems have different values for MAXPATHLEN + */ +#define PATH_LEN_V3 4096 + +/* Changes from V2 - + * PATH_LEN_V3 as described above + * Explicitly specify field bit lengths for systems with different + * lengths for the usual C types. Not sure whether char or + * time_t should be changed, this can be changed later without + * breaking compatibility + * Add alignment field so that different alignments can be used for the + * bitmap and data + * Add cow_format field to allow for the possibility of different ways + * of specifying the COW blocks. For now, the only value is 0, + * for the traditional COW bitmap. + * Move the backing_file field to the end of the header. This allows + * for the possibility of expanding it into the padding required + * by the bitmap alignment. + * The bitmap and data portions of the file will be aligned as specified + * by the alignment field. This is to allow COW files to be + * put on devices with restrictions on access alignments, such as + * /dev/raw, with a 512 byte alignment restriction. This also + * allows the data to be more aligned more strictly than on + * sector boundaries. This is needed for ubd-mmap, which needs + * the data to be page aligned. + * Fixed (finally!) the rounding bug + */ + +struct cow_header_v3 { + __u32 magic; + __u32 version; + time_t mtime; + __u64 size; + __u32 sectorsize; + __u32 alignment; + __u32 cow_format; + char backing_file[PATH_LEN_V3]; +}; + +/* COW format definitions - for now, we have only the usual COW bitmap */ +#define COW_BITMAP 0 + +union cow_header { + struct cow_header_v1 v1; + struct cow_header_v2 v2; + struct cow_header_v3 v3; +}; + +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ +#define COW_VERSION 3 + +#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) +#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) + +void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out) +{ + if(version < 3){ + *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); + + *data_offset_out = bitmap_offset + *bitmap_len_out; + *data_offset_out = (*data_offset_out + sectorsize - 1) / + sectorsize; + *data_offset_out *= sectorsize; + } + else { + *bitmap_len_out = DIV_ROUND(size, sectorsize); + *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); + + *data_offset_out = bitmap_offset + *bitmap_len_out; + *data_offset_out = ROUND_UP(*data_offset_out, align); + } +} + +static int absolutize(char *to, int size, char *from) +{ + char save_cwd[256], *slash; + int remaining; + + if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { + cow_printf("absolutize : unable to get cwd - errno = %d\n", + errno); + return(-1); + } + slash = strrchr(from, '/'); + if(slash != NULL){ + *slash = '\0'; + if(chdir(from)){ + *slash = '/'; + cow_printf("absolutize : Can't cd to '%s' - " + "errno = %d\n", from, errno); + return(-1); + } + *slash = '/'; + if(getcwd(to, size) == NULL){ + cow_printf("absolutize : unable to get cwd of '%s' - " + "errno = %d\n", from, errno); + return(-1); + } + remaining = size - strlen(to); + if(strlen(slash) + 1 > remaining){ + cow_printf("absolutize : unable to fit '%s' into %d " + "chars\n", from, size); + return(-1); + } + strcat(to, slash); + } + else { + if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ + cow_printf("absolutize : unable to fit '%s' into %d " + "chars\n", from, size); + return(-1); + } + strcpy(to, save_cwd); + strcat(to, "/"); + strcat(to, from); + } + chdir(save_cwd); + return(0); +} + +int write_cow_header(char *cow_file, int fd, char *backing_file, + int sectorsize, int alignment, long long *size) +{ + struct cow_header_v3 *header; + unsigned long modtime; + int err; + + err = cow_seek_file(fd, 0); + if(err < 0){ + cow_printf("write_cow_header - lseek failed, err = %d\n", -err); + goto out; + } + + err = -ENOMEM; + header = cow_malloc(sizeof(*header)); + if(header == NULL){ + cow_printf("Failed to allocate COW V3 header\n"); + goto out; + } + header->magic = htonl(COW_MAGIC); + header->version = htonl(COW_VERSION); + + err = -EINVAL; + if(strlen(backing_file) > sizeof(header->backing_file) - 1){ + cow_printf("Backing file name \"%s\" is too long - names are " + "limited to %d characters\n", backing_file, + sizeof(header->backing_file) - 1); + goto out_free; + } + + if(absolutize(header->backing_file, sizeof(header->backing_file), + backing_file)) + goto out_free; + + err = os_file_modtime(header->backing_file, &modtime); + if(err < 0){ + cow_printf("Backing file '%s' mtime request failed, " + "err = %d\n", header->backing_file, -err); + goto out_free; + } + + err = cow_file_size(header->backing_file, size); + if(err < 0){ + cow_printf("Couldn't get size of backing file '%s', " + "err = %d\n", header->backing_file, -err); + goto out_free; + } + + header->mtime = htonl(modtime); + header->size = htonll(*size); + header->sectorsize = htonl(sectorsize); + header->alignment = htonl(alignment); + header->cow_format = COW_BITMAP; + + err = os_write_file(fd, header, sizeof(*header)); + if(err != sizeof(*header)){ + cow_printf("Write of header to new COW file '%s' failed, " + "err = %d\n", cow_file, -err); + goto out_free; + } + err = 0; + out_free: + cow_free(header); + out: + return(err); +} + +int file_reader(__u64 offset, char *buf, int len, void *arg) +{ + int fd = *((int *) arg); + + return(pread(fd, buf, len, offset)); +} + +/* XXX Need to sanity-check the values read from the header */ + +int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, + __u32 *version_out, char **backing_file_out, + time_t *mtime_out, __u64 *size_out, + int *sectorsize_out, __u32 *align_out, + int *bitmap_offset_out) +{ + union cow_header *header; + char *file; + int err, n; + unsigned long version, magic; + + header = cow_malloc(sizeof(*header)); + if(header == NULL){ + cow_printf("read_cow_header - Failed to allocate header\n"); + return(-ENOMEM); + } + err = -EINVAL; + n = (*reader)(0, (char *) header, sizeof(*header), arg); + if(n < offsetof(typeof(header->v1), backing_file)){ + cow_printf("read_cow_header - short header\n"); + goto out; + } + + magic = header->v1.magic; + if(magic == COW_MAGIC) { + version = header->v1.version; + } + else if(magic == ntohl(COW_MAGIC)){ + version = ntohl(header->v1.version); + } + /* No error printed because the non-COW case comes through here */ + else goto out; + + *version_out = version; + + if(version == 1){ + if(n < sizeof(header->v1)){ + cow_printf("read_cow_header - failed to read V1 " + "header\n"); + goto out; + } + *mtime_out = header->v1.mtime; + *size_out = header->v1.size; + *sectorsize_out = header->v1.sectorsize; + *bitmap_offset_out = sizeof(header->v1); + *align_out = *sectorsize_out; + file = header->v1.backing_file; + } + else if(version == 2){ + if(n < sizeof(header->v2)){ + cow_printf("read_cow_header - failed to read V2 " + "header\n"); + goto out; + } + *mtime_out = ntohl(header->v2.mtime); + *size_out = ntohll(header->v2.size); + *sectorsize_out = ntohl(header->v2.sectorsize); + *bitmap_offset_out = sizeof(header->v2); + *align_out = *sectorsize_out; + file = header->v2.backing_file; + } + else if(version == 3){ + if(n < sizeof(header->v3)){ + cow_printf("read_cow_header - failed to read V2 " + "header\n"); + goto out; + } + *mtime_out = ntohl(header->v3.mtime); + *size_out = ntohll(header->v3.size); + *sectorsize_out = ntohl(header->v3.sectorsize); + *align_out = ntohl(header->v3.alignment); + *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); + file = header->v3.backing_file; + } + else { + cow_printf("read_cow_header - invalid COW version\n"); + goto out; + } + err = -ENOMEM; + *backing_file_out = cow_strdup(file); + if(*backing_file_out == NULL){ + cow_printf("read_cow_header - failed to allocate backing " + "file\n"); + goto out; + } + err = 0; + out: + cow_free(header); + return(err); +} + +int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, + int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out) +{ + __u64 size, offset; + char zero = 0; + int err; + + err = write_cow_header(cow_file, fd, backing_file, sectorsize, + alignment, &size); + if(err) + goto out; + + *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); + cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, + bitmap_len_out, data_offset_out); + + offset = *data_offset_out + size - sizeof(zero); + err = cow_seek_file(fd, offset); + if(err < 0){ + cow_printf("cow bitmap lseek failed : err = %d\n", -err); + goto out; + } + + /* does not really matter how much we write it is just to set EOF + * this also sets the entire COW bitmap + * to zero without having to allocate it + */ + err = cow_write_file(fd, &zero, sizeof(zero)); + if(err != sizeof(zero)){ + cow_printf("Write of bitmap to new COW file '%s' failed, " + "err = %d\n", cow_file, -err); + err = -EINVAL; + goto out; + } + + return(0); + + out: + return(err); +} + +/* + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/drivers/daemon_user.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/drivers/daemon_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -53,7 +53,8 @@ static int connect_to_switch(struct daem struct request_v3 req; int fd, n, err; - if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ + pri->control = socket(AF_UNIX, SOCK_STREAM, 0); + if(pri->control < 0){ printk("daemon_open : control socket failed, errno = %d\n", errno); return(-errno); @@ -67,7 +68,8 @@ static int connect_to_switch(struct daem goto out; } - if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if(fd < 0){ printk("daemon_open : data socket failed, errno = %d\n", errno); err = -errno; @@ -91,18 +93,18 @@ static int connect_to_switch(struct daem req.version = SWITCH_VERSION; req.type = REQ_NEW_CONTROL; req.sock = *local_addr; - n = write(pri->control, &req, sizeof(req)); + n = os_write_file(pri->control, &req, sizeof(req)); if(n != sizeof(req)){ - printk("daemon_open : control setup request returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : control setup request failed, err = %d\n", + -n); err = -ENOTCONN; goto out; } - n = read(pri->control, sun, sizeof(*sun)); + n = os_read_file(pri->control, sun, sizeof(*sun)); if(n != sizeof(*sun)){ - printk("daemon_open : read of data socket returned %d, " - "errno = %d\n", n, errno); + printk("daemon_open : read of data socket failed, err = %d\n", + -n); err = -ENOTCONN; goto out_close; } @@ -111,9 +113,9 @@ static int connect_to_switch(struct daem return(fd); out_close: - close(fd); + os_close_file(fd); out: - close(pri->control); + os_close_file(pri->control); return(err); } @@ -153,8 +155,8 @@ static void daemon_remove(void *data) { struct daemon_data *pri = data; - close(pri->fd); - close(pri->control); + os_close_file(pri->fd); + os_close_file(pri->control); if(pri->data_addr != NULL) kfree(pri->data_addr); if(pri->ctl_addr != NULL) kfree(pri->ctl_addr); if(pri->local_addr != NULL) kfree(pri->local_addr); --- linux-2.6.8-rc1/arch/um/drivers/fd.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/arch/um/drivers/fd.c 2004-07-13 17:09:44.000000000 -0700 @@ -35,7 +35,8 @@ void *fd_init(char *str, int device, str printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct fd_chan) { .fd = n, .raw = opts->raw }); return(data); --- linux-2.6.8-rc1/arch/um/drivers/harddog_user.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/arch/um/drivers/harddog_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -27,10 +27,10 @@ static void pre_exec(void *d) dup2(data->stdin, 0); dup2(data->stdout, 1); dup2(data->stdout, 2); - close(data->stdin); - close(data->stdout); - close(data->close_me[0]); - close(data->close_me[1]); + os_close_file(data->stdin); + os_close_file(data->stdout); + os_close_file(data->close_me[0]); + os_close_file(data->close_me[1]); } int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) @@ -44,15 +44,15 @@ int start_watchdog(int *in_fd_ret, int * char **args = NULL; err = os_pipe(in_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out; } err = os_pipe(out_fds, 1, 0); - if(err){ - printk("harddog_open - os_pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("harddog_open - os_pipe failed, err = %d\n", -err); + goto out_close_in; } data.stdin = out_fds[0]; @@ -72,42 +72,47 @@ int start_watchdog(int *in_fd_ret, int * pid = run_helper(pre_exec, &data, args, NULL); - close(out_fds[0]); - close(in_fds[1]); + os_close_file(out_fds[0]); + os_close_file(in_fds[1]); if(pid < 0){ err = -pid; - printk("harddog_open - run_helper failed, errno = %d\n", err); - goto out; + printk("harddog_open - run_helper failed, errno = %d\n", -err); + goto out_close_out; } - n = read(in_fds[0], &c, sizeof(c)); + n = os_read_file(in_fds[0], &c, sizeof(c)); if(n == 0){ printk("harddog_open - EOF on watchdog pipe\n"); helper_wait(pid); err = -EIO; - goto out; + goto out_close_out; } else if(n < 0){ printk("harddog_open - read of watchdog pipe failed, " - "errno = %d\n", errno); + "err = %d\n", -n); helper_wait(pid); - err = -errno; - goto out; + err = n; + goto out_close_out; } *in_fd_ret = in_fds[0]; *out_fd_ret = out_fds[1]; return(0); + + out_close_in: + os_close_file(in_fds[0]); + os_close_file(in_fds[1]); + out_close_out: + os_close_file(out_fds[0]); + os_close_file(out_fds[1]); out: - close(out_fds[1]); - close(in_fds[0]); return(err); } void stop_watchdog(int in_fd, int out_fd) { - close(in_fd); - close(out_fd); + os_close_file(in_fd); + os_close_file(out_fd); } int ping_watchdog(int fd) @@ -115,11 +120,12 @@ int ping_watchdog(int fd) int n; char c = '\n'; - n = write(fd, &c, sizeof(c)); - if(n < sizeof(c)){ - printk("ping_watchdog - write failed, errno = %d\n", - errno); - return(-errno); + n = os_write_file(fd, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("ping_watchdog - write failed, err = %d\n", -n); + if(n < 0) + return(n); + return(-EIO); } return 1; --- linux-2.6.8-rc1/arch/um/drivers/hostaudio_kern.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/arch/um/drivers/hostaudio_kern.c 2004-07-13 17:09:47.000000000 -0700 @@ -5,44 +5,64 @@ #include "linux/config.h" #include "linux/module.h" -#include "linux/version.h" #include "linux/init.h" #include "linux/slab.h" #include "linux/fs.h" #include "linux/sound.h" #include "linux/soundcard.h" +#include "asm/uaccess.h" #include "kern_util.h" #include "init.h" -#include "hostaudio.h" +#include "os.h" + +struct hostaudio_state { + int fd; +}; + +struct hostmixer_state { + int fd; +}; + +#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" +#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" /* Only changed from linux_main at boot time */ char *dsp = HOSTAUDIO_DEV_DSP; char *mixer = HOSTAUDIO_DEV_MIXER; +#define DSP_HELP \ +" This is used to specify the host dsp device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" + +#define MIXER_HELP \ +" This is used to specify the host mixer device to the hostaudio driver.\n" \ +" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" + #ifndef MODULE static int set_dsp(char *name, int *add) { - dsp = uml_strdup(name); + dsp = name; return(0); } -__uml_setup("dsp=", set_dsp, -"dsp=\n" -" This is used to specify the host dsp device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" -); +__uml_setup("dsp=", set_dsp, "dsp=\n" DSP_HELP); static int set_mixer(char *name, int *add) { - mixer = uml_strdup(name); + mixer = name; return(0); } -__uml_setup("mixer=", set_mixer, -"mixer=\n" -" This is used to specify the host mixer device to the hostaudio driver.\n" -" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" -); +__uml_setup("mixer=", set_mixer, "mixer=\n" MIXER_HELP); + +#else /*MODULE*/ + +MODULE_PARM(dsp, "s"); +MODULE_PARM_DESC(dsp, DSP_HELP); + +MODULE_PARM(mixer, "s"); +MODULE_PARM_DESC(mixer, MIXER_HELP); + #endif /* /dev/dsp file operations */ @@ -51,23 +71,55 @@ static ssize_t hostaudio_read(struct fil loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int ret; #ifdef DEBUG printk("hostaudio: read called, count = %d\n", count); #endif - return(hostaudio_read_user(state, buffer, count, ppos)); + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + ret = os_read_file(state->fd, kbuf, count); + if(ret < 0) + goto out; + + if(copy_to_user(buffer, kbuf, ret)) + ret = -EFAULT; + + out: + kfree(kbuf); + return(ret); } static ssize_t hostaudio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; + void *kbuf; + int ret; #ifdef DEBUG printk("hostaudio: write called, count = %d\n", count); #endif - return(hostaudio_write_user(state, buffer, count, ppos)); + + kbuf = kmalloc(count, GFP_KERNEL); + if(kbuf == NULL) + return(-ENOMEM); + + ret = -EFAULT; + if(copy_from_user(kbuf, buffer, count)) + goto out; + + ret = os_write_file(state->fd, kbuf, count); + if(ret < 0) + goto out; + + out: + kfree(kbuf); + return(ret); } static unsigned int hostaudio_poll(struct file *file, @@ -86,12 +138,43 @@ static int hostaudio_ioctl(struct inode unsigned int cmd, unsigned long arg) { struct hostaudio_state *state = file->private_data; + unsigned long data = 0; + int ret; #ifdef DEBUG printk("hostaudio: ioctl called, cmd = %u\n", cmd); #endif + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(get_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } + + ret = os_ioctl_generic(state->fd, cmd, (unsigned long) &data); + + switch(cmd){ + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + if(put_user(data, (int *) arg)) + return(-EFAULT); + break; + default: + break; + } - return(hostaudio_ioctl_user(state, cmd, arg)); + return(ret); } static int hostaudio_open(struct inode *inode, struct file *file) @@ -110,12 +193,17 @@ static int hostaudio_open(struct inode * if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostaudio_open_user(state, r, w, dsp); + ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); + if(ret < 0){ + printk("hostaudio_open failed to open '%s', err = %d\n", + dsp, -ret); kfree(state); return(ret); } + state->fd = ret; + file->private_data = state; return(0); } @@ -123,16 +211,19 @@ static int hostaudio_open(struct inode * static int hostaudio_release(struct inode *inode, struct file *file) { struct hostaudio_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostaudio: release called\n"); #endif - ret = hostaudio_release_user(state); + if(state->fd >= 0){ + os_close_file(state->fd); + state->fd = -1; + } + kfree(state); - return(ret); + return(0); } /* /dev/mixer file operations */ @@ -146,7 +237,7 @@ static int hostmixer_ioctl_mixdev(struct printk("hostmixer: ioctl called\n"); #endif - return(hostmixer_ioctl_mixdev_user(state, cmd, arg)); + return(os_ioctl_generic(state->fd, cmd, arg)); } static int hostmixer_open_mixdev(struct inode *inode, struct file *file) @@ -165,13 +256,17 @@ static int hostmixer_open_mixdev(struct if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostmixer_open_mixdev_user(state, r, w, mixer); + ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); if(ret < 0){ + printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", + dsp, -ret); kfree(state); return(ret); } + state->fd = ret; + file->private_data = state; return(0); } @@ -179,16 +274,18 @@ static int hostmixer_open_mixdev(struct static int hostmixer_release(struct inode *inode, struct file *file) { struct hostmixer_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostmixer: release called\n"); #endif - ret = hostmixer_release_mixdev_user(state); + if(state->fd >= 0){ + os_close_file(state->fd); + state->fd = -1; + } kfree(state); - return(ret); + return(0); } @@ -225,7 +322,8 @@ MODULE_LICENSE("GPL"); static int __init hostaudio_init_module(void) { - printk(KERN_INFO "UML Audio Relay\n"); + printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", + dsp, mixer); module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); if(module_data.dev_audio < 0){ --- linux-2.6.8-rc1/arch/um/drivers/hostaudio_user.c 2003-06-14 12:18:28.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include "hostaudio.h" -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "os.h" - -/* /dev/dsp file operations */ - -ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, - size_t count, loff_t *ppos) -{ - ssize_t ret; - -#ifdef DEBUG - printk("hostaudio: read_user called, count = %d\n", count); -#endif - - ret = read(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); -} - -ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, - size_t count, loff_t *ppos) -{ - ssize_t ret; - -#ifdef DEBUG - printk("hostaudio: write_user called, count = %d\n", count); -#endif - - ret = write(state->fd, buffer, count); - - if(ret < 0) return(-errno); - return(ret); -} - -int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, - unsigned long arg) -{ - int ret; -#ifdef DEBUG - printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); -#endif - - ret = ioctl(state->fd, cmd, arg); - - if(ret < 0) return(-errno); - return(ret); -} - -int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) -{ -#ifdef DEBUG - printk("hostaudio: open_user called\n"); -#endif - - state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd >= 0) return(0); - - printk("hostaudio_open_user failed to open '%s', errno = %d\n", - dsp, errno); - - return(-errno); -} - -int hostaudio_release_user(struct hostaudio_state *state) -{ -#ifdef DEBUG - printk("hostaudio: release called\n"); -#endif - if(state->fd >= 0){ - close(state->fd); - state->fd=-1; - } - - return(0); -} - -/* /dev/mixer file operations */ - -int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, - unsigned int cmd, unsigned long arg) -{ - int ret; -#ifdef DEBUG - printk("hostmixer: ioctl_user called cmd = %u\n",cmd); -#endif - - ret = ioctl(state->fd, cmd, arg); - if(ret < 0) - return(-errno); - return(ret); -} - -int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, - char *mixer) -{ -#ifdef DEBUG - printk("hostmixer: open_user called\n"); -#endif - - state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd >= 0) return(0); - - printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n", - mixer, errno); - - return(-errno); -} - -int hostmixer_release_mixdev_user(struct hostmixer_state *state) -{ -#ifdef DEBUG - printk("hostmixer: release_user called\n"); -#endif - - if(state->fd >= 0){ - close(state->fd); - state->fd = -1; - } - - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ --- linux-2.6.8-rc1/arch/um/drivers/line.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/drivers/line.c 2004-07-13 17:09:44.000000000 -0700 @@ -6,8 +6,8 @@ #include "linux/sched.h" #include "linux/slab.h" #include "linux/list.h" +#include "linux/interrupt.h" #include "linux/devfs_fs_kernel.h" -#include "asm/irq.h" #include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" @@ -16,38 +16,55 @@ #include "user_util.h" #include "kern_util.h" #include "os.h" +#include "irq_kern.h" #define LINE_BUFSIZE 4096 -void line_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) { struct line *dev = data; if(dev->count > 0) chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, dev); + return IRQ_HANDLED; } -void line_timer_cb(void *arg) +static void line_timer_cb(void *arg) { struct line *dev = arg; line_interrupt(dev->driver->read_irq, dev, NULL); } -static void buffer_data(struct line *line, const char *buf, int len) +static int write_room(struct line *dev) { - int end; + int n; + + if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); + + n = dev->head - dev->tail; + if(n <= 0) n = LINE_BUFSIZE + n; + return(n - 1); +} + +static int buffer_data(struct line *line, const char *buf, int len) +{ + int end, room; if(line->buffer == NULL){ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if(line->buffer == NULL){ printk("buffer_data - atomic allocation failed\n"); - return; + return(0); } line->head = line->buffer; line->tail = line->buffer; } + + room = write_room(line); + len = (len > room) ? room : len; + end = line->buffer + LINE_BUFSIZE - line->tail; if(len < end){ memcpy(line->tail, buf, len); @@ -60,6 +77,8 @@ static void buffer_data(struct line *lin memcpy(line->buffer, buf, len); line->tail = line->buffer + len; } + + return(len); } static int flush_buffer(struct line *line) @@ -95,7 +114,7 @@ int line_write(struct line *lines, struc struct line *line; char *new; unsigned long flags; - int n, err, i; + int n, err, i, ret = 0; if(tty->stopped) return 0; @@ -104,9 +123,13 @@ int line_write(struct line *lines, struc if(new == NULL) return(0); n = copy_from_user(new, buf, len); - if(n == len) - return(-EFAULT); buf = new; + if(n == len){ + len = -EFAULT; + goto out_free; + } + + len -= n; } i = tty->index; @@ -115,41 +138,50 @@ int line_write(struct line *lines, struc down(&line->sem); if(line->head != line->tail){ local_irq_save(flags); - buffer_data(line, buf, len); + ret += buffer_data(line, buf, len); err = flush_buffer(line); local_irq_restore(flags); if(err <= 0) - goto out; + goto out_up; } else { n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); if(n < 0){ - len = n; - goto out; + ret = n; + goto out_up; } - if(n < len) - buffer_data(line, buf + n, len - n); + + len -= n; + ret += n; + if(len > 0) + ret += buffer_data(line, buf + n, len); } - out: + out_up: up(&line->sem); - return(len); + out_free: + if(from_user) + kfree(buf); + return(ret); } -void line_write_interrupt(int irq, void *data, struct pt_regs *unused) +static irqreturn_t line_write_interrupt(int irq, void *data, + struct pt_regs *unused) { struct line *dev = data; struct tty_struct *tty = dev->tty; int err; err = flush_buffer(dev); - if(err == 0) return; + if(err == 0) + return(IRQ_NONE); else if(err < 0){ dev->head = dev->buffer; dev->tail = dev->buffer; } - if(tty == NULL) return; + if(tty == NULL) + return(IRQ_NONE); if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && (tty->ldisc.write_wakeup != NULL)) @@ -161,21 +193,9 @@ void line_write_interrupt(int irq, void * writes. */ - if (waitqueue_active(&tty->write_wait)) + if(waitqueue_active(&tty->write_wait)) wake_up_interruptible(&tty->write_wait); - -} - -int line_write_room(struct tty_struct *tty) -{ - struct line *dev = tty->driver_data; - int n; - - if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); - - n = dev->head - dev->tail; - if(n <= 0) n = LINE_BUFSIZE + n; - return(n - 1); + return(IRQ_HANDLED); } int line_setup_irq(int fd, int input, int output, void *data) @@ -305,7 +325,7 @@ int line_setup(struct line *lines, int n if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(1); + return(0); } init = end; } @@ -313,12 +333,12 @@ int line_setup(struct line *lines, int n if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", n, num); - return(1); + return(0); } else if(n >= 0){ if(lines[n].count > 0){ printk("line_setup - device %d is open\n", n); - return(1); + return(0); } if(lines[n].init_pri <= INIT_ONE){ lines[n].init_pri = INIT_ONE; @@ -332,7 +352,7 @@ int line_setup(struct line *lines, int n else if(!all_allowed){ printk("line_setup - can't configure all devices from " "mconsole\n"); - return(1); + return(0); } else { for(i = 0; i < num; i++){ @@ -346,7 +366,7 @@ int line_setup(struct line *lines, int n } } } - return(0); + return(1); } int line_config(struct line *lines, int num, char *str) @@ -357,7 +377,7 @@ int line_config(struct line *lines, int printk("line_config - uml_strdup failed\n"); return(-ENOMEM); } - return(line_setup(lines, num, new, 0)); + return(!line_setup(lines, num, new, 0)); } int line_get_config(char *name, struct line *lines, int num, char *str, @@ -369,7 +389,7 @@ int line_get_config(char *name, struct l dev = simple_strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - *error_out = "line_setup failed to parse device number"; + *error_out = "line_get_config failed to parse device number"; return(0); } @@ -379,15 +399,15 @@ int line_get_config(char *name, struct l } line = &lines[dev]; + down(&line->sem); - if(!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); else if(line->count == 0) CONFIG_CHUNK(str, size, n, line->init_str, 1); else n = chan_config_string(&line->chan_list, str, size, error_out); - up(&line->sem); + return(n); } @@ -396,7 +416,14 @@ int line_remove(struct line *lines, int char config[sizeof("conxxxx=none\0")]; sprintf(config, "%s=none", str); - return(line_setup(lines, num, config, 0)); + return(!line_setup(lines, num, config, 0)); +} + +int line_write_room(struct tty_struct *tty) +{ + struct line *dev = tty->driver_data; + + return(write_room(dev)); } struct tty_driver *line_register_devfs(struct lines *set, @@ -412,7 +439,8 @@ struct tty_driver *line_register_devfs(s return NULL; driver->driver_name = line_driver->name; - driver->name = line_driver->devfs_name; + driver->name = line_driver->device_name; + driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; @@ -432,7 +460,7 @@ struct tty_driver *line_register_devfs(s for(i = 0; i < nlines; i++){ if(!lines[i].valid) - tty_unregister_devfs(driver, i); + tty_unregister_device(driver, i); } mconsole_register_dev(&line_driver->mc); @@ -465,24 +493,25 @@ struct winch { struct line *line; }; -void winch_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) { struct winch *winch = data; struct tty_struct *tty; int err; char c; - err = generic_read(winch->fd, &c, NULL); - if(err < 0){ - if(err != -EAGAIN){ - printk("winch_interrupt : read failed, errno = %d\n", - -err); - printk("fd %d is losing SIGWINCH support\n", - winch->tty_fd); - free_irq(irq, data); - return; + if(winch->fd != -1){ + err = generic_read(winch->fd, &c, NULL); + if(err < 0){ + if(err != -EAGAIN){ + printk("winch_interrupt : read failed, " + "errno = %d\n", -err); + printk("fd %d is losing SIGWINCH support\n", + winch->tty_fd); + return(IRQ_HANDLED); + } + goto out; } - goto out; } tty = winch->line->tty; if(tty != NULL){ @@ -492,7 +521,9 @@ void winch_interrupt(int irq, void *data kill_pg(tty->pgrp, SIGWINCH, 1); } out: - reactivate_fd(winch->fd, WINCH_IRQ); + if(winch->fd != -1) + reactivate_fd(winch->fd, WINCH_IRQ); + return(IRQ_HANDLED); } DECLARE_MUTEX(winch_handler_sem); @@ -529,7 +560,10 @@ static void winch_cleanup(void) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); - close(winch->fd); + if(winch->fd != -1){ + deactivate_fd(winch->fd, WINCH_IRQ); + os_close_file(winch->fd); + } if(winch->pid != -1) os_kill_process(winch->pid, 1); } --- linux-2.6.8-rc1/arch/um/drivers/Makefile 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/drivers/Makefile 2004-07-13 17:09:47.000000000 -0700 @@ -1,5 +1,5 @@ # -# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com) # Licensed under the GPL # @@ -15,7 +15,7 @@ mcast-objs := mcast_kern.o mcast_user.o #pcap-objs := pcap_kern.o pcap_user.o $(PCAP) net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o -hostaudio-objs := hostaudio_kern.o hostaudio_user.o +hostaudio-objs := hostaudio_kern.o ubd-objs := ubd_kern.o ubd_user.o port-objs := port_kern.o port_user.o harddog-objs := harddog_kern.o harddog_user.o @@ -39,6 +39,8 @@ obj-$(CONFIG_PTY_CHAN) += pty.o obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o +obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o +obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o obj-y += stdio_console.o $(CHAN_OBJS) @@ -46,18 +48,7 @@ USER_SINGLE_OBJS = $(foreach f,$(patsubs USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ null.o pty.o tty.o xterm.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean: - -modules: - -fastdep: - -dep: - -archmrproper: clean - --- linux-2.6.8-rc1/arch/um/drivers/mcast_user.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/drivers/mcast_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -23,6 +23,7 @@ #include "kern_util.h" #include "user_util.h" #include "user.h" +#include "os.h" #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER) @@ -62,7 +63,8 @@ static int mcast_open(void *data) goto out; } - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); fd = -ENOMEM; @@ -72,7 +74,7 @@ static int mcast_open(void *data) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -82,7 +84,7 @@ static int mcast_open(void *data) sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -91,7 +93,7 @@ static int mcast_open(void *data) if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -99,7 +101,7 @@ static int mcast_open(void *data) /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); - close(fd); + os_close_file(fd); fd = -EINVAL; goto out; } @@ -115,7 +117,7 @@ static int mcast_open(void *data) "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); - close(fd); + os_close_file(fd); fd = -EINVAL; } @@ -137,7 +139,7 @@ static void mcast_close(int fd, void *da errno); } - close(fd); + os_close_file(fd); } int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri) --- linux-2.6.8-rc1/arch/um/drivers/mconsole_kern.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/drivers/mconsole_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -15,6 +15,9 @@ #include "linux/sysrq.h" #include "linux/workqueue.h" #include "linux/module.h" +#include "linux/file.h" +#include "linux/fs.h" +#include "linux/namei.h" #include "linux/proc_fs.h" #include "asm/irq.h" #include "asm/uaccess.h" @@ -27,6 +30,7 @@ #include "init.h" #include "os.h" #include "umid.h" +#include "irq_kern.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -67,7 +71,7 @@ void mc_work_proc(void *unused) DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -75,9 +79,10 @@ void mconsole_interrupt(int irq, void *d fd = (int) dev_id; while (mconsole_get_request(fd, &req)){ - if(req.cmd->as_interrupt) (*req.cmd->handler)(&req); + if(req.cmd->context == MCONSOLE_INTR) + (*req.cmd->handler)(&req); else { - new = kmalloc(sizeof(req), GFP_ATOMIC); + new = kmalloc(sizeof(*new), GFP_ATOMIC); if(new == NULL) mconsole_reply(&req, "Out of memory", 1, 0); else { @@ -88,6 +93,7 @@ void mconsole_interrupt(int irq, void *d } if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); reactivate_fd(fd, MCONSOLE_IRQ); + return(IRQ_HANDLED); } void mconsole_version(struct mc_request *req) @@ -100,20 +106,109 @@ void mconsole_version(struct mc_request mconsole_reply(req, version, 0, 0); } +void mconsole_log(struct mc_request *req) +{ + int len; + char *ptr = req->request.data; + + ptr += strlen("log "); + + len = req->len - (ptr - req->request.data); + printk("%.*s", len, ptr); + mconsole_reply(req, "", 0, 0); +} + +void mconsole_proc(struct mc_request *req) +{ + struct nameidata nd; + struct file_system_type *proc; + struct super_block *super; + struct file *file; + int n, err; + char *ptr = req->request.data, *buf; + + ptr += strlen("proc"); + while(isspace(*ptr)) ptr++; + + proc = get_fs_type("proc"); + if(proc == NULL){ + mconsole_reply(req, "procfs not registered", 1, 0); + goto out; + } + + super = (*proc->get_sb)(proc, 0, NULL, NULL); + put_filesystem(proc); + if(super == NULL){ + mconsole_reply(req, "Failed to get procfs superblock", 1, 0); + goto out; + } + up_write(&super->s_umount); + + nd.dentry = super->s_root; + nd.mnt = NULL; + nd.flags = O_RDONLY + 1; + nd.last_type = LAST_ROOT; + + err = link_path_walk(ptr, &nd); + if(err){ + mconsole_reply(req, "Failed to look up file", 1, 0); + goto out_kill; + } + + file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + if(IS_ERR(file)){ + mconsole_reply(req, "Failed to open file", 1, 0); + goto out_kill; + } + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + goto out_fput; + } + + if((file->f_op != NULL) && (file->f_op->read != NULL)){ + do { + n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, + &file->f_pos); + if(n >= 0){ + buf[n] = '\0'; + mconsole_reply(req, buf, 0, (n > 0)); + } + else { + mconsole_reply(req, "Read of file failed", + 1, 0); + goto out_free; + } + } while(n > 0); + } + else mconsole_reply(req, "", 0, 0); + + out_free: + kfree(buf); + out_fput: + fput(file); + out_kill: + deactivate_super(super); + out: ; +} + #define UML_MCONSOLE_HELPTEXT \ -"Commands: - version - Get kernel version - help - Print this message - halt - Halt UML - reboot - Reboot UML - config = - Add a new device to UML; - same syntax as command line - config - Query the configuration of a device - remove - Remove a device from UML - sysrq - Performs the SysRq action controlled by the letter - cad - invoke the Ctl-Alt-Del handler - stop - pause the UML; it will do nothing until it receives a 'go' - go - continue the UML after a 'stop' +"Commands: \n\ + version - Get kernel version \n\ + help - Print this message \n\ + halt - Halt UML \n\ + reboot - Reboot UML \n\ + config = - Add a new device to UML; \n\ + same syntax as command line \n\ + config - Query the configuration of a device \n\ + remove - Remove a device from UML \n\ + sysrq - Performs the SysRq action controlled by the letter \n\ + cad - invoke the Ctl-Alt-Del handler \n\ + stop - pause the UML; it will do nothing until it receives a 'go' \n\ + go - continue the UML after a 'stop' \n\ + log - make UML enter into the kernel log\n\ + proc - returns the contents of the UML's /proc/\n\ " void mconsole_help(struct mc_request *req) @@ -302,7 +397,7 @@ int mconsole_init(void) if(umid_file_name("mconsole", file, sizeof(file))) return(-1); snprintf(mconsole_socket_name, sizeof(file), "%s", file); - sock = create_unix_socket(file, sizeof(file)); + sock = os_create_unix_socket(file, sizeof(file), 1); if (sock < 0){ printk("Failed to initialize management console\n"); return(1); @@ -344,11 +439,16 @@ static int write_proc_mconsole(struct fi if(buf == NULL) return(-ENOMEM); - if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + if(copy_from_user(buf, buffer, count)){ + count = -EFAULT; + goto out; + } + buf[count] = '\0'; mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count); + out: + kfree(buf); return(count); } --- linux-2.6.8-rc1/arch/um/drivers/mconsole_user.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/drivers/mconsole_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -18,16 +18,18 @@ #include "umid.h" static struct mconsole_command commands[] = { - { "version", mconsole_version, 1 }, - { "halt", mconsole_halt, 0 }, - { "reboot", mconsole_reboot, 0 }, - { "config", mconsole_config, 0 }, - { "remove", mconsole_remove, 0 }, - { "sysrq", mconsole_sysrq, 1 }, - { "help", mconsole_help, 1 }, - { "cad", mconsole_cad, 1 }, - { "stop", mconsole_stop, 0 }, - { "go", mconsole_go, 1 }, + { "version", mconsole_version, MCONSOLE_INTR }, + { "halt", mconsole_halt, MCONSOLE_PROC }, + { "reboot", mconsole_reboot, MCONSOLE_PROC }, + { "config", mconsole_config, MCONSOLE_PROC }, + { "remove", mconsole_remove, MCONSOLE_PROC }, + { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, + { "help", mconsole_help, MCONSOLE_INTR }, + { "cad", mconsole_cad, MCONSOLE_INTR }, + { "stop", mconsole_stop, MCONSOLE_PROC }, + { "go", mconsole_go, MCONSOLE_INTR }, + { "log", mconsole_log, MCONSOLE_INTR }, + { "proc", mconsole_proc, MCONSOLE_PROC }, }; /* Initialized in mconsole_init, which is an initcall */ @@ -139,6 +141,7 @@ int mconsole_reply(struct mc_request *re memcpy(reply.data, str, len); reply.data[len] = '\0'; total -= len; + str += len; reply.len = len + 1; len = sizeof(reply) + reply.len - sizeof(reply.data); --- linux-2.6.8-rc1/arch/um/drivers/mmapper_kern.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/drivers/mmapper_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -120,7 +120,10 @@ static int __init mmapper_init(void) printk(KERN_INFO "Mapper v0.1\n"); v_buf = (char *) find_iomem("mmapper", &mmapper_size); - if(mmapper_size == 0) return(0); + if(mmapper_size == 0){ + printk(KERN_ERR "mmapper_init - find_iomem failed\n"); + return(0); + } p_buf = __pa(v_buf); --- linux-2.6.8-rc1/arch/um/drivers/net_kern.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/um/drivers/net_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -26,6 +26,7 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(opened); @@ -37,7 +38,8 @@ static int uml_net_rx(struct net_device struct sk_buff *skb; /* If we can't allocate memory, try again next round. */ - if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { + skb = dev_alloc_skb(dev->mtu); + if (skb == NULL) { lp->stats.rx_dropped++; return 0; } @@ -61,14 +63,14 @@ static int uml_net_rx(struct net_device return pkt_len; } -void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct uml_net_private *lp = dev->priv; int err; if(!netif_running(dev)) - return; + return(IRQ_NONE); spin_lock(&lp->lock); while((err = uml_net_rx(dev)) > 0) ; @@ -83,6 +85,7 @@ void uml_net_interrupt(int irq, void *de out: spin_unlock(&lp->lock); + return(IRQ_HANDLED); } static int uml_net_open(struct net_device *dev) @@ -250,37 +253,6 @@ void uml_net_user_timer_expire(unsigned #endif } -/* - * default do nothing hard header packet routines for struct net_device init. - * real ethernet transports will overwrite with real routines. - */ -static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return(0); /* no change */ -} - -static int uml_net_rebuild_header(struct sk_buff *skb) -{ - return(0); /* ignore */ -} - -static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) -{ - return(-1); /* fail */ -} - -static void uml_net_header_cache_update(struct hh_cache *hh, - struct net_device *dev, unsigned char * haddr) -{ - /* ignore */ -} - -static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) -{ - return(0); /* nothing */ -} - static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); @@ -290,7 +262,7 @@ static int eth_configure(int n, void *in struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int err, size; + int save, err, size; size = transport->private_size + sizeof(struct uml_net_private) + sizeof(((struct uml_net_private *) 0)->user); @@ -332,12 +304,6 @@ static int eth_configure(int n, void *in snprintf(dev->name, sizeof(dev->name), "eth%d", n); device->dev = dev; - dev->hard_header = uml_net_hard_header; - dev->rebuild_header = uml_net_rebuild_header; - dev->hard_header_cache = uml_net_header_cache; - dev->header_cache_update= uml_net_header_cache_update; - dev->hard_header_parse = uml_net_header_parse; - (*transport->kern->init)(dev, init); dev->mtu = transport->user->max_packet; @@ -364,21 +330,29 @@ static int eth_configure(int n, void *in } lp = dev->priv; - INIT_LIST_HEAD(&lp->list); - spin_lock_init(&lp->lock); - lp->dev = dev; - lp->fd = -1; - lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; - lp->have_mac = device->have_mac; - lp->protocol = transport->kern->protocol; - lp->open = transport->user->open; - lp->close = transport->user->close; - lp->remove = transport->user->remove; - lp->read = transport->kern->read; - lp->write = transport->kern->write; - lp->add_address = transport->user->add_address; - lp->delete_address = transport->user->delete_address; - lp->set_mtu = transport->user->set_mtu; + /* lp.user is the first four bytes of the transport data, which + * has already been initialized. This structure assignment will + * overwrite that, so we make sure that .user gets overwritten with + * what it already has. + */ + save = lp->user[0]; + *lp = ((struct uml_net_private) + { .list = LIST_HEAD_INIT(lp->list), + .lock = SPIN_LOCK_UNLOCKED, + .dev = dev, + .fd = -1, + .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, + .have_mac = device->have_mac, + .protocol = transport->kern->protocol, + .open = transport->user->open, + .close = transport->user->close, + .remove = transport->user->remove, + .read = transport->kern->read, + .write = transport->kern->write, + .add_address = transport->user->add_address, + .delete_address = transport->user->delete_address, + .set_mtu = transport->user->set_mtu, + .user = { save } }); init_timer(&lp->tl); lp->tl.function = uml_net_user_timer_expire; @@ -611,7 +585,8 @@ static int net_remove(char *str) unregister_netdev(dev); list_del(&device->list); - free_netdev(device); + kfree(device); + free_netdev(dev); return(0); } --- linux-2.6.8-rc1/arch/um/drivers/net_user.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/drivers/net_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -26,8 +26,7 @@ int tap_open_common(void *dev, char *gat if(gate_addr == NULL) return(0); if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ - printk("Invalid tap IP address - '%s'\n", - gate_addr); + printk("Invalid tap IP address - '%s'\n", gate_addr); return(-EINVAL); } return(0); @@ -60,18 +59,18 @@ void read_output(int fd, char *output, i } *output = '\0'; - if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){ - printk("read_output - read of length failed, errno = %d\n", - errno); + n = os_read_file(fd, &remain, sizeof(remain)); + if(n != sizeof(remain)){ + printk("read_output - read of length failed, err = %d\n", -n); return; } while(remain != 0){ n = (remain < len) ? remain : len; - actual = read(fd, output, n); + actual = os_read_file(fd, output, n); if(actual != n){ printk("read_output - read of data failed, " - "errno = %d\n", errno); + "err = %d\n", -actual); return; } remain -= actual; @@ -83,13 +82,12 @@ int net_read(int fd, void *buf, int len) { int n; - while(((n = read(fd, buf, len)) < 0) && (errno == EINTR)) ; + n = os_read_file(fd, buf, len); - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); return(n); } @@ -112,13 +110,13 @@ int net_write(int fd, void *buf, int len { int n; - while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ; - if(n < 0){ - if(errno == EAGAIN) return(0); - return(-errno); - } - else if(n == 0) return(-ENOTCONN); - return(n); + n = os_write_file(fd, buf, len); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-ENOTCONN); + return(n); } int net_send(int fd, void *buf, int len) @@ -157,7 +155,7 @@ static void change_pre_exec(void *arg) { struct change_pre_exec_data *data = arg; - close(data->close_me); + os_close_file(data->close_me); dup2(data->stdout, 1); } @@ -167,17 +165,18 @@ static int change_tramp(char **argv, cha struct change_pre_exec_data pe_data; err = os_pipe(fds, 1, 0); - if(err){ - printk("change_tramp - pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("change_tramp - pipe failed, err = %d\n", -err); return(err); } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); - waitpid(pid, NULL, 0); + + CATCH_EINTR(err = waitpid(pid, NULL, 0)); return(pid); } --- linux-2.6.8-rc1/arch/um/drivers/null.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/drivers/null.c 2004-07-13 17:09:44.000000000 -0700 @@ -5,7 +5,6 @@ #include #include -#include #include "chan_user.h" #include "os.h" --- linux-2.6.8-rc1/arch/um/drivers/port_kern.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/drivers/port_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -6,6 +6,7 @@ #include "linux/list.h" #include "linux/sched.h" #include "linux/slab.h" +#include "linux/interrupt.h" #include "linux/irq.h" #include "linux/spinlock.h" #include "linux/errno.h" @@ -14,6 +15,7 @@ #include "kern_util.h" #include "kern.h" #include "irq_user.h" +#include "irq_kern.h" #include "port.h" #include "init.h" #include "os.h" @@ -38,21 +40,21 @@ struct port_dev { struct connection { struct list_head list; int fd; - int helper_pid; + int helper_pid; int socket[2]; int telnetd_pid; struct port_list *port; }; -static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs) { struct connection *conn = data; int fd; - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); + fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ if(fd == -EAGAIN) - return; + return(IRQ_NONE); printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", -fd); @@ -65,6 +67,7 @@ static void pipe_interrupt(int irq, void list_add(&conn->list, &conn->port->connections); up(&conn->port->sem); + return(IRQ_HANDLED); } static int port_accept(struct port_list *port) @@ -102,8 +105,7 @@ static int port_accept(struct port_list } list_add(&conn->list, &port->pending); - ret = 1; - goto out; + return(1); out_free: kfree(conn); @@ -138,12 +140,13 @@ void port_work_proc(void *unused) DECLARE_WORK(port_work, port_work_proc, NULL); -static void port_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs) { struct port_list *port = data; port->has_connection = 1; schedule_work(&port_work); + return(IRQ_HANDLED); } void *port_data(int port_num) --- linux-2.6.8-rc1/arch/um/drivers/port_user.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/drivers/port_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -47,10 +47,12 @@ void *port_init(char *str, int device, s return(NULL); } - if((kern_data = port_data(port)) == NULL) + kern_data = port_data(port); + if(kern_data == NULL) return(NULL); - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) goto err; *data = ((struct port_chan) { .raw = opts->raw, @@ -90,7 +92,7 @@ void port_close(int fd, void *d) struct port_chan *data = d; port_remove_dev(data->kernel_data); - close(fd); + os_close_file(fd); } int port_console_write(int fd, const char *buf, int n, void *d) @@ -130,11 +132,15 @@ int port_listen_fd(int port) goto out; } - if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){ + if(listen(fd, 1) < 0){ err = -errno; goto out; } + err = os_set_fd_block(fd, 0); + if(err < 0) + goto out; + return(fd); out: os_close_file(fd); @@ -153,10 +159,10 @@ void port_pre_exec(void *arg) dup2(data->sock_fd, 0); dup2(data->sock_fd, 1); dup2(data->sock_fd, 2); - close(data->sock_fd); + os_close_file(data->sock_fd); dup2(data->pipe_fd, 3); os_shutdown_socket(3, 1, 0); - close(data->pipe_fd); + os_close_file(data->pipe_fd); } int port_connection(int fd, int *socket, int *pid_out) @@ -166,11 +172,12 @@ int port_connection(int fd, int *socket, "/usr/lib/uml/port-helper", NULL }; struct port_pre_exec_data data; - if((new = os_accept_connection(fd)) < 0) - return(-errno); + new = os_accept_connection(fd); + if(new < 0) + return(new); err = os_pipe(socket, 0, 0); - if(err) + if(err < 0) goto out_close; data = ((struct port_pre_exec_data) @@ -186,11 +193,11 @@ int port_connection(int fd, int *socket, out_shutdown: os_shutdown_socket(socket[0], 1, 1); - close(socket[0]); + os_close_file(socket[0]); os_shutdown_socket(socket[1], 1, 1); - close(socket[1]); + os_close_file(socket[1]); out_close: - close(new); + os_close_file(new); return(err); } --- linux-2.6.8-rc1/arch/um/drivers/pty.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/drivers/pty.c 2004-07-13 17:09:44.000000000 -0700 @@ -7,12 +7,12 @@ #include #include #include -#include #include #include "chan_user.h" #include "user.h" #include "user_util.h" #include "kern_util.h" +#include "os.h" struct pty_chan { void (*announce)(char *dev_name, int dev); @@ -26,7 +26,8 @@ void *pty_chan_init(char *str, int devic { struct pty_chan *data; - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct pty_chan) { .announce = opts->announce, .dev = device, .raw = opts->raw }); @@ -39,7 +40,8 @@ int pts_open(int input, int output, int char *dev; int fd; - if((fd = get_pty()) < 0){ + fd = get_pty(); + if(fd < 0){ printk("open_pts : Failed to open pts\n"); return(-errno); } @@ -57,29 +59,27 @@ int pts_open(int input, int output, int int getmaster(char *line) { - struct stat stb; char *pty, *bank, *cp; - int master; + int master, err; pty = &line[strlen("/dev/ptyp")]; for (bank = "pqrs"; *bank; bank++) { line[strlen("/dev/pty")] = *bank; *pty = '0'; - if (stat(line, &stb) < 0) + if (os_stat_file(line, NULL) < 0) break; for (cp = "0123456789abcdef"; *cp; cp++) { *pty = *cp; - master = open(line, O_RDWR); + master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); if (master >= 0) { char *tp = &line[strlen("/dev/")]; - int ok; /* verify slave side is usable */ *tp = 't'; - ok = access(line, R_OK|W_OK) == 0; + err = os_access(line, OS_ACC_RW_OK); *tp = 'p'; - if (ok) return(master); - (void) close(master); + if(err == 0) return(master); + (void) os_close_file(master); } } } --- linux-2.6.8-rc1/arch/um/drivers/slip_user.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/drivers/slip_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -4,11 +4,9 @@ #include #include #include -#include -#include +#include #include #include -#include #include #include "user_util.h" #include "kern_util.h" @@ -65,9 +63,9 @@ static void slip_pre_exec(void *arg) { struct slip_pre_exec_data *data = arg; - if(data->stdin != -1) dup2(data->stdin, 0); + if(data->stdin >= 0) dup2(data->stdin, 0); dup2(data->stdout, 1); - if(data->close_me != -1) close(data->close_me); + if(data->close_me >= 0) os_close_file(data->close_me); } static int slip_tramp(char **argv, int fd) @@ -77,8 +75,8 @@ static int slip_tramp(char **argv, int f int status, pid, fds[2], err, output_len; err = os_pipe(fds, 1, 0); - if(err){ - printk("slip_tramp : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("slip_tramp : pipe failed, err = %d\n", -err); return(err); } @@ -96,16 +94,18 @@ static int slip_tramp(char **argv, int f printk("slip_tramp : failed to allocate output " "buffer\n"); - close(fds[1]); + os_close_file(fds[1]); read_output(fds[0], output, output_len); if(output != NULL){ printk("%s", output); kfree(output); } - if(waitpid(pid, &status, 0) < 0) err = errno; + CATCH_EINTR(err = waitpid(pid, &status, 0)); + if(err < 0) + err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ printk("'%s' didn't exit with status 0\n", argv[0]); - err = EINVAL; + err = -EINVAL; } } return(err); @@ -118,15 +118,17 @@ static int slip_open(void *data) char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, NULL }; - int sfd, mfd, disc, sencap, err; + int sfd, mfd, err; - if((mfd = get_pty()) < 0){ - printk("umn : Failed to open pty\n"); - return(-1); + mfd = get_pty(); + if(mfd < 0){ + printk("umn : Failed to open pty, err = %d\n", -mfd); + return(mfd); } - if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("Couldn't open tty for slip line\n"); - return(-1); + sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); + if(sfd < 0){ + printk("Couldn't open tty for slip line, err = %d\n", -sfd); + return(sfd); } if(set_up_tty(sfd)) return(-1); pri->slave = sfd; @@ -138,28 +140,23 @@ static int slip_open(void *data) err = slip_tramp(argv, sfd); - if(err != 0){ - printk("slip_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("slip_tramp failed - err = %d\n", -err); + return(err); } - if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){ - printk("SIOCGIFNAME failed, errno = %d\n", errno); - return(-errno); + err = os_get_ifname(pri->slave, pri->name); + if(err < 0){ + printk("get_ifname failed, err = %d\n", -err); + return(err); } iter_addresses(pri->dev, open_addr, pri->name); } else { - disc = N_SLIP; - if(ioctl(sfd, TIOCSETD, &disc) < 0){ - printk("Failed to set slip line discipline - " - "errno = %d\n", errno); - return(-errno); - } - sencap = 0; - if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to set slip encapsulation - " - "errno = %d\n", errno); - return(-errno); + err = os_set_slip(sfd); + if(err < 0){ + printk("Failed to set slip discipline encapsulation - " + "err = %d\n", -err); + return(err); } } return(mfd); @@ -181,9 +178,9 @@ static void slip_close(int fd, void *dat err = slip_tramp(argv, -1); if(err != 0) - printk("slip_tramp failed - errno = %d\n", err); - close(fd); - close(pri->slave); + printk("slip_tramp failed - errno = %d\n", -err); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; } @@ -243,7 +240,7 @@ static void slip_add_addr(unsigned char { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; open_addr(addr, netmask, pri->name); } @@ -252,7 +249,7 @@ static void slip_del_addr(unsigned char { struct slip_data *pri = data; - if(pri->slave == -1) return; + if(pri->slave < 0) return; close_addr(addr, netmask, pri->name); } --- linux-2.6.8-rc1/arch/um/drivers/slirp_user.c 2003-06-14 12:18:25.000000000 -0700 +++ 25/arch/um/drivers/slirp_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include #include #include #include "user_util.h" @@ -48,15 +47,15 @@ static int slirp_tramp(char **argv, int return(pid); } - + +/* XXX This is just a trivial wrapper around os_pipe */ static int slirp_datachan(int *mfd, int *sfd) { int fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("slirp_datachan: Failed to open pipe, errno = %d\n", - -err); + if(err < 0){ + printk("slirp_datachan: Failed to open pipe, err = %d\n", -err); return(err); } @@ -77,7 +76,7 @@ static int slirp_open(void *data) pid = slirp_tramp(pri->argw.argv, sfd); if(pid < 0){ - printk("slirp_tramp failed - errno = %d\n", pid); + printk("slirp_tramp failed - errno = %d\n", -pid); os_close_file(sfd); os_close_file(mfd); return(pid); @@ -97,8 +96,8 @@ static void slirp_close(int fd, void *da struct slirp_data *pri = data; int status,err; - close(fd); - close(pri->slave); + os_close_file(fd); + os_close_file(pri->slave); pri->slave = -1; @@ -114,13 +113,13 @@ static void slirp_close(int fd, void *da } #endif - err = waitpid(pri->pid, &status, WNOHANG); - if(err<0) { + CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG)); + if(err < 0) { printk("slirp_close: waitpid returned %d\n", errno); return; } - if(err==0) { + if(err == 0) { printk("slirp_close: process %d has not exited\n"); return; } --- linux-2.6.8-rc1/arch/um/drivers/ssl.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/arch/um/drivers/ssl.c 2004-07-13 17:09:44.000000000 -0700 @@ -10,6 +10,7 @@ #include "linux/major.h" #include "linux/mm.h" #include "linux/init.h" +#include "linux/console.h" #include "asm/termbits.h" #include "asm/irq.h" #include "line.h" @@ -53,8 +54,9 @@ static int ssl_remove(char *str); static struct line_driver driver = { .name = "UML serial line", - .devfs_name = "tts/%d", - .major = TTYAUX_MAJOR, + .device_name = "ttS", + .devfs_name = "tts/", + .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, .subtype = 0, @@ -149,6 +151,9 @@ static int ssl_ioctl(struct tty_struct * case TCSETSW: case TCGETA: case TIOCMGET: + case TCSBRK: + case TCSBRKP: + case TIOCMSET: ret = -ENOIOCTLCMD; break; default: @@ -212,6 +217,37 @@ static struct tty_operations ssl_ops = { */ static int ssl_init_done = 0; +static void ssl_console_write(struct console *c, const char *string, + unsigned len) +{ + struct line *line = &serial_lines[c->index]; + if(ssl_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(ssl_init_done) + up(&line->sem); +} + +static struct tty_driver *ssl_console_device(struct console *c, int *index) +{ + *index = c->index; + return ssl_driver; +} + +static int ssl_console_setup(struct console *co, char *options) +{ + return(0); +} + +static struct console ssl_cons = { + name: "ttyS", + write: ssl_console_write, + device: ssl_console_device, + setup: ssl_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + int ssl_init(void) { char *new_title; @@ -227,17 +263,18 @@ int ssl_init(void) new_title = add_xterm_umid(opts.xterm_title); if(new_title != NULL) opts.xterm_title = new_title; + register_console(&ssl_cons); ssl_init_done = 1; return(0); } -__initcall(ssl_init); +late_initcall(ssl_init); static int ssl_chan_setup(char *str) { - line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), - str, 1); - return(1); + return(line_setup(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), + str, 1)); } __setup("ssl", ssl_chan_setup); --- linux-2.6.8-rc1/arch/um/drivers/stdio_console.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/um/drivers/stdio_console.c 2004-07-13 17:09:44.000000000 -0700 @@ -83,7 +83,8 @@ static int con_remove(char *str); static struct line_driver driver = { .name = "UML console", - .devfs_name = "vc/%d", + .device_name = "tty", + .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, @@ -159,6 +160,15 @@ static int chars_in_buffer(struct tty_st static int con_init_done = 0; +static struct tty_operations console_ops = { + .open = con_open, + .close = con_close, + .write = con_write, + .chars_in_buffer = chars_in_buffer, + .set_termios = set_termios, + .write_room = line_write_room, +}; + int stdio_init(void) { char *new_title; @@ -166,7 +176,8 @@ int stdio_init(void) printk(KERN_INFO "Initializing stdio console driver\n"); console_driver = line_register_devfs(&console_lines, &driver, - &console_ops, vts, sizeof(vts)/sizeof(vts[0])); + &console_ops, vts, + sizeof(vts)/sizeof(vts[0])); lines_init(vts, sizeof(vts)/sizeof(vts[0])); @@ -178,24 +189,19 @@ int stdio_init(void) return(0); } -__initcall(stdio_init); +late_initcall(stdio_init); static void console_write(struct console *console, const char *string, unsigned len) { - if(con_init_done) down(&vts[console->index].sem); - console_write_chan(&vts[console->index].chan_list, string, len); - if(con_init_done) up(&vts[console->index].sem); -} + struct line *line = &vts[console->index]; -static struct tty_operations console_ops = { - .open = con_open, - .close = con_close, - .write = con_write, - .chars_in_buffer = chars_in_buffer, - .set_termios = set_termios, - .write_room = line_write_room, -}; + if(con_init_done) + down(&line->sem); + console_write_chan(&line->chan_list, string, len); + if(con_init_done) + up(&line->sem); +} static struct tty_driver *console_device(struct console *c, int *index) { @@ -208,22 +214,28 @@ static int console_setup(struct console return(0); } -static struct console stdiocons = INIT_CONSOLE("tty", console_write, - console_device, console_setup, - CON_PRINTBUFFER); +static struct console stdiocons = { + name: "tty", + write: console_write, + device: console_device, + setup: console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; -static void __init stdio_console_init(void) +static int __init stdio_console_init(void) { INIT_LIST_HEAD(&vts[0].chan_list); list_add(&init_console_chan.list, &vts[0].chan_list); register_console(&stdiocons); + return(0); } + console_initcall(stdio_console_init); static int console_chan_setup(char *str) { - line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); - return(1); + return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1)); } __setup("con", console_chan_setup); --- linux-2.6.8-rc1/arch/um/drivers/tty.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/arch/um/drivers/tty.c 2004-07-13 17:09:44.000000000 -0700 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include "chan_user.h" @@ -30,7 +29,8 @@ void *tty_chan_init(char *str, int devic } str++; - if((data = um_kmalloc(sizeof(*data))) == NULL) + data = um_kmalloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct tty_chan) { .dev = str, .raw = opts->raw }); --- linux-2.6.8-rc1/arch/um/drivers/ubd_kern.c 2003-11-09 16:45:05.000000000 -0800 +++ 25/arch/um/drivers/ubd_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -8,6 +8,13 @@ * old style ubd by setting UBD_SHIFT to 0 * 2002-09-27...2002-10-18 massive tinkering for 2.5 * partitions have changed in 2.5 + * 2003-01-29 more tinkering for 2.5.59-1 + * This should now address the sysfs problems and has + * the symlink for devfs to allow for booting with + * the common /dev/ubd/discX/... names rather than + * only /dev/ubdN/discN this version also has lots of + * clean ups preparing for ubd-many. + * James McMechan */ #define MAJOR_NR UBD_MAJOR @@ -40,9 +47,12 @@ #include "mconsole_kern.h" #include "init.h" #include "irq_user.h" +#include "irq_kern.h" #include "ubd_user.h" #include "2_5compat.h" #include "os.h" +#include "mem.h" +#include "mem_kern.h" static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED; @@ -56,6 +66,10 @@ static int ubd_ioctl(struct inode * inod #define MAX_DEV (8) +/* Changed in early boot */ +static int ubd_do_mmap = 0; +#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE + static struct block_device_operations ubd_blops = { .owner = THIS_MODULE, .open = ubd_open, @@ -67,7 +81,7 @@ static struct block_device_operations ub static request_queue_t *ubd_queue; /* Protected by ubd_lock */ -static int fake_major = 0; +static int fake_major = MAJOR_NR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -96,13 +110,19 @@ struct cow { struct ubd { char *file; - int is_dir; int count; int fd; __u64 size; struct openflags boot_openflags; struct openflags openflags; + int no_cow; struct cow cow; + + int map_writes; + int map_reads; + int nomap_writes; + int nomap_reads; + int write_maps; }; #define DEFAULT_COW { \ @@ -115,21 +135,28 @@ struct ubd { #define DEFAULT_UBD { \ .file = NULL, \ - .is_dir = 0, \ .count = 0, \ .fd = -1, \ .size = -1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ + .no_cow = 0, \ .cow = DEFAULT_COW, \ + .map_writes = 0, \ + .map_reads = 0, \ + .nomap_writes = 0, \ + .nomap_reads = 0, \ + .write_maps = 0, \ } struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; static int ubd0_init(void) { - if(ubd_dev[0].file == NULL) - ubd_dev[0].file = "root_fs"; + struct ubd *dev = &ubd_dev[0]; + + if(dev->file == NULL) + dev->file = "root_fs"; return(0); } @@ -196,19 +223,46 @@ __uml_help(fake_ide_setup, " Create ide0 entries that map onto ubd devices.\n\n" ); +static int parse_unit(char **ptr) +{ + char *str = *ptr, *end; + int n = -1; + + if(isdigit(*str)) { + n = simple_strtoul(str, &end, 0); + if(end == str) + return(-1); + *ptr = end; + } + else if (('a' <= *str) && (*str <= 'h')) { + n = *str - 'a'; + str++; + *ptr = str; + } + return(n); +} + static int ubd_setup_common(char *str, int *index_out) { + struct ubd *dev; struct openflags flags = global_openflags; char *backing_file; int n, err; if(index_out) *index_out = -1; - n = *str++; + n = *str; if(n == '='){ - static int fake_major_allowed = 1; char *end; int major; + str++; + if(!strcmp(str, "mmap")){ + CHOOSE_MODE(printk("mmap not supported by the ubd " + "driver in tt mode\n"), + ubd_do_mmap = 1); + return(0); + } + if(!strcmp(str, "sync")){ global_openflags.s = 1; return(0); @@ -220,20 +274,14 @@ static int ubd_setup_common(char *str, i return(1); } - if(!fake_major_allowed){ - printk(KERN_ERR "Can't assign a fake major twice\n"); - return(1); - } - err = 1; spin_lock(&ubd_lock); - if(!fake_major_allowed){ + if(fake_major != MAJOR_NR){ printk(KERN_ERR "Can't assign a fake major twice\n"); goto out1; } fake_major = major; - fake_major_allowed = 0; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); @@ -243,25 +291,23 @@ static int ubd_setup_common(char *str, i return(err); } - if(n < '0'){ - printk(KERN_ERR "ubd_setup : index out of range\n"); } - - if((n >= '0') && (n <= '9')) n -= '0'; - else if((n >= 'a') && (n <= 'z')) n -= 'a'; - else { - printk(KERN_ERR "ubd_setup : device syntax invalid\n"); + n = parse_unit(&str); + if(n < 0){ + printk(KERN_ERR "ubd_setup : couldn't parse unit number " + "'%s'\n", str); return(1); } if(n >= MAX_DEV){ - printk(KERN_ERR "ubd_setup : index out of range " - "(%d devices)\n", MAX_DEV); + printk(KERN_ERR "ubd_setup : index %d out of range " + "(%d devices)\n", n, MAX_DEV); return(1); } err = 1; spin_lock(&ubd_lock); - if(ubd_dev[n].file != NULL){ + dev = &ubd_dev[n]; + if(dev->file != NULL){ printk(KERN_ERR "ubd_setup : device already configured\n"); goto out2; } @@ -276,6 +322,11 @@ static int ubd_setup_common(char *str, i flags.s = 1; str++; } + if (*str == 'd'){ + dev->no_cow = 1; + str++; + } + if(*str++ != '='){ printk(KERN_ERR "ubd_setup : Expected '='\n"); goto out2; @@ -284,14 +335,17 @@ static int ubd_setup_common(char *str, i err = 0; backing_file = strchr(str, ','); if(backing_file){ - *backing_file = '\0'; - backing_file++; + if(dev->no_cow) + printk(KERN_ERR "Can't specify both 'd' and a " + "cow file\n"); + else { + *backing_file = '\0'; + backing_file++; + } } - ubd_dev[n].file = str; - if(ubd_is_dir(ubd_dev[n].file)) - ubd_dev[n].is_dir = 1; - ubd_dev[n].cow.file = backing_file; - ubd_dev[n].boot_openflags = flags; + dev->file = str; + dev->cow.file = backing_file; + dev->boot_openflags = flags; out2: spin_unlock(&ubd_lock); return(err); @@ -321,8 +375,7 @@ __uml_help(ubd_setup, static int fakehd_set = 0; static int fakehd(char *str) { - printk(KERN_INFO - "fakehd : Changing ubd name to \"hd\".\n"); + printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n"); fakehd_set = 1; return 1; } @@ -368,32 +421,42 @@ static void ubd_handler(void) { struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); - int n; + int n, err; do_ubd = NULL; intr_count++; n = read_ubd_fs(thread_fd, &req, sizeof(req)); if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " - "errno = %d\n", os_getpid(), -n); + "err = %d\n", os_getpid(), -n); spin_lock(&ubd_io_lock); end_request(rq, 0); spin_unlock(&ubd_io_lock); return; } - if((req.offset != ((__u64) (rq->sector)) << 9) || - (req.length != (rq->current_nr_sectors) << 9)) + if((req.op != UBD_MMAP) && + ((req.offset != ((__u64) (rq->sector)) << 9) || + (req.length != (rq->current_nr_sectors) << 9))) panic("I/O op mismatch"); + if(req.map_fd != -1){ + err = physmem_subst_mapping(req.buffer, req.map_fd, + req.map_offset, 1); + if(err) + printk("ubd_handler - physmem_subst_mapping failed, " + "err = %d\n", -err); + } + ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); } -static void ubd_intr(int irq, void *dev, struct pt_regs *unused) +static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) { ubd_handler(); + return(IRQ_HANDLED); } /* Only changed by ubd_init, which is an initcall. */ @@ -417,10 +480,14 @@ static int ubd_file_size(struct ubd *dev static void ubd_close(struct ubd *dev) { + if(ubd_do_mmap) + physmem_forget_descriptor(dev->fd); os_close_file(dev->fd); if(dev->cow.file == NULL) return; + if(ubd_do_mmap) + physmem_forget_descriptor(dev->cow.fd); os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; @@ -429,18 +496,20 @@ static void ubd_close(struct ubd *dev) static int ubd_open_dev(struct ubd *dev) { struct openflags flags; - int err, n, create_cow, *create_ptr; + char **back_ptr; + int err, create_cow, *create_ptr; + dev->openflags = dev->boot_openflags; create_cow = 0; create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, + back_ptr = dev->no_cow ? NULL : &dev->cow.file; + dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset, create_ptr); if((dev->fd == -ENOENT) && create_cow){ - n = dev - ubd_dev; dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, + dev->openflags, 1 << 9, PAGE_SIZE, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset); @@ -455,13 +524,17 @@ static int ubd_open_dev(struct ubd *dev) if(dev->cow.file != NULL){ err = -ENOMEM; dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL) goto error; + if(dev->cow.bitmap == NULL){ + printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); + goto error; + } flush_tlb_kernel_vm(); err = read_cow_bitmap(dev->fd, dev->cow.bitmap, dev->cow.bitmap_offset, dev->cow.bitmap_len); - if(err) goto error; + if(err < 0) + goto error; flags = dev->openflags; flags.w = 0; @@ -481,17 +554,31 @@ static int ubd_new_disk(int major, u64 s { struct gendisk *disk; + char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; + int err; disk = alloc_disk(1 << UBD_SHIFT); - if (!disk) - return -ENOMEM; + if(disk == NULL) + return(-ENOMEM); disk->major = major; disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - sprintf(disk->disk_name, "ubd"); - sprintf(disk->devfs_name, "ubd/disc%d", unit); + if(major == MAJOR_NR){ + sprintf(disk->disk_name, "ubd%c", 'a' + unit); + sprintf(disk->devfs_name, "ubd/disc%d", unit); + sprintf(from, "ubd/%d", unit); + sprintf(to, "disc%d/disc", unit); + err = devfs_mk_symlink(from, to); + if(err) + printk("ubd_new_disk failed to make link from %s to " + "%s, error = %d\n", from, to, err); + } + else { + sprintf(disk->disk_name, "ubd_fake%d", unit); + sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); + } disk->private_data = &ubd_dev[unit]; disk->queue = ubd_queue; @@ -506,24 +593,21 @@ static int ubd_add(int n) struct ubd *dev = &ubd_dev[n]; int err; - if(dev->is_dir) - return(-EISDIR); - - if (!dev->file) + if(dev->file == NULL) return(-ENODEV); if (ubd_open_dev(dev)) return(-ENODEV); err = ubd_file_size(dev, &dev->size); - if(err) + if(err < 0) return(err); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); if(err) return(err); - if(fake_major) + if(fake_major != MAJOR_NR) ubd_new_disk(fake_major, dev->size, n, &fake_gendisk[n]); @@ -561,42 +645,42 @@ static int ubd_config(char *str) return(err); } -static int ubd_get_config(char *dev, char *str, int size, char **error_out) +static int ubd_get_config(char *name, char *str, int size, char **error_out) { - struct ubd *ubd; + struct ubd *dev; char *end; - int major, n = 0; + int n, len = 0; - major = simple_strtoul(dev, &end, 0); - if((*end != '\0') || (end == dev)){ - *error_out = "ubd_get_config : didn't parse major number"; + n = simple_strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + *error_out = "ubd_get_config : didn't parse device number"; return(-1); } - if((major >= MAX_DEV) || (major < 0)){ - *error_out = "ubd_get_config : major number out of range"; + if((n >= MAX_DEV) || (n < 0)){ + *error_out = "ubd_get_config : device number out of range"; return(-1); } - ubd = &ubd_dev[major]; + dev = &ubd_dev[n]; spin_lock(&ubd_lock); - if(ubd->file == NULL){ - CONFIG_CHUNK(str, size, n, "", 1); + if(dev->file == NULL){ + CONFIG_CHUNK(str, size, len, "", 1); goto out; } - CONFIG_CHUNK(str, size, n, ubd->file, 0); + CONFIG_CHUNK(str, size, len, dev->file, 0); - if(ubd->cow.file != NULL){ - CONFIG_CHUNK(str, size, n, ",", 0); - CONFIG_CHUNK(str, size, n, ubd->cow.file, 1); + if(dev->cow.file != NULL){ + CONFIG_CHUNK(str, size, len, ",", 0); + CONFIG_CHUNK(str, size, len, dev->cow.file, 1); } - else CONFIG_CHUNK(str, size, n, "", 1); + else CONFIG_CHUNK(str, size, len, "", 1); out: spin_unlock(&ubd_lock); - return(n); + return(len); } static int ubd_remove(char *str) @@ -604,11 +688,9 @@ static int ubd_remove(char *str) struct ubd *dev; int n, err = -ENODEV; - if(!isdigit(*str)) - return(err); /* it should be a number 0-7/a-h */ + n = parse_unit(&str); - n = *str - '0'; - if(n >= MAX_DEV) + if((n < 0) || (n >= MAX_DEV)) return(err); dev = &ubd_dev[n]; @@ -669,7 +751,7 @@ int ubd_init(void) elevator_init(ubd_queue, &elevator_noop); - if (fake_major != 0) { + if (fake_major != MAJOR_NR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); @@ -696,6 +778,7 @@ int ubd_driver_init(void){ io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ + io_pid = -1; printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); @@ -703,8 +786,8 @@ int ubd_driver_init(void){ } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, SA_INTERRUPT, "ubd", ubd_dev); - if(err != 0) printk(KERN_ERR - "um_request_irq failed - errno = %d\n", -err); + if(err != 0) + printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return(err); } @@ -714,15 +797,9 @@ static int ubd_open(struct inode *inode, { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - int err = -EISDIR; + int err = 0; - if(dev->is_dir == 1) - goto out; - - err = 0; if(dev->count == 0){ - dev->openflags = dev->boot_openflags; - err = ubd_open_dev(dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", @@ -749,62 +826,156 @@ static int ubd_release(struct inode * in return(0); } -void cowify_req(struct io_thread_req *req, struct ubd *dev) +static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, + __u64 *cow_offset, unsigned long *bitmap, + __u64 bitmap_offset, unsigned long *bitmap_words, + __u64 bitmap_len) +{ + __u64 sector = io_offset >> 9; + int i, update_bitmap = 0; + + for(i = 0; i < length >> 9; i++){ + if(cow_mask != NULL) + ubd_set_bit(i, (unsigned char *) cow_mask); + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) + continue; + + update_bitmap = 1; + ubd_set_bit(sector + i, (unsigned char *) bitmap); + } + + if(!update_bitmap) + return; + + *cow_offset = sector / (sizeof(unsigned long) * 8); + + /* This takes care of the case where we're exactly at the end of the + * device, and *cow_offset + 1 is off the end. So, just back it up + * by one word. Thanks to Lynn Kerby for the fix and James McMechan + * for the original diagnosis. + */ + if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / + sizeof(unsigned long) - 1)) + (*cow_offset)--; + + bitmap_words[0] = bitmap[*cow_offset]; + bitmap_words[1] = bitmap[*cow_offset + 1]; + + *cow_offset *= sizeof(unsigned long); + *cow_offset += bitmap_offset; +} + +static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, + __u64 bitmap_offset, __u64 bitmap_len) { - int i, update_bitmap, sector = req->offset >> 9; + __u64 sector = req->offset >> 9; + int i; if(req->length > (sizeof(req->sector_mask) * 8) << 9) panic("Operation too long"); + if(req->op == UBD_READ) { for(i = 0; i < req->length >> 9; i++){ - if(ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)){ + if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) ubd_set_bit(i, (unsigned char *) &req->sector_mask); - } } - } - else { - update_bitmap = 0; - for(i = 0; i < req->length >> 9; i++){ - ubd_set_bit(i, (unsigned char *) - &req->sector_mask); - if(!ubd_test_bit(sector + i, (unsigned char *) - dev->cow.bitmap)) - update_bitmap = 1; - ubd_set_bit(sector + i, (unsigned char *) - dev->cow.bitmap); - } - if(update_bitmap){ - req->cow_offset = sector / (sizeof(unsigned long) * 8); - req->bitmap_words[0] = - dev->cow.bitmap[req->cow_offset]; - req->bitmap_words[1] = - dev->cow.bitmap[req->cow_offset + 1]; - req->cow_offset *= sizeof(unsigned long); - req->cow_offset += dev->cow.bitmap_offset; + } + else cowify_bitmap(req->offset, req->length, &req->sector_mask, + &req->cow_offset, bitmap, bitmap_offset, + req->bitmap_words, bitmap_len); +} + +static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) +{ + __u64 sector; + unsigned char *bitmap; + int bit, i; + + /* mmap must have been requested on the command line */ + if(!ubd_do_mmap) + return(-1); + + /* The buffer must be page aligned */ + if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + /* The request must be a page long */ + if((req->current_nr_sectors << 9) != PAGE_SIZE) + return(-1); + + if(dev->cow.file == NULL) + return(dev->fd); + + sector = offset >> 9; + bitmap = (unsigned char *) dev->cow.bitmap; + bit = ubd_test_bit(sector, bitmap); + + for(i = 1; i < req->current_nr_sectors; i++){ + if(ubd_test_bit(sector + i, bitmap) != bit) + return(-1); + } + + if(bit || (rq_data_dir(req) == WRITE)) + offset += dev->cow.data_offset; + + /* The data on disk must be page aligned */ + if((offset % UBD_MMAP_BLOCK_SIZE) != 0) + return(-1); + + return(bit ? dev->fd : dev->cow.fd); +} + +static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, + struct request *req, + struct io_thread_req *io_req) +{ + int err; + + if(rq_data_dir(req) == WRITE){ + /* Writes are almost no-ops since the new data is already in the + * host page cache + */ + dev->map_writes++; + if(dev->cow.file != NULL) + cowify_bitmap(io_req->offset, io_req->length, + &io_req->sector_mask, &io_req->cow_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + io_req->bitmap_words, + dev->cow.bitmap_len); + } + else { + int w; + + if((dev->cow.file != NULL) && (fd == dev->cow.fd)) + w = 0; + else w = dev->openflags.w; + + if((dev->cow.file != NULL) && (fd == dev->fd)) + offset += dev->cow.data_offset; + + err = physmem_subst_mapping(req->buffer, fd, offset, w); + if(err){ + printk("physmem_subst_mapping failed, err = %d\n", + -err); + return(1); } + dev->map_reads++; } + io_req->op = UBD_MMAP; + io_req->buffer = req->buffer; + return(0); } static int prepare_request(struct request *req, struct io_thread_req *io_req) { struct gendisk *disk = req->rq_disk; struct ubd *dev = disk->private_data; - __u64 block; - int nsect; + __u64 offset; + int len, fd; if(req->rq_status == RQ_INACTIVE) return(1); - if(dev->is_dir){ - strcpy(req->buffer, "HOSTFS:"); - strcat(req->buffer, dev->file); - spin_lock(&ubd_io_lock); - end_request(req, 1); - spin_unlock(&ubd_io_lock); - return(1); - } - if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %s\n", disk->disk_name); @@ -814,23 +985,49 @@ static int prepare_request(struct reques return(1); } - block = req->sector; - nsect = req->current_nr_sectors; + offset = ((__u64) req->sector) << 9; + len = req->current_nr_sectors << 9; - io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE; io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; io_req->fds[1] = dev->fd; + io_req->map_fd = -1; + io_req->cow_offset = -1; + io_req->offset = offset; + io_req->length = len; + io_req->error = 0; + io_req->sector_mask = 0; + + fd = mmap_fd(req, dev, io_req->offset); + if(fd > 0){ + /* If mmapping is otherwise OK, but the first access to the + * page is a write, then it's not mapped in yet. So we have + * to write the data to disk first, then we can map the disk + * page in and continue normally from there. + */ + if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ + io_req->map_fd = dev->fd; + io_req->map_offset = io_req->offset + + dev->cow.data_offset; + dev->write_maps++; + } + else return(prepare_mmap_request(dev, fd, io_req->offset, req, + io_req)); + } + + if(rq_data_dir(req) == READ) + dev->nomap_reads++; + else dev->nomap_writes++; + + io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; io_req->offsets[0] = 0; io_req->offsets[1] = dev->cow.data_offset; - io_req->offset = ((__u64) block) << 9; - io_req->length = nsect << 9; io_req->buffer = req->buffer; io_req->sectorsize = 1 << 9; - io_req->sector_mask = 0; - io_req->cow_offset = -1; - io_req->error = 0; - if(dev->cow.file != NULL) cowify_req(io_req, dev); + if(dev->cow.file != NULL) + cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, + dev->cow.bitmap_len); + return(0); } @@ -841,7 +1038,7 @@ static void do_ubd_request(request_queue int err, n; if(thread_fd == -1){ - while(!list_empty(&q->queue_head)){ + while(!elv_queue_empty(q)){ req = elv_next_request(q); err = prepare_request(req, &io_req); if(!err){ @@ -851,7 +1048,8 @@ static void do_ubd_request(request_queue } } else { - if(do_ubd || list_empty(&q->queue_head)) return; + if(do_ubd || elv_queue_empty(q)) + return; req = elv_next_request(q); err = prepare_request(req, &io_req); if(!err){ @@ -885,7 +1083,7 @@ static int ubd_ioctl(struct inode * inod g.heads = 128; g.sectors = 32; g.cylinders = dev->size / (128 * 32 * 512); - g.start = 2; + g.start = get_start_sect(inode->i_bdev); return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); case HDIO_SET_UNMASKINTR: @@ -935,6 +1133,142 @@ static int ubd_ioctl(struct inode * inod return(-EINVAL); } +static int ubd_check_remapped(int fd, unsigned long address, int is_write, + __u64 offset) +{ + __u64 bitmap_offset; + unsigned long new_bitmap[2]; + int i, err, n; + + /* If it's not a write access, we can't do anything about it */ + if(!is_write) + return(0); + + /* We have a write */ + for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ + struct ubd *dev = &ubd_dev[i]; + + if((dev->fd != fd) && (dev->cow.fd != fd)) + continue; + + /* It's a write to a ubd device */ + + if(!dev->openflags.w){ + /* It's a write access on a read-only device - probably + * shouldn't happen. If the kernel is trying to change + * something with no intention of writing it back out, + * then this message will clue us in that this needs + * fixing + */ + printk("Write access to mapped page from readonly ubd " + "device %d\n", i); + return(0); + } + + /* It's a write to a writeable ubd device - it must be COWed + * because, otherwise, the page would have been mapped in + * writeable + */ + + if(!dev->cow.file) + panic("Write fault on writeable non-COW ubd device %d", + i); + + /* It should also be an access to the backing file since the + * COW pages should be mapped in read-write + */ + + if(fd == dev->fd) + panic("Write fault on a backing page of ubd " + "device %d\n", i); + + /* So, we do the write, copying the backing data to the COW + * file... + */ + + err = os_seek_file(dev->fd, offset + dev->cow.data_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", + offset + dev->cow.data_offset, i, -err); + + n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Couldn't copy data to COW file of ubd " + "device %d, err = %d", i, -n); + + /* ... updating the COW bitmap... */ + + cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, + dev->cow.bitmap, dev->cow.bitmap_offset, + new_bitmap, dev->cow.bitmap_len); + + err = os_seek_file(dev->fd, bitmap_offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of ubd " + "device %d, err = %d", bitmap_offset, i, -err); + + n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); + if(n != sizeof(new_bitmap)) + panic("Couldn't update bitmap of ubd device %d, " + "err = %d", i, -n); + + /* Maybe we can map the COW page in, and maybe we can't. If + * it is a pre-V3 COW file, we can't, since the alignment will + * be wrong. If it is a V3 or later COW file which has been + * moved to a system with a larger page size, then maybe we + * can't, depending on the exact location of the page. + */ + + offset += dev->cow.data_offset; + + /* Remove the remapping, putting the original anonymous page + * back. If the COW file can be mapped in, that is done. + * Otherwise, the COW page is read in. + */ + + if(!physmem_remove_mapping((void *) address)) + panic("Address 0x%lx not remapped by ubd device %d", + address, i); + if((offset % UBD_MMAP_BLOCK_SIZE) == 0) + physmem_subst_mapping((void *) address, dev->fd, + offset, 1); + else { + err = os_seek_file(dev->fd, offset); + if(err < 0) + panic("Couldn't seek to %lld in COW file of " + "ubd device %d, err = %d", offset, i, + -err); + + n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); + if(n != PAGE_SIZE) + panic("Failed to read page from offset %llx of " + "COW file of ubd device %d, err = %d", + offset, i, -n); + } + + return(1); + } + + /* It's not a write on a ubd device */ + return(0); +} + +static struct remapper ubd_remapper = { + .list = LIST_HEAD_INIT(ubd_remapper.list), + .proc = ubd_check_remapped, +}; + +static int ubd_remapper_setup(void) +{ + if(ubd_do_mmap) + register_remapper(&ubd_remapper); + + return(0); +} + +__initcall(ubd_remapper_setup); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- linux-2.6.8-rc1/arch/um/drivers/ubd_user.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/um/drivers/ubd_user.c 2004-07-13 17:09:44.000000000 -0700 @@ -11,11 +11,8 @@ #include #include #include -#include #include -#include #include -#include #include #include #include "asm/types.h" @@ -24,146 +21,30 @@ #include "user.h" #include "ubd_user.h" #include "os.h" +#include "cow.h" #include #include -#if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -#elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -#else -#error "__BYTE_ORDER not defined" -#endif - -#define PATH_LEN_V1 256 - -struct cow_header_v1 { - int magic; - int version; - char backing_file[PATH_LEN_V1]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -#define PATH_LEN_V2 MAXPATHLEN - -struct cow_header_v2 { - unsigned long magic; - unsigned long version; - char backing_file[PATH_LEN_V2]; - time_t mtime; - __u64 size; - int sectorsize; -}; - -union cow_header { - struct cow_header_v1 v1; - struct cow_header_v2 v2; -}; - -#define COW_MAGIC 0x4f4f4f4d /* MOOO */ -#define COW_VERSION 2 - -static void sizes(__u64 size, int sectorsize, int bitmap_offset, - unsigned long *bitmap_len_out, int *data_offset_out) -{ - *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); - - *data_offset_out = bitmap_offset + *bitmap_len_out; - *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; - *data_offset_out *= sectorsize; -} - -static int read_cow_header(int fd, int *magic_out, char **backing_file_out, - time_t *mtime_out, __u64 *size_out, - int *sectorsize_out, int *bitmap_offset_out) -{ - union cow_header *header; - char *file; - int err, n; - unsigned long version, magic; - - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("read_cow_header - Failed to allocate header\n"); - return(-ENOMEM); - } - err = -EINVAL; - n = read(fd, header, sizeof(*header)); - if(n < offsetof(typeof(header->v1), backing_file)){ - printk("read_cow_header - short header\n"); - goto out; - } - - magic = header->v1.magic; - if(magic == COW_MAGIC) { - version = header->v1.version; - } - else if(magic == ntohl(COW_MAGIC)){ - version = ntohl(header->v1.version); - } - else goto out; - - *magic_out = COW_MAGIC; - - if(version == 1){ - if(n < sizeof(header->v1)){ - printk("read_cow_header - failed to read V1 header\n"); - goto out; - } - *mtime_out = header->v1.mtime; - *size_out = header->v1.size; - *sectorsize_out = header->v1.sectorsize; - *bitmap_offset_out = sizeof(header->v1); - file = header->v1.backing_file; - } - else if(version == 2){ - if(n < sizeof(header->v2)){ - printk("read_cow_header - failed to read V2 header\n"); - goto out; - } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); - *bitmap_offset_out = sizeof(header->v2); - file = header->v2.backing_file; - } - else { - printk("read_cow_header - invalid COW version\n"); - goto out; - } - err = -ENOMEM; - *backing_file_out = uml_strdup(file); - if(*backing_file_out == NULL){ - printk("read_cow_header - failed to allocate backing file\n"); - goto out; - } - err = 0; - out: - kfree(header); - return(err); -} static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { - struct stat buf1, buf2; + struct uml_stat buf1, buf2; + int err; if(from_cmdline == NULL) return(1); if(!strcmp(from_cmdline, from_cow)) return(1); - if(stat(from_cmdline, &buf1) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cmdline, - errno); + err = os_stat_file(from_cmdline, &buf1); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); return(1); } - if(stat(from_cow, &buf2) < 0){ - printk("Couldn't stat '%s', errno = %d\n", from_cow, errno); + err = os_stat_file(from_cow, &buf2); + if(err < 0){ + printk("Couldn't stat '%s', err = %d\n", from_cow, -err); return(1); } - if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino)) + if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) return(1); printk("Backing file mismatch - \"%s\" requested,\n" @@ -174,20 +55,21 @@ static int same_backing_files(char *from static int backing_file_mismatch(char *file, __u64 size, time_t mtime) { - struct stat64 buf; + unsigned long modtime; long long actual; int err; - if(stat64(file, &buf) < 0){ - printk("Failed to stat backing file \"%s\", errno = %d\n", - file, errno); - return(-errno); + err = os_file_modtime(file, &modtime); + if(err < 0){ + printk("Failed to get modification time of backing file " + "\"%s\", err = %d\n", file, -err); + return(err); } err = os_file_size(file, &actual); - if(err){ + if(err < 0){ printk("Failed to get size of backing file \"%s\", " - "errno = %d\n", file, -err); + "err = %d\n", file, -err); return(err); } @@ -196,9 +78,9 @@ static int backing_file_mismatch(char *f "file\n", size, actual); return(-EINVAL); } - if(buf.st_mtime != mtime){ + if(modtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", mtime, buf.st_mtime); + "file\n", mtime, modtime); return(-EINVAL); } return(0); @@ -209,124 +91,16 @@ int read_cow_bitmap(int fd, void *buf, i int err; err = os_seek_file(fd, offset); - if(err != 0) return(-errno); - err = read(fd, buf, len); - if(err < 0) return(-errno); - return(0); -} + if(err < 0) + return(err); -static int absolutize(char *to, int size, char *from) -{ - char save_cwd[256], *slash; - int remaining; + err = os_read_file(fd, buf, len); + if(err < 0) + return(err); - if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { - printk("absolutize : unable to get cwd - errno = %d\n", errno); - return(-1); - } - slash = strrchr(from, '/'); - if(slash != NULL){ - *slash = '\0'; - if(chdir(from)){ - *slash = '/'; - printk("absolutize : Can't cd to '%s' - errno = %d\n", - from, errno); - return(-1); - } - *slash = '/'; - if(getcwd(to, size) == NULL){ - printk("absolutize : unable to get cwd of '%s' - " - "errno = %d\n", from, errno); - return(-1); - } - remaining = size - strlen(to); - if(strlen(slash) + 1 > remaining){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcat(to, slash); - } - else { - if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ - printk("absolutize : unable to fit '%s' into %d " - "chars\n", from, size); - return(-1); - } - strcpy(to, save_cwd); - strcat(to, "/"); - strcat(to, from); - } - chdir(save_cwd); return(0); } -static int write_cow_header(char *cow_file, int fd, char *backing_file, - int sectorsize, long long *size) -{ - struct cow_header_v2 *header; - struct stat64 buf; - int err; - - err = os_seek_file(fd, 0); - if(err != 0){ - printk("write_cow_header - lseek failed, errno = %d\n", errno); - return(-errno); - } - - err = -ENOMEM; - header = um_kmalloc(sizeof(*header)); - if(header == NULL){ - printk("Failed to allocate COW V2 header\n"); - goto out; - } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); - - err = -EINVAL; - if(strlen(backing_file) > sizeof(header->backing_file) - 1){ - printk("Backing file name \"%s\" is too long - names are " - "limited to %d characters\n", backing_file, - sizeof(header->backing_file) - 1); - goto out_free; - } - - if(absolutize(header->backing_file, sizeof(header->backing_file), - backing_file)) - goto out_free; - - err = stat64(header->backing_file, &buf); - if(err < 0){ - printk("Stat of backing file '%s' failed, errno = %d\n", - header->backing_file, errno); - err = -errno; - goto out_free; - } - - err = os_file_size(header->backing_file, size); - if(err){ - printk("Couldn't get size of backing file '%s', errno = %d\n", - header->backing_file, -*size); - goto out_free; - } - - header->mtime = htonl(buf.st_mtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - - err = write(fd, header, sizeof(*header)); - if(err != sizeof(*header)){ - printk("Write of header to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_free; - } - err = 0; - out_free: - kfree(header); - out: - return(err); -} - int open_ubd_file(char *file, struct openflags *openflags, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, @@ -334,26 +108,36 @@ int open_ubd_file(char *file, struct ope { time_t mtime; __u64 size; + __u32 version, align; char *backing_file; - int fd, err, sectorsize, magic, same, mode = 0644; + int fd, err, sectorsize, same, mode = 0644; - if((fd = os_open_file(file, *openflags, mode)) < 0){ + fd = os_open_file(file, *openflags, mode); + if(fd < 0){ if((fd == -ENOENT) && (create_cow_out != NULL)) *create_cow_out = 1; if(!openflags->w || ((errno != EROFS) && (errno != EACCES))) return(-errno); openflags->w = 0; - if((fd = os_open_file(file, *openflags, mode)) < 0) + fd = os_open_file(file, *openflags, mode); + if(fd < 0) return(fd); } + + err = os_lock_file(fd, openflags->w); + if(err < 0){ + printk("Failed to lock '%s', err = %d\n", file, -err); + goto out_close; + } + if(backing_file_out == NULL) return(fd); - err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, - §orsize, bitmap_offset_out); + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, + &size, §orsize, &align, bitmap_offset_out); if(err && (*backing_file_out != NULL)){ printk("Failed to read COW header from COW file \"%s\", " - "errno = %d\n", file, err); - goto error; + "errno = %d\n", file, -err); + goto out_close; } if(err) return(fd); @@ -363,36 +147,33 @@ int open_ubd_file(char *file, struct ope if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ printk("Switching backing file to '%s'\n", *backing_file_out); - err = write_cow_header(file, fd, *backing_file_out, - sectorsize, &size); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); if(err){ - printk("Switch failed, errno = %d\n", err); + printk("Switch failed, errno = %d\n", -err); return(err); } } else { *backing_file_out = backing_file; err = backing_file_mismatch(*backing_file_out, size, mtime); - if(err) goto error; + if(err) goto out_close; } - sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, - data_offset_out); + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); return(fd); - error: - close(fd); + out_close: + os_close_file(fd); return(err); } int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int *bitmap_offset_out, + int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out) { - __u64 blocks; - long zero; - int err, fd, i; - long long size; + int err, fd; flags.c = 1; fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); @@ -403,57 +184,49 @@ int create_cow_file(char *cow_file, char goto out; } - err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size); - if(err) goto out_close; - - blocks = (size + sectorsize - 1) / sectorsize; - blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8); - zero = 0; - for(i = 0; i < blocks; i++){ - err = write(fd, &zero, sizeof(zero)); - if(err != sizeof(zero)){ - printk("Write of bitmap to new COW file '%s' failed, " - "errno = %d\n", cow_file, errno); - goto out_close; - } - } - - sizes(size, sectorsize, sizeof(struct cow_header_v2), - bitmap_len_out, data_offset_out); - *bitmap_offset_out = sizeof(struct cow_header_v2); - - return(fd); - - out_close: - close(fd); + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, + bitmap_offset_out, bitmap_len_out, + data_offset_out); + if(!err) + return(fd); + os_close_file(fd); out: return(err); } +/* XXX Just trivial wrappers around os_read_file and os_write_file */ int read_ubd_fs(int fd, void *buffer, int len) { - int n; - - n = read(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_read_file(fd, buffer, len)); } int write_ubd_fs(int fd, char *buffer, int len) { - int n; - - n = write(fd, buffer, len); - if(n < 0) return(-errno); - else return(n); + return(os_write_file(fd, buffer, len)); } -int ubd_is_dir(char *file) +static int update_bitmap(struct io_thread_req *req) { - struct stat64 buf; + int n; + + if(req->cow_offset == -1) + return(0); + + n = os_seek_file(req->fds[1], req->cow_offset); + if(n < 0){ + printk("do_io - bitmap lseek failed : err = %d\n", -n); + return(1); + } + + n = os_write_file(req->fds[1], &req->bitmap_words, + sizeof(req->bitmap_words)); + if(n != sizeof(req->bitmap_words)){ + printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, + req->fds[1]); + return(1); + } - if(stat64(file, &buf) < 0) return(0); - return(S_ISDIR(buf.st_mode)); + return(0); } void do_io(struct io_thread_req *req) @@ -461,8 +234,18 @@ void do_io(struct io_thread_req *req) char *buf; unsigned long len; int n, nsectors, start, end, bit; + int err; __u64 off; + if(req->op == UBD_MMAP){ + /* Touch the page to force the host to do any necessary IO to + * get it into memory + */ + n = *((volatile int *) req->buffer); + req->error = update_bitmap(req); + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -473,15 +256,14 @@ void do_io(struct io_thread_req *req) &req->sector_mask) == bit)) end++; - if(end != nsectors) - printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; buf = &req->buffer[start * req->sectorsize]; - if(os_seek_file(req->fds[bit], off) != 0){ - printk("do_io - lseek failed : errno = %d\n", errno); + err = os_seek_file(req->fds[bit], off); + if(err < 0){ + printk("do_io - lseek failed : err = %d\n", -err); req->error = 1; return; } @@ -490,11 +272,10 @@ void do_io(struct io_thread_req *req) do { buf = &buf[n]; len -= n; - n = read(req->fds[bit], buf, len); + n = os_read_file(req->fds[bit], buf, len); if (n < 0) { - printk("do_io - read returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - read failed, err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -502,11 +283,10 @@ void do_io(struct io_thread_req *req) if (n < len) memset(&buf[n], 0, len - n); } else { - n = write(req->fds[bit], buf, len); + n = os_write_file(req->fds[bit], buf, len); if(n != len){ - printk("do_io - write returned %d : " - "errno = %d fd = %d\n", n, - errno, req->fds[bit]); + printk("do_io - write failed err = %d " + "fd = %d\n", -n, req->fds[bit]); req->error = 1; return; } @@ -515,24 +295,7 @@ void do_io(struct io_thread_req *req) start = end; } while(start < nsectors); - if(req->cow_offset != -1){ - if(os_seek_file(req->fds[1], req->cow_offset) != 0){ - printk("do_io - bitmap lseek failed : errno = %d\n", - errno); - req->error = 1; - return; - } - n = write(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); - if(n != sizeof(req->bitmap_words)){ - printk("do_io - bitmap update returned %d : " - "errno = %d fd = %d\n", n, errno, req->fds[1]); - req->error = 1; - return; - } - } - req->error = 0; - return; + req->error = update_bitmap(req); } /* Changed in start_io_thread, which is serialized by being called only @@ -550,19 +313,23 @@ int io_thread(void *arg) signal(SIGWINCH, SIG_IGN); while(1){ - n = read(kernel_fd, &req, sizeof(req)); - if(n < 0) printk("io_thread - read returned %d, errno = %d\n", - n, errno); - else if(n < sizeof(req)){ - printk("io_thread - short read : length = %d\n", n); + n = os_read_file(kernel_fd, &req, sizeof(req)); + if(n != sizeof(req)){ + if(n < 0) + printk("io_thread - read failed, fd = %d, " + "err = %d\n", kernel_fd, -n); + else { + printk("io_thread - short read, fd = %d, " + "length = %d\n", kernel_fd, n); + } continue; } io_count++; do_io(&req); - n = write(kernel_fd, &req, sizeof(req)); + n = os_write_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)) - printk("io_thread - write failed, errno = %d\n", - errno); + printk("io_thread - write failed, fd = %d, err = %d\n", + kernel_fd, -n); } } @@ -571,10 +338,11 @@ int start_io_thread(unsigned long sp, in int pid, fds[2], err; err = os_pipe(fds, 1, 1); - if(err){ - printk("start_io_thread - os_pipe failed, errno = %d\n", -err); - return(-1); + if(err < 0){ + printk("start_io_thread - os_pipe failed, err = %d\n", -err); + goto out; } + kernel_fd = fds[0]; *fd_out = fds[1]; @@ -582,32 +350,19 @@ int start_io_thread(unsigned long sp, in NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); + goto out_close; } - return(pid); -} - -#ifdef notdef -int start_io_thread(unsigned long sp, int *fd_out) -{ - int pid; - if((kernel_fd = get_pty()) < 0) return(-1); - raw(kernel_fd, 0); - if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){ - printk("Couldn't open tty for IO\n"); - return(-1); - } - - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); - if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } return(pid); + + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + kernel_fd = -1; + *fd_out = -1; + out: + return(err); } -#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. --- linux-2.6.8-rc1/arch/um/drivers/xterm.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/drivers/xterm.c 2004-07-13 17:09:44.000000000 -0700 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,8 @@ void *xterm_init(char *str, int device, { struct xterm_chan *data; - if((data = malloc(sizeof(*data))) == NULL) return(NULL); + data = malloc(sizeof(*data)); + if(data == NULL) return(NULL); *data = ((struct xterm_chan) { .pid = -1, .helper_pid = -1, .device = device, @@ -93,7 +93,7 @@ int xterm_open(int input, int output, in "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; - if(access(argv[4], X_OK)) + if(os_access(argv[4], OS_ACC_X_OK) < 0) argv[4] = "port-helper"; fd = mkstemp(file); @@ -106,13 +106,13 @@ int xterm_open(int input, int output, in printk("xterm_open : unlink failed, errno = %d\n", errno); return(-errno); } - close(fd); + os_close_file(fd); - fd = create_unix_socket(file, sizeof(file)); + fd = os_create_unix_socket(file, sizeof(file), 1); if(fd < 0){ printk("xterm_open : create_unix_socket failed, errno = %d\n", -fd); - return(-fd); + return(fd); } sprintf(title, data->title, data->device); @@ -128,15 +128,16 @@ int xterm_open(int input, int output, in if(data->direct_rcv) new = os_rcv_fd(fd, &data->helper_pid); else { - if((err = os_set_fd_block(fd, 0)) != 0){ + err = os_set_fd_block(fd, 0); + if(err < 0){ printk("xterm_open : failed to set descriptor " - "non-blocking, errno = %d\n", err); + "non-blocking, err = %d\n", -err); return(err); } new = xterm_fd(fd, &data->helper_pid); } if(new < 0){ - printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new); + printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); goto out; } @@ -160,7 +161,7 @@ void xterm_close(int fd, void *d) if(data->helper_pid != -1) os_kill_process(data->helper_pid, 0); data->helper_pid = -1; - close(fd); + os_close_file(fd); } void xterm_free(void *d) --- linux-2.6.8-rc1/arch/um/drivers/xterm_kern.c 2003-06-14 12:18:28.000000000 -0700 +++ 25/arch/um/drivers/xterm_kern.c 2004-07-13 17:09:44.000000000 -0700 @@ -5,9 +5,12 @@ #include "linux/errno.h" #include "linux/slab.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "asm/irq.h" #include "irq_user.h" +#include "irq_kern.h" #include "kern_util.h" #include "os.h" #include "xterm.h" @@ -19,17 +22,18 @@ struct xterm_wait { int new_fd; }; -static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) +static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs) { struct xterm_wait *xterm = data; int fd; fd = os_rcv_fd(xterm->fd, &xterm->pid); if(fd == -EAGAIN) - return; + return(IRQ_NONE); xterm->new_fd = fd; up(&xterm->sem); + return(IRQ_HANDLED); } int xterm_fd(int socket, int *pid_out) @@ -54,7 +58,8 @@ int xterm_fd(int socket, int *pid_out) if(err){ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); - return(err); + ret = err; + goto out; } down(&data->sem); @@ -62,6 +67,7 @@ int xterm_fd(int socket, int *pid_out) ret = data->new_fd; *pid_out = data->pid; + out: kfree(data); return(ret); --- linux-2.6.8-rc1/arch/um/dyn.lds.S 2003-06-14 12:18:21.000000000 -0700 +++ 25/arch/um/dyn.lds.S 2004-07-13 17:09:44.000000000 -0700 @@ -1,3 +1,5 @@ +#include + OUTPUT_FORMAT(ELF_FORMAT) OUTPUT_ARCH(ELF_ARCH) ENTRY(_start) @@ -10,12 +12,15 @@ SECTIONS { . = START + SIZEOF_HEADERS; .interp : { *(.interp) } - . = ALIGN(4096); __binary_start = .; . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); @@ -55,7 +60,9 @@ SECTIONS } =0x90909090 .plt : { *(.plt) } .text : { - *(.text .stub .text.* .gnu.linkonce.t.*) + *(.text) + SCHED_TEXT + *(.stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0x90909090 @@ -67,7 +74,7 @@ SECTIONS #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(.init.data) } /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but --- linux-2.6.8-rc1/arch/um/include/2_5compat.h 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/um/include/2_5compat.h 2004-07-13 17:09:44.000000000 -0700 @@ -6,20 +6,6 @@ #ifndef __2_5_COMPAT_H__ #define __2_5_COMPAT_H__ -#include "linux/version.h" - -#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \ - name : dev_name, \ - write : write_proc, \ - read : NULL, \ - device : device_proc, \ - setup : setup_proc, \ - flags : f, \ - index : -1, \ - cflag : 0, \ - next : NULL \ -} - #define INIT_HARDSECT(arr, maj, sizes) #define SET_PRI(task) do ; while(0) --- linux-2.6.8-rc1/arch/um/include/hostaudio.h 2003-06-14 12:18:22.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#ifndef HOSTAUDIO_H -#define HOSTAUDIO_H - -#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" -#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" - -struct hostaudio_state { - int fd; -}; - -struct hostmixer_state { - int fd; -}; - -/* UML user-side protoypes */ -extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, - size_t count, loff_t *ppos); -extern ssize_t hostaudio_write_user(struct hostaudio_state *state, - const char *buffer, size_t count, - loff_t *ppos); -extern int hostaudio_ioctl_user(struct hostaudio_state *state, - unsigned int cmd, unsigned long arg); -extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, - char *dsp); -extern int hostaudio_release_user(struct hostaudio_state *state); -extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, - unsigned int cmd, unsigned long arg); -extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, - int w, char *mixer); -extern int hostmixer_release_mixdev_user(struct hostmixer_state *state); - -#endif /* HOSTAUDIO_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/include/irq_kern.h 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __IRQ_KERN_H__ +#define __IRQ_KERN_H__ + +#include "linux/interrupt.h" + +extern int um_request_irq(unsigned int irq, int fd, int type, + irqreturn_t (*handler)(int, void *, + struct pt_regs *), + unsigned long irqflags, const char * devname, + void *dev_id); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/include/kern_util.h 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/um/include/kern_util.h 2004-07-13 17:09:44.000000000 -0700 @@ -60,12 +60,11 @@ extern void finish_fork(void); extern void paging_init(void); extern void init_flush_vm(void); extern void *syscall_sp(void *t); -extern void syscall_trace(void); +extern void syscall_trace(union uml_pt_regs *regs, int entryexit); extern int hz(void); -extern void idle_timer(void); +extern void uml_idle_timer(void); extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); extern int external_pid(void *t); -extern int pid_to_processor_id(int pid); extern void boot_timer_handler(int sig); extern void interrupt_end(void); extern void initial_thread_cb(void (*proc)(void *), void *arg); @@ -89,9 +88,7 @@ extern int remove_gdb(void); extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); -extern void set_kmem_end(unsigned long); extern void uml_cleanup(void); -extern int pid_to_processor_id(int pid); extern void set_current(void *t); extern void lock_signalled_task(void *t); extern void IPI_handler(int cpu); @@ -100,7 +97,9 @@ extern void *get_init_task(void); extern int clear_user_proc(void *buf, int size); extern int copy_to_user_proc(void *to, void *from, int size); extern int copy_from_user_proc(void *to, void *from, int size); +extern int strlen_user_proc(char *str); extern void bus_handler(int sig, union uml_pt_regs *regs); +extern void winch(int sig, union uml_pt_regs *regs); extern long execute_syscall(void *r); extern int smp_sigio_handler(void); extern void *get_current(void); @@ -111,6 +110,8 @@ extern void arch_switch(void); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); +extern unsigned long long time_stamp(void); + #endif /* --- linux-2.6.8-rc1/arch/um/include/line.h 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/include/line.h 2004-07-13 17:09:44.000000000 -0700 @@ -9,12 +9,14 @@ #include "linux/list.h" #include "linux/workqueue.h" #include "linux/tty.h" +#include "linux/interrupt.h" #include "asm/semaphore.h" #include "chan_user.h" #include "mconsole_kern.h" struct line_driver { char *name; + char *device_name; char *devfs_name; short major; short minor_start; @@ -67,8 +69,6 @@ struct lines { #define LINES_INIT(n) { num : n } -extern void line_interrupt(int irq, void *data, struct pt_regs *unused); -extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); --- linux-2.6.8-rc1/arch/um/include/mconsole.h 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/include/mconsole.h 2004-07-13 17:09:45.000000000 -0700 @@ -41,11 +41,13 @@ struct mconsole_notify { struct mc_request; +enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC }; + struct mconsole_command { char *command; void (*handler)(struct mc_request *req); - int as_interrupt; + enum mc_context context; }; struct mc_request @@ -77,6 +79,8 @@ extern void mconsole_sysrq(struct mc_req extern void mconsole_cad(struct mc_request *req); extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); +extern void mconsole_log(struct mc_request *req); +extern void mconsole_proc(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); extern int mconsole_notify(char *sock_name, int type, const void *data, --- linux-2.6.8-rc1/arch/um/include/mem.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/um/include/mem.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,19 +1,18 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #ifndef __MEM_H__ #define __MEM_H__ -struct vm_reserved { - struct list_head list; - unsigned long start; - unsigned long end; -}; +#include "linux/types.h" -extern void set_usable_vm(unsigned long start, unsigned long end); -extern void set_kmem_end(unsigned long new); +extern int phys_mapping(unsigned long phys, __u64 *offset_out); +extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); +extern int is_remapped(void *virt); +extern int physmem_remove_mapping(void *virt); +extern void physmem_forget_descriptor(int fd); #endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/include/mem_kern.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __MEM_KERN_H__ +#define __MEM_KERN_H__ + +#include "linux/list.h" +#include "linux/types.h" + +struct remapper { + struct list_head list; + int (*proc)(int, unsigned long, int, __u64); +}; + +extern void register_remapper(struct remapper *info); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/include/mem_user.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/arch/um/include/mem_user.h 2004-07-13 17:09:45.000000000 -0700 @@ -32,43 +32,38 @@ #ifndef _MEM_USER_H #define _MEM_USER_H -struct mem_region { +struct iomem_region { + struct iomem_region *next; char *driver; - unsigned long start_pfn; - unsigned long start; - unsigned long len; - void *mem_map; int fd; + int size; + unsigned long phys; + unsigned long virt; }; -extern struct mem_region *regions[]; -extern struct mem_region physmem_region; +extern struct iomem_region *iomem_regions; +extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) extern unsigned long host_task_size; extern unsigned long task_size; +extern void check_devanon(void); extern int init_mem_user(void); extern int create_mem_file(unsigned long len); -extern void setup_range(int fd, char *driver, unsigned long start, - unsigned long pfn, unsigned long total, int need_vm, - struct mem_region *region, void *reserved); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern int init_maps(struct mem_region *region); -extern int nregions(void); -extern int reserve_vm(unsigned long start, unsigned long end, void *e); +extern int init_maps(unsigned long physmem, unsigned long iomem, + unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len); -extern int setup_region(struct mem_region *region, void *entry); + unsigned long len, unsigned long highmem); extern void add_iomem(char *name, int fd, unsigned long size); -extern struct mem_region *phys_region(unsigned long phys); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); -extern int map_memory(unsigned long virt, unsigned long phys, - unsigned long len, int r, int w, int x); +extern void map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); extern int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed); extern unsigned long get_kmem_end(void); --- linux-2.6.8-rc1/arch/um/include/os.h 2003-06-14 12:18:02.000000000 -0700 +++ 25/arch/um/include/os.h 2004-07-13 17:09:45.000000000 -0700 @@ -17,6 +17,32 @@ #define OS_TYPE_FIFO 6 #define OS_TYPE_SOCK 7 +/* os_access() flags */ +#define OS_ACC_F_OK 0 /* Test for existence. */ +#define OS_ACC_X_OK 1 /* Test for execute permission. */ +#define OS_ACC_W_OK 2 /* Test for write permission. */ +#define OS_ACC_R_OK 4 /* Test for read permission. */ +#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ + +/* + * types taken from stat_file() in hostfs_user.c + * (if they are wrong here, they are wrong there...). + */ +struct uml_stat { + int ust_dev; /* device */ + unsigned long long ust_ino; /* inode */ + int ust_mode; /* protection */ + int ust_nlink; /* number of hard links */ + int ust_uid; /* user ID of owner */ + int ust_gid; /* group ID of owner */ + unsigned long long ust_size; /* total size, in bytes */ + int ust_blksize; /* blocksize for filesystem I/O */ + unsigned long long ust_blocks; /* number of blocks allocated */ + unsigned long ust_atime; /* time of last access */ + unsigned long ust_mtime; /* time of last modification */ + unsigned long ust_ctime; /* time of last change */ +}; + struct openflags { unsigned int r : 1; unsigned int w : 1; @@ -84,29 +110,47 @@ static inline struct openflags of_excl(s flags.e = 1; return(flags); } - + static inline struct openflags of_cloexec(struct openflags flags) { flags.cl = 1; return(flags); } +extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_stat_fd(const int fd, struct uml_stat *buf); +extern int os_access(const char *file, int mode); +extern void os_print_error(int error, const char* str); +extern int os_get_exec_close(int fd, int *close_on_exec); +extern int os_set_exec_close(int fd, int close_on_exec); +extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); +extern int os_window_size(int fd, int *rows, int *cols); +extern int os_new_tty_pgrp(int fd, int pid); +extern int os_get_ifname(int fd, char *namebuf); +extern int os_set_slip(int fd); +extern int os_set_owner(int fd, int pid); +extern int os_sigio_async(int master, int slave); +extern int os_mode_fd(int fd, int mode); + extern int os_seek_file(int fd, __u64 offset); extern int os_open_file(char *file, struct openflags flags, int mode); extern int os_read_file(int fd, void *buf, int len); -extern int os_write_file(int fd, void *buf, int count); +extern int os_write_file(int fd, const void *buf, int count); extern int os_file_size(char *file, long long *size_out); +extern int os_file_modtime(char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); extern int os_set_fd_async(int fd, int owner); extern int os_set_fd_block(int fd, int blocking); extern int os_accept_connection(int fd); +extern int os_create_unix_socket(char *file, int len, int close_on_exec); extern int os_shutdown_socket(int fd, int r, int w); extern void os_close_file(int fd); extern int os_rcv_fd(int fd, int *helper_pid_out); -extern int create_unix_socket(char *file, int len); +extern int create_unix_socket(char *file, int len, int close_on_exec); extern int os_connect_socket(char *name); extern int os_file_type(char *file); extern int os_file_mode(char *file, struct openflags *mode_out); +extern int os_lock_file(int fd, int excl); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); @@ -115,11 +159,12 @@ extern void os_kill_process(int pid, int extern void os_usr1_process(int pid); extern int os_getpid(void); -extern int os_map_memory(void *virt, int fd, unsigned long off, +extern int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x); extern int os_protect_memory(void *addr, unsigned long len, int r, int w, int x); extern int os_unmap_memory(void *addr, int len); +extern void os_flush_stdout(void); #endif --- linux-2.6.8-rc1/arch/um/include/signal_user.h 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/include/signal_user.h 2004-07-13 17:09:45.000000000 -0700 @@ -11,6 +11,8 @@ extern int signal_stack_size; extern int change_sig(int signal, int on); extern void set_sigstack(void *stack, int size); extern void set_handler(int sig, void (*handler)(int), int flags, ...); +extern int set_signals(int enable); +extern int get_signals(void); #endif --- linux-2.6.8-rc1/arch/um/include/skas_ptrace.h 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/include/skas_ptrace.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ --- linux-2.6.8-rc1/arch/um/include/sysdep-i386/frame_user.h 2003-06-14 12:18:34.000000000 -0700 +++ 25/arch/um/include/sysdep-i386/frame_user.h 2004-07-13 17:09:45.000000000 -0700 @@ -56,26 +56,26 @@ static inline void setup_arch_frame(stru * it would have to be __builtin_frame_address(1). */ -static inline unsigned long frame_restorer(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_restorer() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) /* Similarly, this returns the value of sp when the handler was first * entered. This is used to calculate the proper sp when delivering * signals. */ -static inline unsigned long frame_sp(void) -{ - unsigned long *fp; - - fp = __builtin_frame_address(0); - return((unsigned long) (fp + 1)); -} +#define frame_sp() \ +({ \ + unsigned long *fp; \ +\ + fp = __builtin_frame_address(0); \ + ((unsigned long) (fp + 1)); \ +}) #endif --- linux-2.6.8-rc1/arch/um/include/sysdep-i386/sigcontext.h 2003-06-14 12:18:28.000000000 -0700 +++ 25/arch/um/include/sysdep-i386/sigcontext.h 2004-07-13 17:09:45.000000000 -0700 @@ -28,8 +28,8 @@ */ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) -/* These are General Protection and Page Fault */ -#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14)) +/* This is Page Fault */ +#define SEGV_IS_FIXABLE(trap) (trap == 14) #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) --- linux-2.6.8-rc1/arch/um/include/sysdep-i386/syscalls.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/include/sysdep-i386/syscalls.h 2004-07-13 17:09:45.000000000 -0700 @@ -11,39 +11,34 @@ typedef long syscall_handler_t(struct pt #define EXECUTE_SYSCALL(syscall, regs) \ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) -extern syscall_handler_t sys_modify_ldt; -extern syscall_handler_t old_mmap_i386; -extern syscall_handler_t old_select; -extern syscall_handler_t sys_ni_syscall; - #define ARCH_SYSCALLS \ - [ __NR_mmap ] = old_mmap_i386, \ - [ __NR_select ] = old_select, \ - [ __NR_vm86old ] = sys_ni_syscall, \ - [ __NR_modify_ldt ] = sys_modify_ldt, \ - [ __NR_lchown32 ] = sys_lchown, \ - [ __NR_getuid32 ] = sys_getuid, \ - [ __NR_getgid32 ] = sys_getgid, \ - [ __NR_geteuid32 ] = sys_geteuid, \ - [ __NR_getegid32 ] = sys_getegid, \ - [ __NR_setreuid32 ] = sys_setreuid, \ - [ __NR_setregid32 ] = sys_setregid, \ - [ __NR_getgroups32 ] = sys_getgroups, \ - [ __NR_setgroups32 ] = sys_setgroups, \ - [ __NR_fchown32 ] = sys_fchown, \ - [ __NR_setresuid32 ] = sys_setresuid, \ - [ __NR_getresuid32 ] = sys_getresuid, \ - [ __NR_setresgid32 ] = sys_setresgid, \ - [ __NR_getresgid32 ] = sys_getresgid, \ - [ __NR_chown32 ] = sys_chown, \ - [ __NR_setuid32 ] = sys_setuid, \ - [ __NR_setgid32 ] = sys_setgid, \ - [ __NR_setfsuid32 ] = sys_setfsuid, \ - [ __NR_setfsgid32 ] = sys_setfsgid, \ - [ __NR_pivot_root ] = sys_pivot_root, \ - [ __NR_mincore ] = sys_mincore, \ - [ __NR_madvise ] = sys_madvise, \ - [ 222 ] = sys_ni_syscall, + [ __NR_mmap ] = (syscall_handler_t *) old_mmap_i386, \ + [ __NR_select ] = (syscall_handler_t *) old_select, \ + [ __NR_vm86old ] = (syscall_handler_t *) sys_ni_syscall, \ + [ __NR_modify_ldt ] = (syscall_handler_t *) sys_modify_ldt, \ + [ __NR_lchown32 ] = (syscall_handler_t *) sys_lchown, \ + [ __NR_getuid32 ] = (syscall_handler_t *) sys_getuid, \ + [ __NR_getgid32 ] = (syscall_handler_t *) sys_getgid, \ + [ __NR_geteuid32 ] = (syscall_handler_t *) sys_geteuid, \ + [ __NR_getegid32 ] = (syscall_handler_t *) sys_getegid, \ + [ __NR_setreuid32 ] = (syscall_handler_t *) sys_setreuid, \ + [ __NR_setregid32 ] = (syscall_handler_t *) sys_setregid, \ + [ __NR_getgroups32 ] = (syscall_handler_t *) sys_getgroups, \ + [ __NR_setgroups32 ] = (syscall_handler_t *) sys_setgroups, \ + [ __NR_fchown32 ] = (syscall_handler_t *) sys_fchown, \ + [ __NR_setresuid32 ] = (syscall_handler_t *) sys_setresuid, \ + [ __NR_getresuid32 ] = (syscall_handler_t *) sys_getresuid, \ + [ __NR_setresgid32 ] = (syscall_handler_t *) sys_setresgid, \ + [ __NR_getresgid32 ] = (syscall_handler_t *) sys_getresgid, \ + [ __NR_chown32 ] = (syscall_handler_t *) sys_chown, \ + [ __NR_setuid32 ] = (syscall_handler_t *) sys_setuid, \ + [ __NR_setgid32 ] = (syscall_handler_t *) sys_setgid, \ + [ __NR_setfsuid32 ] = (syscall_handler_t *) sys_setfsuid, \ + [ __NR_setfsgid32 ] = (syscall_handler_t *) sys_setfsgid, \ + [ __NR_pivot_root ] = (syscall_handler_t *) sys_pivot_root, \ + [ __NR_mincore ] = (syscall_handler_t *) sys_mincore, \ + [ __NR_madvise ] = (syscall_handler_t *) sys_madvise, \ + [ 222 ] = (syscall_handler_t *) sys_ni_syscall, /* 222 doesn't yet have a name in include/asm-i386/unistd.h */ --- linux-2.6.8-rc1/arch/um/include/ubd_user.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/include/ubd_user.h 2004-07-13 17:09:45.000000000 -0700 @@ -9,7 +9,7 @@ #include "os.h" -enum ubd_req { UBD_READ, UBD_WRITE }; +enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; struct io_thread_req { enum ubd_req op; @@ -20,8 +20,10 @@ struct io_thread_req { char *buffer; int sectorsize; unsigned long sector_mask; - unsigned long cow_offset; + unsigned long long cow_offset; unsigned long bitmap_words[2]; + int map_fd; + unsigned long long map_offset; int error; }; @@ -31,7 +33,7 @@ extern int open_ubd_file(char *file, str int *create_cow_out); extern int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, int sectorsize, - int *bitmap_offset_out, + int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); extern int read_cow_bitmap(int fd, void *buf, int offset, int len); @@ -39,7 +41,6 @@ extern int read_ubd_fs(int fd, void *buf extern int write_ubd_fs(int fd, char *buffer, int len); extern int start_io_thread(unsigned long sp, int *fds_out); extern void do_io(struct io_thread_req *req); -extern int ubd_is_dir(char *file); static inline int ubd_test_bit(__u64 bit, unsigned char *data) { --- linux-2.6.8-rc1/arch/um/include/um_uaccess.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/arch/um/include/um_uaccess.h 2004-07-13 17:09:45.000000000 -0700 @@ -38,22 +38,73 @@ static inline int copy_to_user(void *to, from, n)); } +/* + * strncpy_from_user: - Copy a NUL terminated string from userspace. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Source address, in user space. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from userspace to kernel space. + * + * On success, returns the length of the string (not including the trailing + * NUL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * + * If @count is smaller than the length of the string, copies @count bytes + * and returns @count. + */ + static inline int strncpy_from_user(char *dst, const char *src, int count) { return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, dst, src, count)); } +/* + * __clear_user: - Zero a block of memory in user space, with less checking. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. Caller must check + * the specified block with access_ok() before calling this function. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int __clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); } +/* + * clear_user: - Zero a block of memory in user space. + * @to: Destination address, in user space. + * @n: Number of bytes to zero. + * + * Zero a block of memory in user space. + * + * Returns number of bytes that could not be cleared. + * On success, this will be zero. + */ static inline int clear_user(void *mem, int len) { return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); } +/* + * strlen_user: - Get the size of a string in user space. + * @str: The string to measure. + * @n: The maximum valid length + * + * Get the size of a NUL-terminated string in user space. + * + * Returns the size of the string INCLUDING the terminating NUL. + * On exception, returns 0. + * If the string is too long, returns a value greater than @n. + */ static inline int strnlen_user(const void *str, int len) { return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); --- linux-2.6.8-rc1/arch/um/include/user.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/include/user.h 2004-07-13 17:09:49.000000000 -0700 @@ -14,6 +14,9 @@ extern void *um_kmalloc_atomic(int size) extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); +extern int strlcpy(char *, const char *, int); +extern void *um_vmalloc(int size); +extern void vfree(void *ptr); #endif --- linux-2.6.8-rc1/arch/um/include/user_util.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/include/user_util.h 2004-07-13 17:09:48.000000000 -0700 @@ -14,8 +14,6 @@ extern int grantpt(int __fd); extern int unlockpt(int __fd); extern char *ptsname(int __fd); -enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; - struct cpu_task { int pid; void *task; @@ -59,13 +57,11 @@ extern int wait_for_stop(int pid, int si extern void *add_signal_handler(int sig, void (*handler)(int)); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); -extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); extern int linux_main(int argc, char **argv); extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); extern int get_pty(void); extern void *um_kmalloc(int size); -extern int raw(int fd, int complain); extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); @@ -86,11 +82,17 @@ extern void check_sigio(void); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); extern void write_sigio_workaround(void); extern void arch_check_bugs(void); +extern int cpu_feature(char *what, char *buf, int len); extern int arch_handle_signal(int sig, union uml_pt_regs *regs); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); extern int can_do_skas(void); - +extern void arch_init_thread(void); + +extern int __raw(int fd, int complain, int now); +#define raw(fd, complain) __raw((fd), (complain), 1) + +#define CATCH_EINTR(expr) while ( ((expr) < 0) && errno == EINTR) #endif /* --- linux-2.6.8-rc1/arch/um/Kconfig 2004-05-09 21:07:23.000000000 -0700 +++ 25/arch/um/Kconfig 2004-07-13 17:09:45.000000000 -0700 @@ -61,6 +61,20 @@ config MODE_SKAS config NET bool "Networking support" + help + Unless you really know what you are doing, you should say Y here. + The reason is that some programs need kernel networking support even + when running on a stand-alone machine that isn't connected to any + other computer. If you are upgrading from an older kernel, you + should consider updating your networking tools too because changes + in the kernel and the tools often go hand in hand. The tools are + contained in the package net-tools, the location and version number + of which are given in Documentation/Changes. + + For a general introduction to Linux networking, it is highly + recommended to read the NET-HOWTO, available from + . + source "fs/Kconfig.binfmt" @@ -85,6 +99,19 @@ config HOSTFS If you'd like to be able to work with files stored on the host, say Y or M here; otherwise say N. +config HPPFS + tristate "HoneyPot ProcFS" + help + hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc + entries to be overridden, removed, or fabricated from the host. + Its purpose is to allow a UML to appear to be a physical machine + by removing or changing anything in /proc which gives away the + identity of a UML. + + See http://user-mode-linux.sf.net/hppfs.html for more information. + + You only need this if you are setting up a UML honeypot. Otherwise, + it is safe to say 'N' here. config MCONSOLE bool "Management console" @@ -105,6 +132,16 @@ config MCONSOLE config MAGIC_SYSRQ bool "Magic SysRq key" depends on MCONSOLE + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in Documentation/sysrq.txt. Don't say Y + unless you really know what this hack does. config HOST_2G_2G bool "2G/2G host address space split" @@ -168,6 +205,17 @@ config KERNEL_STACK_ORDER be 1 << order pages. The default is OK unless you're running Valgrind on UML, in which case, set this to 3. +config UML_REAL_TIME_CLOCK + bool "Real-time Clock" + default y + help + This option makes UML time deltas match wall clock deltas. This should + normally be enabled. The exception would be if you are debugging with + UML and spend long times with UML stopped at a breakpoint. In this + case, when UML is restarted, it will call the timer enough times to make + up for the time spent at the breakpoint. This could result in a + noticable lag. If this is a problem, then disable this option. + endmenu source "init/Kconfig" @@ -240,6 +288,10 @@ config FRAME_POINTER config PT_PROXY bool "Enable ptrace proxy" depends on XTERM_CHAN && DEBUG_INFO + help + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. config GPROF bool "Enable gprof support" --- linux-2.6.8-rc1/arch/um/Kconfig_block 2003-06-14 12:18:25.000000000 -0700 +++ 25/arch/um/Kconfig_block 2004-07-13 17:09:45.000000000 -0700 @@ -29,6 +29,20 @@ config BLK_DEV_UBD_SYNC wise choice too. In all other cases (for example, if you're just playing around with User-Mode Linux) you can choose N. +# Turn this back on when the driver actually works +# +#config BLK_DEV_COW +# tristate "COW block device" +# help +# This is a layered driver which sits above two other block devices. +# One is read-only, and the other is a read-write layer which stores +# all changes. This provides the illusion that the read-only layer +# can be mounted read-write and changed. + +config BLK_DEV_COW_COMMON + bool + default BLK_DEV_COW || BLK_DEV_UBD + config BLK_DEV_LOOP tristate "Loopback device support" --- linux-2.6.8-rc1/arch/um/Kconfig_char 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/um/Kconfig_char 2004-07-13 17:09:46.000000000 -0700 @@ -108,11 +108,60 @@ config SSL_CHAN config UNIX98_PTYS bool "Unix98 PTY support" - -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on UNIX98_PTYS + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + All modern Linux systems use the Unix98 ptys. Say Y unless + you're on an embedded system and want to conserve memory. + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. + +#config UNIX98_PTY_COUNT +# int "Maximum number of Unix98 PTYs in use (0-2048)" +# depends on UNIX98_PTYS +# default "256" config WATCHDOG bool "Watchdog Timer Support" --- linux-2.6.8-rc1/arch/um/Kconfig_net 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/Kconfig_net 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ -menu "Network Devices" +menu "UML Network Devices" depends on NET # UML virtual driver @@ -176,73 +176,5 @@ config UML_NET_SLIRP Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" - -# Below are hardware-independent drivers mirrored from -# drivers/net/Config.in. It would be nice if Linux -# had HW independent drivers separated from the other -# but it does not. Until then each non-ISA/PCI arch -# needs to provide it's own menu of network drivers -config DUMMY - tristate "Dummy net driver support" - -config BONDING - tristate "Bonding driver support" - -config EQUALIZER - tristate "EQL (serial line load balancing) support" - -config TUN - tristate "Universal TUN/TAP device driver support" - -config ETHERTAP - tristate "Ethertap network tap (OBSOLETE)" - depends on EXPERIMENTAL && NETLINK - -config PPP - tristate "PPP (point-to-point protocol) support" - -config PPP_MULTILINK - bool "PPP multilink support (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config PPP_FILTER - bool "PPP filtering" - depends on PPP && FILTER - -config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP - -config PPP_SYNC_TTY - tristate "PPP support for sync tty ports" - depends on PPP - -config PPP_DEFLATE - tristate "PPP Deflate compression" - depends on PPP - -config PPP_BSDCOMP - tristate "PPP BSD-Compress compression" - depends on PPP - -config PPPOE - tristate "PPP over Ethernet (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - -config SLIP - tristate "SLIP (serial line) support" - -config SLIP_COMPRESSED - bool "CSLIP compressed headers" - depends on SLIP=y - -config SLIP_SMART - bool "Keepalive and linefill" - depends on SLIP=y - -config SLIP_MODE_SLIP6 - bool "Six bit SLIP encapsulation" - depends on SLIP=y - endmenu --- linux-2.6.8-rc1/arch/um/kernel/config.c.in 2003-06-14 12:18:28.000000000 -0700 +++ 25/arch/um/kernel/config.c.in 2004-07-13 17:09:45.000000000 -0700 @@ -7,9 +7,7 @@ #include #include "init.h" -static __initdata char *config = " -CONFIG -"; +static __initdata char *config = "CONFIG"; static int __init print_config(char *line, int *add) { --- linux-2.6.8-rc1/arch/um/kernel/exec_kern.c 2003-06-14 12:18:05.000000000 -0700 +++ 25/arch/um/kernel/exec_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -32,10 +32,15 @@ void start_thread(struct pt_regs *regs, CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } +extern void log_exec(char **argv, void *tty); + static int execve1(char *file, char **argv, char **env) { int error; +#ifdef CONFIG_TTY_LOG + log_exec(argv, current->tty); +#endif error = do_execve(file, argv, env, ¤t->thread.regs); if (error == 0){ current->ptrace &= ~PT_DTRACE; --- linux-2.6.8-rc1/arch/um/kernel/frame.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/arch/um/kernel/frame.c 2004-07-13 17:09:48.000000000 -0700 @@ -21,6 +21,7 @@ #include "sysdep/sigcontext.h" #include "frame_user.h" #include "kern_util.h" +#include "user_util.h" #include "ptrace_user.h" #include "os.h" @@ -40,7 +41,7 @@ static int capture_stack(int (*child)(vo /* Wait for it to stop itself and continue it with a SIGUSR1 to force * it into the signal handler. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -60,7 +61,7 @@ static int capture_stack(int (*child)(vo * At this point, the handler has stuffed the addresses of * sig, sc, and SA_RESTORER in raw. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -82,7 +83,8 @@ static int capture_stack(int (*child)(vo errno); exit(1); } - if(waitpid(pid, &status, 0) < 0){ + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); } @@ -279,7 +281,7 @@ void capture_signal_stack(void) struct sc_frame_raw raw_sc; struct si_frame_raw raw_si; void *stack, *sigstack; - unsigned long top, sig_top, base; + unsigned long top, base; stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -292,7 +294,6 @@ void capture_signal_stack(void) } top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - sig_top = (unsigned long) sigstack + PAGE_SIZE; /* Get the sigcontext, no sigrestorer layout */ raw_sc.restorer = 0; --- linux-2.6.8-rc1/arch/um/kernel/frame_kern.c 2003-06-14 12:18:52.000000000 -0700 +++ 25/arch/um/kernel/frame_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -6,7 +6,6 @@ #include "asm/ptrace.h" #include "asm/uaccess.h" #include "asm/signal.h" -#include "asm/uaccess.h" #include "asm/ucontext.h" #include "frame_kern.h" #include "sigcontext.h" @@ -29,12 +28,15 @@ static int copy_restorer(void (*restorer sizeof(restorer))); } +extern int userspace_pid[]; + static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, struct arch_frame_data *arch) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), arch), - copy_sc_to_user_skas(to, fp, &from->regs, + copy_sc_to_user_skas(userspace_pid[0], to, fp, + &from->regs, current->thread.cr2, current->thread.err))); } --- linux-2.6.8-rc1/arch/um/kernel/helper.c 2003-06-14 12:18:20.000000000 -0700 +++ 25/arch/um/kernel/helper.c 2004-07-13 17:09:48.000000000 -0700 @@ -7,12 +7,12 @@ #include #include #include -#include #include #include #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" struct helper_data { @@ -33,6 +33,7 @@ static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; + int errval; if(helper_pause){ signal(SIGHUP, helper_hup); @@ -41,8 +42,9 @@ static int helper_child(void *arg) if(data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); + errval = errno; printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); - write(data->fd, &errno, sizeof(errno)); + os_write_file(data->fd, &errval, sizeof(errval)); os_kill_process(os_getpid(), 0); return(0); } @@ -59,17 +61,20 @@ int run_helper(void (*pre_exec)(void *), if((stack_out != NULL) && (*stack_out != 0)) stack = *stack_out; else stack = alloc_stack(0, um_in_interrupt()); - if(stack == 0) return(-ENOMEM); + if(stack == 0) + return(-ENOMEM); err = os_pipe(fds, 1, 0); - if(err){ - printk("run_helper : pipe failed, errno = %d\n", -err); - return(err); + if(err < 0){ + printk("run_helper : pipe failed, err = %d\n", -err); + goto out_free; } - if(fcntl(fds[1], F_SETFD, 1) != 0){ - printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n", - errno); - return(-errno); + + err = os_set_exec_close(fds[1], 1); + if(err < 0){ + printk("run_helper : setting FD_CLOEXEC failed, err = %d\n", + -err); + goto out_close; } sp = stack + page_size() - sizeof(void *); @@ -80,23 +85,34 @@ int run_helper(void (*pre_exec)(void *), pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if(pid < 0){ printk("run_helper : clone failed, errno = %d\n", errno); - return(-errno); + err = -errno; + goto out_close; } - close(fds[1]); - n = read(fds[0], &err, sizeof(err)); + + os_close_file(fds[1]); + n = os_read_file(fds[0], &err, sizeof(err)); if(n < 0){ - printk("run_helper : read on pipe failed, errno = %d\n", - errno); - return(-errno); + printk("run_helper : read on pipe failed, err = %d\n", -n); + err = n; + goto out_kill; } else if(n != 0){ - waitpid(pid, NULL, 0); - pid = -err; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + pid = -errno; } if(stack_out == NULL) free_stack(stack, 0); else *stack_out = stack; return(pid); + + out_kill: + os_kill_process(pid, 1); + out_close: + os_close_file(fds[0]); + os_close_file(fds[1]); + out_free: + free_stack(stack, 0); + return(err); } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, @@ -117,9 +133,11 @@ int run_helper_thread(int (*proc)(void * } if(stack_out == NULL){ pid = waitpid(pid, &status, 0); - if(pid < 0) + if(pid < 0){ printk("run_helper_thread - wait failed, errno = %d\n", - pid); + errno); + pid = -errno; + } if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); --- linux-2.6.8-rc1/arch/um/kernel/initrd_user.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/kernel/initrd_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include "user_util.h" @@ -19,13 +18,15 @@ int load_initrd(char *filename, void *bu { int fd, n; - if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){ - printk("Opening '%s' failed - errno = %d\n", filename, errno); + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); return(-1); } - if((n = read(fd, buf, size)) != size){ - printk("Read of %d bytes from '%s' returned %d, errno = %d\n", - size, filename, n, errno); + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); return(-1); } return(0); --- linux-2.6.8-rc1/arch/um/kernel/init_task.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/um/kernel/init_task.c 2004-07-13 17:09:45.000000000 -0700 @@ -8,7 +8,6 @@ #include "linux/module.h" #include "linux/sched.h" #include "linux/init_task.h" -#include "linux/version.h" #include "linux/mqueue.h" #include "asm/uaccess.h" #include "asm/pgtable.h" @@ -19,7 +18,7 @@ static struct fs_struct init_fs = INIT_F struct mm_struct init_mm = INIT_MM(init_mm); static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); - +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); EXPORT_SYMBOL(init_mm); /* @@ -44,26 +43,12 @@ union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) = { INIT_THREAD_INFO(init_task) }; -struct task_struct *alloc_task_struct(void) -{ - return((struct task_struct *) - __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER)); -} - void unprotect_stack(unsigned long stack) { protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 1, 1, 0, 1); } -void free_task_struct(struct task_struct *task) -{ - /* free_pages decrements the page counter and only actually frees - * the pages if they are now not accessed by anything. - */ - free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- linux-2.6.8-rc1/arch/um/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/um/kernel/irq.c 2004-07-13 17:09:45.000000000 -0700 @@ -29,6 +29,7 @@ #include "user_util.h" #include "kern_util.h" #include "irq_user.h" +#include "irq_kern.h" static void register_irq_proc (unsigned int irq); @@ -83,65 +84,55 @@ struct hw_interrupt_type no_irq_type = { end_none }; -/* Not changed */ -volatile unsigned long irq_err_count; - /* * Generic, controller-independent functions: */ -int get_irq_list(char *buf) +int show_interrupts(struct seq_file *p, void *v) { - int i, j; - unsigned long flags; + int i = *(loff_t *) v, j; struct irqaction * action; - char *p = buf; + unsigned long flags; - p += sprintf(p, " "); - for (j=0; jtypename); - p += sprintf(p, " %s", action->name); + seq_printf(p, " %14s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); for (action=action->next; action; action = action->next) - p += sprintf(p, ", %s", action->name); - *p++ = '\n'; - end: + seq_printf(p, ", %s", action->name); + + seq_putc(p, '\n'); +skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); } - p += sprintf(p, "\n"); -#ifdef notdef -#ifdef CONFIG_SMP - p += sprintf(p, "LOC: "); - for (j = 0; j < num_online_cpus(); j++) - p += sprintf(p, "%10u ", - apic_timer_irqs[cpu_logical_map(j)]); - p += sprintf(p, "\n"); -#endif -#endif - p += sprintf(p, "ERR: %10lu\n", irq_err_count); - return p - buf; -} - -int show_interrupts(struct seq_file *p, void *v) -{ - return(0); + return 0; } /* @@ -282,13 +273,12 @@ unsigned int do_IRQ(int irq, union uml_p * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* @@ -385,7 +375,7 @@ out: */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -433,15 +423,19 @@ int request_irq(unsigned int irq, EXPORT_SYMBOL(request_irq); int um_request_irq(unsigned int irq, int fd, int type, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { - int retval; + int err; - retval = request_irq(irq, handler, irqflags, devname, dev_id); - if(retval) return(retval); - return(activate_fd(irq, fd, type, dev_id)); + err = request_irq(irq, handler, irqflags, devname, dev_id); + if(err) + return(err); + + if(fd != -1) + err = activate_fd(irq, fd, type, dev_id); + return(err); } /* this was setup_x86_irq but it seems pretty generic */ @@ -474,7 +468,8 @@ int setup_irq(unsigned int irq, struct i */ spin_lock_irqsave(&desc->lock,flags); p = &desc->action; - if ((old = *p) != NULL) { + old = *p; + if (old != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { spin_unlock_irqrestore(&desc->lock,flags); @@ -586,12 +581,14 @@ static int irq_affinity_write_proc (stru unsigned long count, void *data) { int irq = (long) data, full_count = count, err; - cpumask_t new_value, tmp; + cpumask_t new_value; if (!irq_desc[irq].handler->set_affinity) return -EIO; err = cpumask_parse(buffer, count, new_value); + if(err) + return(err); #ifdef CONFIG_SMP /* @@ -599,9 +596,11 @@ static int irq_affinity_write_proc (stru * way to make the system unusable accidentally :-) At least * one online CPU still has to be targeted. */ - cpus_and(tmp, new_value, cpu_online_map); - if (cpus_empty(tmp)) - return -EINVAL; + { cpumask_t tmp; + cpus_and(tmp, new_value, cpu_online_map); + if (cpus_empty(tmp)) + return -EINVAL; + } #endif irq_affinity[irq] = new_value; --- linux-2.6.8-rc1/arch/um/kernel/irq_user.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/irq_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -49,7 +48,8 @@ void sigio_handler(int sig, union uml_pt if(smp_sigio_handler()) return; while(1){ - if((n = poll(pollfds, pollfds_num, 0)) < 0){ + n = poll(pollfds, pollfds_num, 0); + if(n < 0){ if(errno == EINTR) continue; printk("sigio_handler : poll returned %d, " "errno = %d\n", n, errno); @@ -366,34 +366,31 @@ void deactivate_fd(int fd, int irqnum) void forward_ipi(int fd, int pid) { - if(fcntl(fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(fd, F_GETOWN, 0) != pid){ - printk("forward_ipi: F_SETOWN failed, fd = %d, " - "me = %d, target = %d, errno = %d\n", fd, - os_getpid(), pid, save_errno); - } - } + int err; + + err = os_set_owner(fd, pid); + if(err < 0) + printk("forward_ipi: set_owner failed, fd = %d, me = %d, " + "target = %d, err = %d\n", fd, os_getpid(), pid, -err); } void forward_interrupts(int pid) { struct irq_fd *irq; unsigned long flags; + int err; flags = irq_lock(); for(irq=active_fds;irq != NULL;irq = irq->next){ - if(fcntl(irq->fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - if(fcntl(irq->fd, F_GETOWN, 0) != pid){ - /* XXX Just remove the irq rather than - * print out an infinite stream of these - */ - printk("Failed to forward %d to pid %d, " - "errno = %d\n", irq->fd, pid, - save_errno); - } + err = os_set_owner(irq->fd, pid); + if(err < 0){ + /* XXX Just remove the irq rather than + * print out an infinite stream of these + */ + printk("Failed to forward %d to pid %d, err = %d\n", + irq->fd, pid, -err); } + irq->pid = pid; } irq_unlock(flags); --- linux-2.6.8-rc1/arch/um/kernel/ksyms.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/kernel/ksyms.c 2004-07-13 17:09:48.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -8,7 +8,7 @@ #include "linux/string.h" #include "linux/smp_lock.h" #include "linux/spinlock.h" -#include +#include "linux/highmem.h" #include "asm/current.h" #include "asm/delay.h" #include "asm/processor.h" @@ -19,6 +19,7 @@ #include "asm/tlbflush.h" #include "kern_util.h" #include "user_util.h" +#include "mem_user.h" #include "os.h" #include "helper.h" @@ -34,34 +35,66 @@ EXPORT_SYMBOL(task_size); EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); +EXPORT_SYMBOL(get_kmem_end); -EXPORT_SYMBOL(region_pa); -EXPORT_SYMBOL(region_va); -EXPORT_SYMBOL(phys_mem_map); -EXPORT_SYMBOL(page_mem_map); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(um_virt_to_phys); +EXPORT_SYMBOL(__virt_to_page); +EXPORT_SYMBOL(to_phys); +EXPORT_SYMBOL(to_virt); EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); +EXPORT_SYMBOL(find_iomem); +#ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(strncpy_from_user_tt); +EXPORT_SYMBOL(copy_from_user_tt); +EXPORT_SYMBOL(copy_to_user_tt); +#endif + +#ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strncpy_from_user_skas); +EXPORT_SYMBOL(copy_to_user_skas); +EXPORT_SYMBOL(copy_from_user_skas); +#endif + +EXPORT_SYMBOL(os_stat_fd); +EXPORT_SYMBOL(os_stat_file); +EXPORT_SYMBOL(os_access); +EXPORT_SYMBOL(os_print_error); +EXPORT_SYMBOL(os_get_exec_close); +EXPORT_SYMBOL(os_set_exec_close); EXPORT_SYMBOL(os_getpid); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); EXPORT_SYMBOL(os_write_file); EXPORT_SYMBOL(os_seek_file); +EXPORT_SYMBOL(os_lock_file); +EXPORT_SYMBOL(os_ioctl_generic); EXPORT_SYMBOL(os_pipe); EXPORT_SYMBOL(os_file_type); +EXPORT_SYMBOL(os_file_mode); +EXPORT_SYMBOL(os_file_size); +EXPORT_SYMBOL(os_flush_stdout); EXPORT_SYMBOL(os_close_file); +EXPORT_SYMBOL(os_set_fd_async); +EXPORT_SYMBOL(os_set_fd_block); EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); +EXPORT_SYMBOL(os_create_unix_socket); EXPORT_SYMBOL(os_connect_socket); +EXPORT_SYMBOL(os_accept_connection); +EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(do_gettimeofday); +EXPORT_SYMBOL(do_settimeofday); + /* This is here because UML expands open to sys_open, not to a system * call instruction. */ @@ -90,3 +123,13 @@ EXPORT_SYMBOL(kunmap_atomic); EXPORT_SYMBOL(kmap_atomic_to_page); #endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/kernel/Makefile 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/um/kernel/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -7,11 +7,11 @@ extra-y := vmlinux.lds.s obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ - sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ - syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ - umid.o user_syms.o user_util.o + physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ + sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ + syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ + time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ + um_arch.o umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -24,43 +24,27 @@ obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ - process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o + process.o tempfile.o time.o tty_log.o umid.o user_util.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ -DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ - - -CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ - -I/usr/include -I../include - CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - # This has to be separate because it needs be compiled with frame pointers # regardless of how the rest of the kernel is built. $(obj)/frame.o: $(src)/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< -QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< -$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config - $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ +QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' $(obj)/config.o : $(obj)/config.c -clean: - rm -f config.c - for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done - -modules: - -fastdep: - -dep: - -archmrproper: clean +quiet_cmd_quote = QUOTE $@ +cmd_quote = $(PERL) -e $(QUOTE) < $< > $@ +targets += config.c +$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config FORCE + $(call if_changed,quote) --- linux-2.6.8-rc1/arch/um/kernel/mem.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/um/kernel/mem.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,74 +1,66 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ -#include "linux/config.h" -#include "linux/module.h" -#include "linux/types.h" +#include "linux/stddef.h" +#include "linux/kernel.h" #include "linux/mm.h" -#include "linux/fs.h" -#include "linux/init.h" #include "linux/bootmem.h" #include "linux/swap.h" -#include "linux/slab.h" -#include "linux/vmalloc.h" #include "linux/highmem.h" +#include "linux/gfp.h" #include "asm/page.h" -#include "asm/pgtable.h" +#include "asm/fixmap.h" #include "asm/pgalloc.h" -#include "asm/bitops.h" -#include "asm/uaccess.h" -#include "asm/tlb.h" #include "user_util.h" #include "kern_util.h" -#include "mem_user.h" -#include "mem.h" #include "kern.h" -#include "init.h" -#include "os.h" -#include "mode_kern.h" +#include "mem_user.h" #include "uml_uaccess.h" +#include "os.h" + +extern char __binary_start; /* Changed during early boot */ -pgd_t swapper_pg_dir[1024]; -unsigned long high_physmem; -unsigned long vm_start; -unsigned long vm_end; -unsigned long highmem; unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; - -/* Not modified */ -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; - -extern char __init_begin, __init_end; -extern long physmem_size; - -/* Not changed by UML */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); - -/* Changed during early boot */ +pgd_t swapper_pg_dir[1024]; +unsigned long highmem; int kmalloc_ok = 0; -#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1) -struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL }; -#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1) - -/* Changed during early boot */ static unsigned long brk_end; +void unmap_physmem(void) +{ + os_unmap_memory((void *) brk_end, uml_reserved - brk_end); +} + static void map_cb(void *unused) { map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } -void unmap_physmem(void) +#ifdef CONFIG_HIGHMEM +static void setup_highmem(unsigned long highmem_start, + unsigned long highmem_len) { - os_unmap_memory((void *) brk_end, uml_reserved - brk_end); -} + struct page *page; + unsigned long highmem_pfn; + int i; -extern char __binary_start; + highmem_start_page = virt_to_page(highmem_start); + + highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; + for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ + page = &mem_map[highmem_pfn + i]; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + set_page_count(page, 1); + __free_page(page); + } +} +#endif void mem_init(void) { @@ -103,50 +95,15 @@ void mem_init(void) totalhigh_pages = highmem >> PAGE_SHIFT; totalram_pages += totalhigh_pages; num_physpages = totalram_pages; - max_mapnr = totalram_pages; max_pfn = totalram_pages; printk(KERN_INFO "Memory: %luk available\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); kmalloc_ok = 1; -} - -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) - kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); - return(kmem_top); -} - -void set_kmem_end(unsigned long new) -{ - kmem_top = new; -} #ifdef CONFIG_HIGHMEM -/* Changed during early boot */ -pte_t *kmap_pte; -pgprot_t kmap_prot; - -EXPORT_SYMBOL(kmap_prot); -EXPORT_SYMBOL(kmap_pte); - -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) - -void __init kmap_init(void) -{ - unsigned long kmap_vstart; - - /* cache the first kmap pte */ - kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); - kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - - kmap_prot = PAGE_KERNEL; + setup_highmem(end_iomem, highmem); +#endif } -#endif /* CONFIG_HIGHMEM */ static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) @@ -178,76 +135,24 @@ static void __init fixrange_init(unsigne } } -int init_maps(struct mem_region *region) -{ - struct page *p, *map; - int i, n, len; - - if(region == &physmem_region){ - region->mem_map = mem_map; - return(0); - } - else if(region->mem_map != NULL) return(0); - - n = region->len >> PAGE_SHIFT; - len = n * sizeof(struct page); - if(kmalloc_ok){ - map = kmalloc(len, GFP_KERNEL); - if(map == NULL) map = vmalloc(len); - } - else map = alloc_bootmem_low_pages(len); - - if(map == NULL) - return(-ENOMEM); - for(i = 0; i < n; i++){ - p = &map[i]; - set_page_count(p, 0); - SetPageReserved(p); - INIT_LIST_HEAD(&p->list); - } - region->mem_map = map; - return(0); -} +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; -DECLARE_MUTEX(regions_sem); +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) -static int setup_one_range(int fd, char *driver, unsigned long start, - unsigned long pfn, int len, - struct mem_region *region) +void __init kmap_init(void) { - int i; - - down(®ions_sem); - for(i = 0; i < NREGIONS; i++){ - if(regions[i] == NULL) break; - } - if(i == NREGIONS){ - printk("setup_range : no free regions\n"); - i = -1; - goto out; - } - - if(fd == -1) - fd = create_mem_file(len); + unsigned long kmap_vstart; - if(region == NULL){ - region = alloc_bootmem_low_pages(sizeof(*region)); - if(region == NULL) - panic("Failed to allocating mem_region"); - } + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - *region = ((struct mem_region) { .driver = driver, - .start_pfn = pfn, - .start = start, - .len = len, - .fd = fd } ); - regions[i] = region; - out: - up(®ions_sem); - return(i); + kmap_prot = PAGE_KERNEL; } -#ifdef CONFIG_HIGHMEM static void init_highmem(void) { pgd_t *pgd; @@ -268,63 +173,20 @@ static void init_highmem(void) kmap_init(); } - -void setup_highmem(unsigned long len) -{ - struct mem_region *region; - struct page *page, *map; - unsigned long phys; - int i, cur, index; - - phys = physmem_size; - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur, - NULL); - if(i == -1){ - printk("setup_highmem - setup_one_range failed\n"); - return; - } - region = regions[i]; - index = phys / PAGE_SIZE; - region->mem_map = &mem_map[index]; - - map = region->mem_map; - for(i = 0; i < (cur >> PAGE_SHIFT); i++){ - page = &map[i]; - ClearPageReserved(page); - set_bit(PG_highmem, &page->flags); - set_page_count(page, 1); - __free_page(page); - } - phys += cur; - len -= cur; - } while(len > 0); -} -#endif +#endif /* CONFIG_HIGHMEM */ void paging_init(void) { - struct mem_region *region; - unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr; - int i, index; + unsigned long zones_size[MAX_NR_ZONES], vaddr; + int i; empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); for(i=0;i> PAGE_SHIFT) - - (uml_physmem >> PAGE_SHIFT); + zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); zones_size[2] = highmem >> PAGE_SHIFT; free_area_init(zones_size); - start = phys_region_index(__pa(uml_physmem)); - end = phys_region_index(__pa(high_physmem - 1)); - for(i = start; i <= end; i++){ - region = regions[i]; - index = (region->start - uml_physmem) / PAGE_SIZE; - region->mem_map = &mem_map[index]; - if(i > start) free_bootmem(__pa(region->start), region->len); - } /* * Fixed mappings, only the page table structure has to be @@ -335,15 +197,33 @@ void paging_init(void) #ifdef CONFIG_HIGHMEM init_highmem(); - setup_highmem(highmem); #endif } -pte_t __bad_page(void) +struct page *arch_validate(struct page *page, int mask, int order) { - clear_page(empty_bad_page); - return pte_mkdirty(mk_pte((struct page *) empty_bad_page, - PAGE_SHARED)); + unsigned long addr, zero = 0; + int i; + + again: + if(page == NULL) return(page); + if(PageHighMem(page)) return(page); + + addr = (unsigned long) page_address(page); + for(i = 0; i < (1 << order); i++){ + current->thread.fault_addr = (void *) addr; + if(__do_copy_to_user((void *) addr, &zero, + sizeof(zero), + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)){ + if(!(mask & __GFP_WAIT)) return(NULL); + else break; + } + addr += PAGE_SIZE; + } + if(i == (1 << order)) return(page); + page = alloc_pages(mask, order); + goto again; } /* This can't do anything because nothing in the kernel image can be freed @@ -401,395 +281,6 @@ void show_mem(void) printk("%d pages swap cached\n", cached); } -static int __init uml_mem_setup(char *line, int *add) -{ - char *retptr; - physmem_size = memparse(line,&retptr); - return 0; -} -__uml_setup("mem=", uml_mem_setup, -"mem=\n" -" This controls how much \"physical\" memory the kernel allocates\n" -" for the system. The size is specified as a number followed by\n" -" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" -" This is not related to the amount of memory in the physical\n" -" machine. It can be more, and the excess, if it's ever used, will\n" -" just be swapped out.\n Example: mem=64M\n\n" -); - -struct page *arch_validate(struct page *page, int mask, int order) -{ - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; -} - -DECLARE_MUTEX(vm_reserved_sem); -static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved); - -/* Static structures, linked in to the list in early boot */ -static struct vm_reserved head = { - .list = LIST_HEAD_INIT(head.list), - .start = 0, - .end = 0xffffffff -}; - -static struct vm_reserved tail = { - .list = LIST_HEAD_INIT(tail.list), - .start = 0, - .end = 0xffffffff -}; - -void set_usable_vm(unsigned long start, unsigned long end) -{ - list_add(&head.list, &vm_reserved); - list_add(&tail.list, &head.list); - head.end = start; - tail.start = end; -} - -int reserve_vm(unsigned long start, unsigned long end, void *e) - -{ - struct vm_reserved *entry = e, *reserved, *prev; - struct list_head *ele; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - reserved = list_entry(ele, struct vm_reserved, list); - if(reserved->start >= end) goto found; - } - panic("Reserved vm out of range"); - found: - prev = list_entry(ele->prev, struct vm_reserved, list); - if(prev->end > start) - panic("Can't reserve vm"); - if(entry == NULL) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if(entry == NULL){ - printk("reserve_vm : Failed to allocate entry\n"); - err = -ENOMEM; - goto out; - } - *entry = ((struct vm_reserved) - { .list = LIST_HEAD_INIT(entry->list), - .start = start, - .end = end }); - list_add(&entry->list, &prev->list); - err = 0; - out: - up(&vm_reserved_sem); - return(0); -} - -unsigned long get_vm(unsigned long len) -{ - struct vm_reserved *this, *next; - struct list_head *ele; - unsigned long start; - int err; - - down(&vm_reserved_sem); - list_for_each(ele, &vm_reserved){ - this = list_entry(ele, struct vm_reserved, list); - next = list_entry(ele->next, struct vm_reserved, list); - if((this->start < next->start) && - (this->end + len + PAGE_SIZE <= next->start)) - goto found; - } - up(&vm_reserved_sem); - return(0); - found: - up(&vm_reserved_sem); - start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE; - err = reserve_vm(start, start + len, NULL); - if(err) return(0); - return(start); -} - -int nregions(void) -{ - return(NREGIONS); -} - -void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn, - unsigned long len, int need_vm, struct mem_region *region, - void *reserved) -{ - int i, cur; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - i = setup_one_range(fd, driver, start, pfn, cur, region); - region = regions[i]; - if(need_vm && setup_region(region, reserved)){ - kfree(region); - regions[i] = NULL; - return; - } - start += cur; - if(pfn != -1) pfn += cur; - len -= cur; - } while(len > 0); -} - -struct iomem { - char *name; - int fd; - unsigned long size; -}; - -/* iomem regions can only be added on the command line at the moment. - * Locking will be needed when they can be added via mconsole. - */ - -struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = - { .name = NULL, - .fd = -1, - .size = 0 } }; - -int num_iomem_regions = 0; - -void add_iomem(char *name, int fd, unsigned long size) -{ - if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0])) - return; - size = (size + PAGE_SIZE - 1) & PAGE_MASK; - iomem_regions[num_iomem_regions++] = - ((struct iomem) { .name = name, - .fd = fd, - .size = size } ); -} - -int setup_iomem(void) -{ - struct iomem *iomem; - int i; - - for(i = 0; i < num_iomem_regions; i++){ - iomem = &iomem_regions[i]; - setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, - NULL, NULL); - } - return(0); -} - -__initcall(setup_iomem); - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) - -/* Changed during early boot */ -static struct mem_region physmem_region; -static struct vm_reserved physmem_reserved; - -void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len) -{ - struct mem_region *region = &physmem_region; - struct vm_reserved *reserved = &physmem_reserved; - unsigned long cur, pfn = 0; - int do_free = 1, bootmap_size; - - do { - cur = min(len, (unsigned long) REGION_SIZE); - if(region == NULL) - region = alloc_bootmem_low_pages(sizeof(*region)); - if(reserved == NULL) - reserved = alloc_bootmem_low_pages(sizeof(*reserved)); - if((region == NULL) || (reserved == NULL)) - panic("Couldn't allocate physmem region or vm " - "reservation\n"); - setup_range(-1, NULL, start, pfn, cur, 1, region, reserved); - - if(do_free){ - unsigned long reserve = reserve_end - start; - int pfn = PFN_UP(__pa(reserve_end)); - int delta = (len - reserve) >> PAGE_SHIFT; - - bootmap_size = init_bootmem(pfn, pfn + delta); - free_bootmem(__pa(reserve_end) + bootmap_size, - cur - bootmap_size - reserve); - do_free = 0; - } - start += cur; - pfn += cur >> PAGE_SHIFT; - len -= cur; - region = NULL; - reserved = NULL; - } while(len > 0); -} - -struct mem_region *phys_region(unsigned long phys) -{ - unsigned int n = phys_region_index(phys); - - if(regions[n] == NULL) - panic("Physical address in uninitialized region"); - return(regions[n]); -} - -unsigned long phys_offset(unsigned long phys) -{ - return(phys_addr(phys)); -} - -struct page *phys_mem_map(unsigned long phys) -{ - return((struct page *) phys_region(phys)->mem_map); -} - -struct page *pte_mem_map(pte_t pte) -{ - return(phys_mem_map(pte_val(pte))); -} - -struct mem_region *page_region(struct page *page, int *index_out) -{ - int i; - struct mem_region *region; - struct page *map; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - map = region->mem_map; - if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){ - if(index_out != NULL) *index_out = i; - return(region); - } - } - panic("No region found for page"); - return(NULL); -} - -unsigned long page_to_pfn(struct page *page) -{ - struct mem_region *region = page_region(page, NULL); - - return(region->start_pfn + (page - (struct page *) region->mem_map)); -} - -struct mem_region *pfn_to_region(unsigned long pfn, int *index_out) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) - continue; - - if((region->start_pfn <= pfn) && - (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){ - if(index_out != NULL) - *index_out = i; - return(region); - } - } - return(NULL); -} - -struct page *pfn_to_page(unsigned long pfn) -{ - struct mem_region *region = pfn_to_region(pfn, NULL); - struct page *mem_map = (struct page *) region->mem_map; - - return(&mem_map[pfn - region->start_pfn]); -} - -unsigned long phys_to_pfn(unsigned long p) -{ - struct mem_region *region = regions[phys_region_index(p)]; - - return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT)); -} - -unsigned long pfn_to_phys(unsigned long pfn) -{ - int n; - struct mem_region *region = pfn_to_region(pfn, &n); - - return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n)); -} - -struct page *page_mem_map(struct page *page) -{ - return((struct page *) page_region(page, NULL)->mem_map); -} - -extern unsigned long region_pa(void *virt) -{ - struct mem_region *region; - unsigned long addr = (unsigned long) virt; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->start <= addr) && - (addr <= region->start + region->len)) - return(mk_phys(addr - region->start, i)); - } - panic("region_pa : no region for virtual address"); - return(0); -} - -extern void *region_va(unsigned long phys) -{ - return((void *) (phys_region(phys)->start + phys_addr(phys))); -} - -unsigned long page_to_phys(struct page *page) -{ - int n; - struct mem_region *region = page_region(page, &n); - struct page *map = region->mem_map; - return(mk_phys((page - map) << PAGE_SHIFT, n)); -} - -struct page *phys_to_page(unsigned long phys) -{ - struct page *mem_map; - - mem_map = phys_mem_map(phys); - return(mem_map + (phys_offset(phys) >> PAGE_SHIFT)); -} - -static int setup_mem_maps(void) -{ - struct mem_region *region; - int i; - - for(i = 0; i < NREGIONS; i++){ - region = regions[i]; - if((region != NULL) && (region->fd > 0)) init_maps(region); - } - return(0); -} - -__initcall(setup_mem_maps); - /* * Allocate and free page tables. */ --- linux-2.6.8-rc1/arch/um/kernel/mem_user.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/kernel/mem_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -34,10 +34,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include "kern_util.h" @@ -47,105 +46,145 @@ #include "init.h" #include "os.h" #include "tempfile.h" +#include "kern_constants.h" extern struct mem_region physmem_region; #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" -int create_mem_file(unsigned long len) +static int create_tmp_file(unsigned long len) { - int fd; + int fd, err; char zero; fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); - if (fchmod(fd, 0777) < 0){ - perror("fchmod"); + if(fd < 0) { + os_print_error(fd, "make_tempfile"); + exit(1); + } + + err = os_mode_fd(fd, 0777); + if(err < 0){ + os_print_error(err, "os_mode_fd"); exit(1); } - if(os_seek_file(fd, len) < 0){ - perror("lseek"); + err = os_seek_file(fd, len); + if(err < 0){ + os_print_error(err, "os_seek_file"); exit(1); } zero = 0; - if(write(fd, &zero, 1) != 1){ - perror("write"); + err = os_write_file(fd, &zero, 1); + if(err != 1){ + os_print_error(err, "os_write_file"); exit(1); } - if(fcntl(fd, F_SETFD, 1) != 0) - perror("Setting FD_CLOEXEC failed"); + return(fd); } -int setup_region(struct mem_region *region, void *entry) +static int have_devanon = 0; + +void check_devanon(void) +{ + int fd; + + printk("Checking for /dev/anon on the host..."); + fd = open("/dev/anon", O_RDWR); + if(fd < 0){ + printk("Not available (open failed with errno %d)\n", errno); + return; + } + + printk("OK\n"); + have_devanon = 1; +} + +static int create_anon_file(unsigned long len) { - void *loc, *start; - char *driver; - int err, offset; - - if(region->start != -1){ - err = reserve_vm(region->start, - region->start + region->len, entry); - if(err){ - printk("setup_region : failed to reserve " - "0x%x - 0x%x for driver '%s'\n", - region->start, - region->start + region->len, - region->driver); - return(-1); - } - } - else region->start = get_vm(region->len); - if(region->start == 0){ - if(region->driver == NULL) driver = "physmem"; - else driver = region->driver; - printk("setup_region : failed to find vm for " - "driver '%s' (length %d)\n", driver, region->len); - return(-1); - } - if(region->start == uml_physmem){ - start = (void *) uml_reserved; - offset = uml_reserved - uml_physmem; - } - else { - start = (void *) region->start; - offset = 0; - } - - loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, region->fd, offset); - if(loc != start){ - perror("Mapping memory"); + void *addr; + int fd; + + fd = open("/dev/anon", O_RDWR); + if(fd < 0) { + os_print_error(fd, "opening /dev/anon"); exit(1); } - return(0); + + addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + os_print_error((int) addr, "mapping physmem file"); + exit(1); + } + munmap(addr, len); + + return(fd); +} + +int create_mem_file(unsigned long len) +{ + int err, fd; + + if(have_devanon) + fd = create_anon_file(len); + else fd = create_tmp_file(len); + + err = os_set_exec_close(fd, 1); + if(err < 0) + os_print_error(err, "exec_close"); + return(fd); } +struct iomem_region *iomem_regions = NULL; +int iomem_size = 0; + static int __init parse_iomem(char *str, int *add) { - struct stat buf; + struct iomem_region *new; + struct uml_stat buf; char *file, *driver; - int fd; + int fd, err; driver = str; file = strchr(str,','); if(file == NULL){ - printk("parse_iomem : failed to parse iomem\n"); - return(1); + printf("parse_iomem : failed to parse iomem\n"); + goto out; } *file = '\0'; file++; fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); if(fd < 0){ - printk("parse_iomem - Couldn't open io file, errno = %d\n", - errno); - return(1); - } - if(fstat(fd, &buf) < 0) { - printk("parse_iomem - cannot fstat file, errno = %d\n", errno); - return(1); + os_print_error(fd, "parse_iomem - Couldn't open io file"); + goto out; } - add_iomem(driver, fd, buf.st_size); + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; + } + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; + } + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = buf.ust_size, + .phys = 0, + .virt = 0 }); + iomem_regions = new; + iomem_size += new->size + UM_KERN_PAGE_SIZE; + return(0); + out_close: + os_close_file(fd); + out: + return(1); } __uml_setup("iomem=", parse_iomem, @@ -153,73 +192,20 @@ __uml_setup("iomem=", parse_iomem, " Configure as an IO memory region named .\n\n" ); -#ifdef notdef -int logging = 0; -int logging_fd = -1; - -int logging_line = 0; -char logging_buf[256]; - -void log(char *fmt, ...) -{ - va_list ap; - struct timeval tv; - struct openflags flags; - - if(logging == 0) return; - if(logging_fd < 0){ - flags = of_create(of_trunc(of_rdrw(OPENFLAGS()))); - logging_fd = os_open_file("log", flags, 0644); - } - gettimeofday(&tv, NULL); - sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, - tv.tv_usec); - va_start(ap, fmt); - vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); - va_end(ap); - write(logging_fd, logging_buf, strlen(logging_buf)); -} -#endif - -int map_memory(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) -{ - struct mem_region *region = phys_region(phys); - - return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len, - r, w, x)); -} - int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed) { - if(os_protect_memory((void *) addr, len, r, w, x) < 0){ + int err; + + err = os_protect_memory((void *) addr, len, r, w, x); + if(err < 0){ if(must_succeed) - panic("protect failed, errno = %d", errno); - else return(-errno); + panic("protect failed, err = %d", -err); + else return(err); } return(0); } -unsigned long find_iomem(char *driver, unsigned long *len_out) -{ - struct mem_region *region; - int i, n; - - n = nregions(); - for(i = 0; i < n; i++){ - region = regions[i]; - if(region == NULL) continue; - if((region->driver != NULL) && - !strcmp(region->driver, driver)){ - *len_out = region->len; - return(region->start); - } - } - *len_out = 0; - return 0; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/kernel/physmem.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/ghash.h" +#include "linux/slab.h" +#include "linux/vmalloc.h" +#include "linux/bootmem.h" +#include "asm/types.h" +#include "asm/pgtable.h" +#include "kern_util.h" +#include "user_util.h" +#include "mode_kern.h" +#include "mem.h" +#include "mem_user.h" +#include "os.h" +#include "kern.h" +#include "init.h" + +#if 0 +static pgd_t physmem_pgd[PTRS_PER_PGD]; + +static struct phys_desc *lookup_mapping(void *addr) +{ + pgd = &physmem_pgd[pgd_index(addr)]; + if(pgd_none(pgd)) + return(NULL); + + pmd = pmd_offset(pgd, addr); + if(pmd_none(pmd)) + return(NULL); + + pte = pte_offset_kernel(pmd, addr); + return((struct phys_desc *) pte_val(pte)); +} + +static struct add_mapping(void *addr, struct phys_desc *new) +{ +} +#endif + +#define PHYS_HASHSIZE (8192) + +struct phys_desc; + +DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc); + +struct phys_desc { + struct virtmem_ptrs virt_ptrs; + int fd; + __u64 offset; + void *virt; + unsigned long phys; + struct list_head list; +}; + +struct virtmem_table virtmem_hash; + +static int virt_cmp(void *virt1, void *virt2) +{ + return(virt1 != virt2); +} + +static int virt_hash(void *virt) +{ + unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT; + return(addr % PHYS_HASHSIZE); +} + +DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, + virt_hash); + +LIST_HEAD(descriptor_mappings); + +struct desc_mapping { + int fd; + struct list_head list; + struct list_head pages; +}; + +static struct desc_mapping *find_mapping(int fd) +{ + struct desc_mapping *desc; + struct list_head *ele; + + list_for_each(ele, &descriptor_mappings){ + desc = list_entry(ele, struct desc_mapping, list); + if(desc->fd == fd) + return(desc); + } + + return(NULL); +} + +static struct desc_mapping *descriptor_mapping(int fd) +{ + struct desc_mapping *desc; + + desc = find_mapping(fd); + if(desc != NULL) + return(desc); + + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + return(NULL); + + *desc = ((struct desc_mapping) + { .fd = fd, + .list = LIST_HEAD_INIT(desc->list), + .pages = LIST_HEAD_INIT(desc->pages) }); + list_add(&desc->list, &descriptor_mappings); + + return(desc); +} + +int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) +{ + struct desc_mapping *fd_maps; + struct phys_desc *desc; + unsigned long phys; + int err; + + fd_maps = descriptor_mapping(fd); + if(fd_maps == NULL) + return(-ENOMEM); + + phys = __pa(virt); + if(find_virtmem_hash(&virtmem_hash, virt) != NULL) + panic("Address 0x%p is already substituted\n", virt); + + err = -ENOMEM; + desc = kmalloc(sizeof(*desc), GFP_ATOMIC); + if(desc == NULL) + goto out; + + *desc = ((struct phys_desc) + { .virt_ptrs = { NULL, NULL }, + .fd = fd, + .offset = offset, + .virt = virt, + .phys = __pa(virt), + .list = LIST_HEAD_INIT(desc->list) }); + insert_virtmem_hash(&virtmem_hash, desc); + + list_add(&desc->list, &fd_maps->pages); + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); + if(!err) + goto out; + + remove_virtmem_hash(&virtmem_hash, desc); + kfree(desc); + out: + return(err); +} + +static int physmem_fd = -1; + +static void remove_mapping(struct phys_desc *desc) +{ + void *virt = desc->virt; + int err; + + remove_virtmem_hash(&virtmem_hash, desc); + list_del(&desc->list); + kfree(desc); + + err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); + if(err) + panic("Failed to unmap block device page from physical memory, " + "errno = %d", -err); +} + +int physmem_remove_mapping(void *virt) +{ + struct phys_desc *desc; + + virt = (void *) ((unsigned long) virt & PAGE_MASK); + desc = find_virtmem_hash(&virtmem_hash, virt); + if(desc == NULL) + return(0); + + remove_mapping(desc); + return(1); +} + +void physmem_forget_descriptor(int fd) +{ + struct desc_mapping *desc; + struct phys_desc *page; + struct list_head *ele, *next; + __u64 offset; + void *addr; + int err; + + desc = find_mapping(fd); + if(desc == NULL) + return; + + list_for_each_safe(ele, next, &desc->pages){ + page = list_entry(ele, struct phys_desc, list); + offset = page->offset; + addr = page->virt; + remove_mapping(page); + err = os_seek_file(fd, offset); + if(err) + panic("physmem_forget_descriptor - failed to seek " + "to %lld in fd %d, error = %d\n", + offset, fd, -err); + err = os_read_file(fd, addr, PAGE_SIZE); + if(err < 0) + panic("physmem_forget_descriptor - failed to read " + "from fd %d to 0x%p, error = %d\n", + fd, addr, -err); + } + + list_del(&desc->list); + kfree(desc); +} + +void arch_free_page(struct page *page, int order) +{ + void *virt; + int i; + + for(i = 0; i < (1 << order); i++){ + virt = __va(page_to_phys(page + i)); + physmem_remove_mapping(virt); + } +} + +int is_remapped(void *virt) +{ + return(find_virtmem_hash(&virtmem_hash, virt) != NULL); +} + +/* Changed during early boot */ +unsigned long high_physmem; + +extern unsigned long physmem_size; + +void *to_virt(unsigned long phys) +{ + return((void *) uml_physmem + phys); +} + +unsigned long to_phys(void *virt) +{ + return(((unsigned long) virt) - uml_physmem); +} + +int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) +{ + struct page *p, *map; + unsigned long phys_len, phys_pages, highmem_len, highmem_pages; + unsigned long iomem_len, iomem_pages, total_len, total_pages; + int i; + + phys_pages = physmem >> PAGE_SHIFT; + phys_len = phys_pages * sizeof(struct page); + + iomem_pages = iomem >> PAGE_SHIFT; + iomem_len = iomem_pages * sizeof(struct page); + + highmem_pages = highmem >> PAGE_SHIFT; + highmem_len = highmem_pages * sizeof(struct page); + + total_pages = phys_pages + iomem_pages + highmem_pages; + total_len = phys_len + iomem_pages + highmem_len; + + if(kmalloc_ok){ + map = kmalloc(total_len, GFP_KERNEL); + if(map == NULL) + map = vmalloc(total_len); + } + else map = alloc_bootmem_low_pages(total_len); + + if(map == NULL) + return(-ENOMEM); + + for(i = 0; i < total_pages; i++){ + p = &map[i]; + set_page_count(p, 0); + SetPageReserved(p); + INIT_LIST_HEAD(&p->lru); + } + + mem_map = map; + max_mapnr = total_pages; + return(0); +} + +struct page *phys_to_page(const unsigned long phys) +{ + return(&mem_map[phys >> PAGE_SHIFT]); +} + +struct page *__virt_to_page(const unsigned long virt) +{ + return(&mem_map[__pa(virt) >> PAGE_SHIFT]); +} + +unsigned long page_to_phys(struct page *page) +{ + return((page - mem_map) << PAGE_SHIFT); +} + +pte_t mk_pte(struct page *page, pgprot_t pgprot) +{ + pte_t pte; + + pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot); + if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte)); + return(pte); +} + +/* Changed during early boot */ +static unsigned long kmem_top = 0; + +unsigned long get_kmem_end(void) +{ + if(kmem_top == 0) + kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); + return(kmem_top); +} + +void map_memory(unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) +{ + __u64 offset; + int fd, err; + + fd = phys_mapping(phys, &offset); + err = os_map_memory((void *) virt, fd, offset, len, r, w, x); + if(err) + panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " + "err = %d\n", virt, fd, offset, len, r, w, x, err); +} + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) + +void setup_physmem(unsigned long start, unsigned long reserve_end, + unsigned long len, unsigned long highmem) +{ + unsigned long reserve = reserve_end - start; + int pfn = PFN_UP(__pa(reserve_end)); + int delta = (len - reserve) >> PAGE_SHIFT; + int err, offset, bootmap_size; + + physmem_fd = create_mem_file(len + highmem); + + offset = uml_reserved - uml_physmem; + err = os_map_memory((void *) uml_reserved, physmem_fd, offset, + len - offset, 1, 1, 0); + if(err < 0){ + os_print_error(err, "Mapping memory"); + exit(1); + } + + bootmap_size = init_bootmem(pfn, pfn + delta); + free_bootmem(__pa(reserve_end) + bootmap_size, + len - bootmap_size - reserve); +} + +int phys_mapping(unsigned long phys, __u64 *offset_out) +{ + struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, + __va(phys & PAGE_MASK)); + int fd = -1; + + if(desc != NULL){ + fd = desc->fd; + *offset_out = desc->offset; + } + else if(phys < physmem_size){ + fd = physmem_fd; + *offset_out = phys; + } + else if(phys < __pa(end_iomem)){ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if((phys >= region->phys) && + (phys < region->phys + region->size)){ + fd = region->fd; + *offset_out = phys - region->phys; + break; + } + region = region->next; + } + } + else if(phys < __pa(end_iomem) + highmem){ + fd = physmem_fd; + *offset_out = phys - iomem_size; + } + + return(fd); +} + +static int __init uml_mem_setup(char *line, int *add) +{ + char *retptr; + physmem_size = memparse(line,&retptr); + return 0; +} +__uml_setup("mem=", uml_mem_setup, +"mem=\n" +" This controls how much \"physical\" memory the kernel allocates\n" +" for the system. The size is specified as a number followed by\n" +" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" +" This is not related to the amount of memory in the host. It can\n" +" be more, and the excess, if it's ever used, will just be swapped out.\n" +" Example: mem=64M\n\n" +); + +unsigned long find_iomem(char *driver, unsigned long *len_out) +{ + struct iomem_region *region = iomem_regions; + + while(region != NULL){ + if(!strcmp(region->driver, driver)){ + *len_out = region->size; + return(region->virt); + } + } + + return(0); +} + +int setup_iomem(void) +{ + struct iomem_region *region = iomem_regions; + unsigned long iomem_start = high_physmem + PAGE_SIZE; + int err; + + while(region != NULL){ + err = os_map_memory((void *) iomem_start, region->fd, 0, + region->size, 1, 1, 0); + if(err) + printk("Mapping iomem region for driver '%s' failed, " + "errno = %d\n", region->driver, -err); + else { + region->virt = iomem_start; + region->phys = __pa(region->virt); + } + + iomem_start += region->size + PAGE_SIZE; + region = region->next; + } + + return(0); +} + +__initcall(setup_iomem); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/kernel/process.c 2003-06-14 12:18:32.000000000 -0700 +++ 25/arch/um/kernel/process.c 2004-07-13 17:09:48.000000000 -0700 @@ -9,18 +9,17 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include #include +#include #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -58,7 +57,11 @@ void init_new_thread_signals(int altstac { int flags = altstack ? SA_ONSTACK : 0; - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, + /* NODEFER is set here because SEGV isn't turned back on when the + * handler is ready to receive signals. This causes any segfault + * during a copy_user to kill the process because the fault is blocked. + */ + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); @@ -72,7 +75,6 @@ void init_new_thread_signals(int altstac SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); - (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -123,11 +125,12 @@ int start_fork_tramp(void *thread_arg, u /* Start the process and wait for it to kill itself */ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); if(new_pid < 0) return(-errno); - while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ; + CATCH_EINTR(err = waitpid(new_pid, &status, 0)); if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", errno); if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) - panic("outer trampoline didn't exit with SIGKILL"); + panic("outer trampoline didn't exit with SIGKILL, " + "status = %d", status); return(arg.pid); } @@ -138,7 +141,7 @@ void suspend_new_thread(int fd) os_stop_process(os_getpid()); - if(read(fd, &c, sizeof(c)) != sizeof(c)) + if(os_read_file(fd, &c, sizeof(c)) != sizeof(c)) panic("read failed in suspend_new_thread"); } @@ -168,7 +171,7 @@ static int start_ptraced_child(void **st pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); if(pid < 0) panic("check_ptrace : clone failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) @@ -185,7 +188,7 @@ static void stop_ptraced_child(int pid, if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, 0); + CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) panic("check_ptrace : child exited with status 0x%x", status); @@ -193,6 +196,66 @@ static void stop_ptraced_child(int pid, panic("check_ptrace : munmap failed, errno = %d", errno); } +static int force_sysemu_disabled = 0; + +static int __init nosysemu_cmd_param(char *str, int* add) +{ + force_sysemu_disabled = 1; + return 0; +} + +__uml_setup("nosysemu", nosysemu_cmd_param, + "nosysemu\n" + " Turns off syscall emulation patch for ptrace (SYSEMU) on.\n" + " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" + " behaviour of ptrace() and helps reducing host context switch rate.\n" + " To make it working, you need a kernel patch for your host, too.\n" + " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further information.\n"); + +static void __init check_sysemu(void) +{ + void *stack; + int pid, n, status; + + if (mode_tt) + return; + + printk("Checking syscall emulation patch for ptrace..."); + sysemu_supported = 0; + pid = start_ptraced_child(&stack); + if(ptrace(PTRACE_SYSEMU, pid, 0, 0) >= 0) { + struct user_regs_struct regs; + + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + if (n < 0) + panic("check_ptrace : wait failed, errno = %d", errno); + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("check_ptrace : expected SIGTRAP, " + "got status = %d", status); + + if (ptrace(PTRACE_GETREGS, pid, 0, ®s) < 0) + panic("check_ptrace : failed to read child " + "registers, errno = %d", errno); + regs.orig_eax = pid; + if (ptrace(PTRACE_SETREGS, pid, 0, ®s) < 0) + panic("check_ptrace : failed to modify child " + "registers, errno = %d", errno); + + stop_ptraced_child(pid, stack, 0); + + sysemu_supported = 1; + printk("found\n"); + } + else + { + stop_ptraced_child(pid, stack, 1); + sysemu_supported = 0; + printk("missing\n"); + } + + set_using_sysemu(!force_sysemu_disabled); +} + void __init check_ptrace(void) { void *stack; @@ -205,7 +268,7 @@ void __init check_ptrace(void) if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) @@ -225,6 +288,7 @@ void __init check_ptrace(void) } stop_ptraced_child(pid, stack, 0); printk("OK\n"); + check_sysemu(); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) @@ -233,7 +297,7 @@ int run_kernel_thread(int (*fn)(void *), int n; *jmp_ptr = &buf; - n = setjmp(buf); + n = sigsetjmp(buf, 1); if(n != 0) return(n); (*fn)(arg); @@ -273,7 +337,7 @@ int can_do_skas(void) stop_ptraced_child(pid, stack, 1); printf("Checking for /proc/mm..."); - if(access("/proc/mm", W_OK)){ + if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ printf("not found\n"); ret = 0; } --- linux-2.6.8-rc1/arch/um/kernel/process_kern.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/um/kernel/process_kern.c 2004-07-13 17:09:49.000000000 -0700 @@ -16,6 +16,8 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/vmalloc.h" +#include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -23,7 +25,6 @@ #include "asm/pgtable.h" #include "asm/processor.h" #include "asm/tlbflush.h" -#include "asm/spinlock.h" #include "asm/uaccess.h" #include "asm/user.h" #include "user_util.h" @@ -52,17 +53,12 @@ struct cpu_task cpu_tasks[NR_CPUS] = { [ struct task_struct *get_task(int pid, int require) { - struct task_struct *task, *ret; + struct task_struct *ret; - ret = NULL; read_lock(&tasklist_lock); - for_each_process(task){ - if(task->pid == pid){ - ret = task; - break; - } - } + ret = find_task_by_pid(pid); read_unlock(&tasklist_lock); + if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); return(ret); } @@ -95,7 +91,8 @@ unsigned long alloc_stack(int order, int int flags = GFP_KERNEL; if(atomic) flags |= GFP_ATOMIC; - if((page = __get_free_pages(flags, order)) == 0) + page = __get_free_pages(flags, order); + if(page == 0) return(0); stack_protections(page); return(page); @@ -103,13 +100,15 @@ unsigned long alloc_stack(int order, int int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { - struct task_struct *p; + int pid; current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL); - if(IS_ERR(p)) panic("do_fork failed in kernel_thread"); - return(p->pid); + pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL, + NULL); + if(pid < 0) + panic("do_fork failed in kernel_thread, errno = %d", pid); + return(pid); } void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -129,7 +128,7 @@ void set_current(void *t) { external_pid(task), task }); } -void *switch_to(void *prev, void *next, void *last) +void *_switch_to(void *prev, void *next, void *last) { return(CHOOSE_MODE(switch_to_tt(prev, next), switch_to_skas(prev, next))); @@ -149,7 +148,7 @@ void release_thread(struct task_struct * void exit_thread(void) { CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); } void *get_current(void) @@ -157,13 +156,17 @@ void *get_current(void) return(current); } +void prepare_to_copy(struct task_struct *tsk) +{ +} + int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { p->thread = (struct thread_struct) INIT_THREAD; p->thread.kernel_stack = - (unsigned long) p->thread_info + 2 * PAGE_SIZE; + (unsigned long) p->thread_info + THREAD_SIZE; return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, clone_flags, sp, stack_top, p, regs)); } @@ -190,7 +193,7 @@ int current_pid(void) void default_idle(void) { - idle_timer(); + uml_idle_timer(); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; @@ -299,6 +302,11 @@ void *um_kmalloc_atomic(int size) return(kmalloc(size, GFP_ATOMIC)); } +void *um_vmalloc(int size) +{ + return(vmalloc(size)); +} + unsigned long get_fault_addr(void) { return((unsigned long) current->thread.fault_addr); @@ -367,10 +375,15 @@ int clear_user_proc(void *buf, int size) return(clear_user(buf, size)); } +int strlen_user_proc(char *str) +{ + return(strlen_user(str)); +} + int smp_sigio_handler(void) { #ifdef CONFIG_SMP - int cpu = current->thread_info->cpu; + int cpu = current_thread->cpu; IPI_handler(cpu); if(cpu != 0) return(1); @@ -385,7 +398,7 @@ int um_in_interrupt(void) int cpu(void) { - return(current->thread_info->cpu); + return(current_thread->cpu); } /* --- linux-2.6.8-rc1/arch/um/kernel/ptrace.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/kernel/ptrace.c 2004-07-13 17:09:45.000000000 -0700 @@ -24,11 +24,6 @@ void ptrace_disable(struct task_struct * { } -extern long do_mmap2(struct task_struct *task, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, - unsigned long pgoff); - int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -302,8 +297,17 @@ int sys_ptrace(long request, long pid, l return ret; } -void syscall_trace(void) +void syscall_trace(union uml_pt_regs *regs, int entryexit) { + if (unlikely(current->audit_context)) { + if (!entryexit) + audit_syscall_entry(current, regs->orig_eax, + regs->ebx, regs->ecx, + regs->edx, regs->esi); + else + audit_syscall_exit(current, regs->eax); + } + if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; if (!(current->ptrace & PT_PTRACED)) @@ -311,11 +315,8 @@ void syscall_trace(void) /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; - notify_parent(current, SIGCHLD); - schedule(); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do --- linux-2.6.8-rc1/arch/um/kernel/reboot.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/um/kernel/reboot.c 2004-07-13 17:09:45.000000000 -0700 @@ -15,6 +15,7 @@ #ifdef CONFIG_SMP static void kill_idlers(int me) { +#ifdef CONFIG_MODE_TT struct task_struct *p; int i; @@ -23,6 +24,7 @@ static void kill_idlers(int me) if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) os_kill_process(p->thread.mode.tt.extern_pid, 0); } +#endif } #endif --- linux-2.6.8-rc1/arch/um/kernel/sigio_kern.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/um/kernel/sigio_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -6,18 +6,21 @@ #include "linux/kernel.h" #include "linux/list.h" #include "linux/slab.h" -#include "asm/irq.h" +#include "linux/signal.h" +#include "linux/interrupt.h" #include "init.h" #include "sigio.h" #include "irq_user.h" +#include "irq_kern.h" /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; -void sigio_interrupt(int irq, void *data, struct pt_regs *unused) +irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) { read_sigio_fd(sigio_irq_fd); reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); + return(IRQ_HANDLED); } int write_sigio_irq(int fd) --- linux-2.6.8-rc1/arch/um/kernel/sigio_user.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/arch/um/kernel/sigio_user.c 2004-07-13 17:09:47.000000000 -0700 @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include "init.h" #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "sigio.h" #include "helper.h" #include "os.h" @@ -26,7 +26,7 @@ int pty_output_sigio = 0; int pty_close_sigio = 0; /* Used as a flag during SIGIO testing early in boot */ -static int got_sigio = 0; +static volatile int got_sigio = 0; void __init handler(int sig) { @@ -45,19 +45,18 @@ static void openpty_cb(void *arg) info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) - info->err = errno; + info->err = -errno; } void __init check_one_sigio(void (*proc)(int, int)) { struct sigaction old, new; - struct termios tt; struct openpty_arg pty = { .master = -1, .slave = -1 }; - int master, slave, flags; + int master, slave, err; initial_thread_cb(openpty_cb, &pty); if(pty.err){ - printk("openpty failed, errno = %d\n", pty.err); + printk("openpty failed, errno = %d\n", -pty.err); return; } @@ -69,23 +68,13 @@ void __init check_one_sigio(void (*proc) return; } - if(tcgetattr(master, &tt) < 0) - panic("check_sigio : tcgetattr failed, errno = %d\n", errno); - cfmakeraw(&tt); - if(tcsetattr(master, TCSADRAIN, &tt) < 0) - panic("check_sigio : tcsetattr failed, errno = %d\n", errno); - - if((flags = fcntl(master, F_GETFL)) < 0) - panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno); - - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) - panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, " - "errno = %d\n", errno); - - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) - panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", - errno); + err = __raw(master, 1, 0); //Not now, but complain so we now where we failed. + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); + + err = os_sigio_async(master, slave); + if(err < 0) + panic("tty_fds : sigio_async failed, err = %d\n", -err); if(sigaction(SIGIO, NULL, &old) < 0) panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); @@ -97,8 +86,8 @@ void __init check_one_sigio(void (*proc) got_sigio = 0; (*proc)(master, slave); - close(master); - close(slave); + os_close_file(master); + os_close_file(slave); if(sigaction(SIGIO, &old, NULL) < 0) panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); @@ -112,25 +101,25 @@ static void tty_output(int master, int s printk("Checking that host ptys support output SIGIO..."); memset(buf, 0, sizeof(buf)); - while(write(master, buf, sizeof(buf)) > 0) ; + + while(os_write_file(master, buf, sizeof(buf)) > 0) ; if(errno != EAGAIN) panic("check_sigio : write failed, errno = %d\n", errno); - - while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; if(got_sigio){ printk("Yes\n"); pty_output_sigio = 1; } - else if(errno == EAGAIN) printk("No, enabling workaround\n"); - else panic("check_sigio : read failed, errno = %d\n", errno); + else if(n == -EAGAIN) printk("No, enabling workaround\n"); + else panic("check_sigio : read failed, err = %d\n", n); } static void tty_close(int master, int slave) { printk("Checking that host ptys support SIGIO on close..."); - close(slave); + os_close_file(slave); if(got_sigio){ printk("Yes\n"); pty_close_sigio = 1; @@ -140,7 +129,8 @@ static void tty_close(int master, int sl void __init check_sigio(void) { - if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){ + if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && + (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ printk("No pseudo-terminals available - skipping pty SIGIO " "check\n"); return; @@ -201,11 +191,10 @@ static int write_sigio_thread(void *unus p = &fds->poll[i]; if(p->revents == 0) continue; if(p->fd == sigio_private[1]){ - n = read(sigio_private[1], &c, sizeof(c)); + n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, errno = %d\n", - errno); + "read failed, err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -218,10 +207,10 @@ static int write_sigio_thread(void *unus (fds->used - i) * sizeof(*fds->poll)); } - n = write(respond_fd, &c, sizeof(c)); + n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : write failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } } } @@ -252,15 +241,15 @@ static void update_thread(void) char c; flags = set_signals(0); - n = write(sigio_private[0], &c, sizeof(c)); + n = os_write_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : write failed, errno = %d\n", errno); + printk("update_thread : write failed, err = %d\n", -n); goto fail; } - n = read(sigio_private[0], &c, sizeof(c)); + n = os_read_file(sigio_private[0], &c, sizeof(c)); if(n != sizeof(c)){ - printk("update_thread : read failed, errno = %d\n", errno); + printk("update_thread : read failed, err = %d\n", -n); goto fail; } @@ -271,10 +260,10 @@ static void update_thread(void) if(write_sigio_pid != -1) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; - close(sigio_private[0]); - close(sigio_private[1]); - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); set_signals(flags); } @@ -369,15 +358,15 @@ void write_sigio_workaround(void) goto out; err = os_pipe(write_sigio_fds, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 1 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out; } err = os_pipe(sigio_private, 1, 1); - if(err){ + if(err < 0){ printk("write_sigio_workaround - os_pipe 2 failed, " - "errno = %d\n", -err); + "err = %d\n", -err); goto out_close1; } if(setup_initial_poll(sigio_private[1])) @@ -399,11 +388,11 @@ void write_sigio_workaround(void) os_kill_process(write_sigio_pid, 1); write_sigio_pid = -1; out_close2: - close(sigio_private[0]); - close(sigio_private[1]); + os_close_file(sigio_private[0]); + os_close_file(sigio_private[1]); out_close1: - close(write_sigio_fds[0]); - close(write_sigio_fds[1]); + os_close_file(write_sigio_fds[0]); + os_close_file(write_sigio_fds[1]); sigio_unlock(); } @@ -412,10 +401,16 @@ int read_sigio_fd(int fd) int n; char c; - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ - printk("read_sigio_fd - read failed, errno = %d\n", errno); - return(-errno); + if(n < 0) { + printk("read_sigio_fd - read failed, err = %d\n", -n); + return(n); + } + else { + printk("read_sigio_fd - short read, bytes = %d\n", n); + return(-EIO); + } } return(n); } --- linux-2.6.8-rc1/arch/um/kernel/signal_kern.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/kernel/signal_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -36,7 +36,7 @@ static void force_segv(int sig) if(sig == SIGSEGV){ struct k_sigaction *ka; - ka = ¤t->sig->action[SIGSEGV - 1]; + ka = ¤t->sighand->action[SIGSEGV - 1]; ka->sa.sa_handler = SIG_DFL; } force_sig(SIGSEGV, current); @@ -60,10 +60,10 @@ static int handle_signal(struct pt_regs int err, ret; ret = 0; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; switch(error){ case -ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = - do_no_restart_syscall; case -ERESTARTNOHAND: ret = -EINTR; break; @@ -142,7 +142,7 @@ static int kern_do_signal(struct pt_regs return(0); /* Whee! Actually deliver the signal. */ - ka = ¤t->sig->action[sig -1 ]; + ka = ¤t->sighand->action[sig -1 ]; err = handle_signal(regs, sig, ka, &info, oldset, error); if(!err) return(1); @@ -201,7 +201,7 @@ int sys_sigsuspend(int history0, int his } } -int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) { sigset_t saveset, newset; @@ -227,20 +227,59 @@ int sys_rt_sigsuspend(sigset_t *unewset, } } +int sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); +} + +extern int userspace_pid[]; + static int copy_sc_from_user(struct pt_regs *to, void *from, struct arch_frame_data *arch) { int ret; ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), - copy_sc_from_user_skas(&to->regs, from)); + copy_sc_from_user_skas(userspace_pid[0], + &to->regs, from)); return(ret); } int sys_sigreturn(struct pt_regs regs) { - void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); - void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); + void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); + void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -257,8 +296,8 @@ int sys_sigreturn(struct pt_regs regs) int sys_rt_sigreturn(struct pt_regs regs) { - struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs)); - void *fp; + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct ucontext __user *uc = sp_to_uc(sp); int sig_size = _NSIG_WORDS * sizeof(unsigned long); spin_lock_irq(¤t->sighand->siglock); @@ -266,7 +305,6 @@ int sys_rt_sigreturn(struct pt_regs regs sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext)); copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, &signal_frame_si.common.arch); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); --- linux-2.6.8-rc1/arch/um/kernel/skas/exec_user.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/kernel/skas/exec_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -11,6 +11,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" #include "time_user.h" @@ -26,7 +27,7 @@ static int user_thread_tramp(void *arg) int user_thread(unsigned long stack, int flags) { - int pid, status; + int pid, status, err; pid = clone(user_thread_tramp, (void *) stack_sp(stack), flags | CLONE_FILES | SIGCHLD, NULL); @@ -35,7 +36,8 @@ int user_thread(unsigned long stack, int return(pid); } - if(waitpid(pid, &status, WUNTRACED) < 0){ + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if(err < 0){ printk("user_thread - waitpid failed, errno = %d\n", errno); return(-errno); } --- linux-2.6.8-rc1/arch/um/kernel/skas/include/mode.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/kernel/skas/include/mode.h 2004-07-13 17:09:45.000000000 -0700 @@ -12,14 +12,16 @@ extern unsigned long exec_fpx_regs[]; extern int have_fpx_regs; extern void user_time_init_skas(void); -extern int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr); -extern int copy_sc_to_user_skas(void *to_ptr, void *fp, +extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, + void *from_ptr); +extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, union uml_pt_regs *regs, unsigned long fault_addr, int fault_type); extern void sig_handler_common_skas(int sig, void *sc_ptr); extern void halt_skas(void); extern void reboot_skas(void); extern void kill_off_processes_skas(void); +extern int is_skas_winch(int pid, int fd, void *data); #endif --- linux-2.6.8-rc1/arch/um/kernel/skas/include/ptrace-skas.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/kernel/skas/include/ptrace-skas.h 2004-07-13 17:09:48.000000000 -0700 @@ -10,6 +10,16 @@ #ifdef UML_CONFIG_MODE_SKAS +/* syscall emulation path in ptrace */ + +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +void set_using_sysemu(int value); +int get_using_sysemu(void); +extern int sysemu_supported; + #include "skas_ptregs.h" #define HOST_FRAME_SIZE 17 --- linux-2.6.8-rc1/arch/um/kernel/skas/include/skas.h 2003-06-14 12:18:06.000000000 -0700 +++ 25/arch/um/kernel/skas/include/skas.h 2004-07-13 17:09:45.000000000 -0700 @@ -8,7 +8,7 @@ #include "sysdep/ptrace.h" -extern int userspace_pid; +extern int userspace_pid[]; extern void switch_threads(void *me, void *next); extern void thread_wait(void *sw, void *fb); @@ -32,7 +32,7 @@ extern int singlestepping_skas(void); extern int new_mm(int from); extern void save_registers(union uml_pt_regs *regs); extern void restore_registers(union uml_pt_regs *regs); -extern void start_userspace(void); +extern void start_userspace(int cpu); extern void init_registers(int pid); #endif --- linux-2.6.8-rc1/arch/um/kernel/skas/include/uaccess.h 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/skas/include/uaccess.h 2004-07-13 17:09:45.000000000 -0700 @@ -6,20 +6,12 @@ #ifndef __SKAS_UACCESS_H #define __SKAS_UACCESS_H -#include "linux/string.h" -#include "linux/sched.h" -#include "linux/err.h" -#include "asm/processor.h" -#include "asm/pgtable.h" #include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" -#include "kern_util.h" #define access_ok_skas(type, addr, size) \ ((segment_eq(get_fs(), KERNEL_DS)) || \ (((unsigned long) (addr) < TASK_SIZE) && \ - ((unsigned long) (addr) + (size) < TASK_SIZE))) + ((unsigned long) (addr) + (size) <= TASK_SIZE))) static inline int verify_area_skas(int type, const void * addr, unsigned long size) @@ -27,197 +19,12 @@ static inline int verify_area_skas(int t return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); } -static inline unsigned long maybe_map(unsigned long virt, int is_write) -{ - pte_t pte; - - void *phys = um_virt_to_phys(current, virt, &pte); - int dummy_code; - - if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - if(handle_page_fault(virt, 0, is_write, 0, &dummy_code)) - return(0); - phys = um_virt_to_phys(current, virt, NULL); - } - return((unsigned long) __va((unsigned long) phys)); -} - -static inline int buffer_op(unsigned long addr, int len, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) -{ - int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); - int remain = len, n; - - n = (*op)(addr, size, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += size; - remain -= size; - if(remain == 0) - return(0); - - while(addr < ((addr + remain) & PAGE_MASK)){ - n = (*op)(addr, PAGE_SIZE, arg); - if(n != 0) - return(n < 0 ? remain : 0); - - addr += PAGE_SIZE; - remain -= PAGE_SIZE; - } - if(remain == 0) - return(0); - - n = (*op)(addr, remain, arg); - if(n != 0) - return(n < 0 ? remain : 0); - return(0); -} - -static inline int copy_chunk_from_user(unsigned long from, int len, void *arg) -{ - unsigned long *to_ptr = arg, to = *to_ptr; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *to_ptr += len; - return(0); -} - -static inline int copy_from_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_READ, from, n) ? - buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) : - n); -} - -static inline int copy_chunk_to_user(unsigned long to, int len, void *arg) -{ - unsigned long *from_ptr = arg, from = *from_ptr; - - to = maybe_map(to, 1); - if(to == 0) - return(-1); - - memcpy((void *) to, (void *) from, len); - *from_ptr += len; - return(0); -} - -static inline int copy_to_user_skas(void *to, const void *from, int n) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memcpy(to, from, n); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, to, n) ? - buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) : - n); -} - -static inline int strncpy_chunk_from_user(unsigned long from, int len, - void *arg) -{ - char **to_ptr = arg, *to = *to_ptr; - int n; - - from = maybe_map(from, 0); - if(from == 0) - return(-1); - - strncpy(to, (void *) from, len); - n = strnlen(to, len); - *to_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strncpy_from_user_skas(char *dst, const char *src, int count) -{ - int n; - char *ptr = dst; - - if(segment_eq(get_fs(), KERNEL_DS)){ - strncpy(dst, src, count); - return(strnlen(dst, count)); - } - - if(!access_ok_skas(VERIFY_READ, src, 1)) - return(-EFAULT); - - n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, - &ptr); - if(n != 0) - return(-EFAULT); - return(strnlen(dst, count)); -} - -static inline int clear_chunk(unsigned long addr, int len, void *unused) -{ - addr = maybe_map(addr, 1); - if(addr == 0) - return(-1); - - memset((void *) addr, 0, len); - return(0); -} - -static inline int __clear_user_skas(void *mem, int len) -{ - return(buffer_op((unsigned long) mem, len, clear_chunk, NULL)); -} - -static inline int clear_user_skas(void *mem, int len) -{ - if(segment_eq(get_fs(), KERNEL_DS)){ - memset(mem, 0, len); - return(0); - } - - return(access_ok_skas(VERIFY_WRITE, mem, len) ? - buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len); -} - -static inline int strnlen_chunk(unsigned long str, int len, void *arg) -{ - int *len_ptr = arg, n; - - str = maybe_map(str, 0); - if(str == 0) - return(-1); - - n = strnlen((void *) str, len); - *len_ptr += n; - - if(n < len) - return(1); - return(0); -} - -static inline int strnlen_user_skas(const void *str, int len) -{ - int count = 0, n; - - if(segment_eq(get_fs(), KERNEL_DS)) - return(strnlen(str, len) + 1); - - n = buffer_op((unsigned long) str, len, strnlen_chunk, &count); - if(n == 0) - return(count + 1); - return(-EFAULT); -} +extern int copy_from_user_skas(void *to, const void *from, int n); +extern int copy_to_user_skas(void *to, const void *from, int n); +extern int strncpy_from_user_skas(char *dst, const char *src, int count); +extern int __clear_user_skas(void *mem, int len); +extern int clear_user_skas(void *mem, int len); +extern int strnlen_user_skas(const void *str, int len); #endif --- linux-2.6.8-rc1/arch/um/kernel/skas/Makefile 2003-06-14 12:18:06.000000000 -0700 +++ 25/arch/um/kernel/skas/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -5,20 +5,24 @@ obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ - sys-$(SUBARCH)/ + uaccess.o sys-$(SUBARCH)/ + +host-progs := util/mk_ptregs +clean-files := include/skas_ptregs.h USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -include/skas_ptregs.h : util/mk_ptregs - util/mk_ptregs > $@ - -util/mk_ptregs : - $(MAKE) -C util +$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs + @echo -n ' Generating $@' + @$< > $@.tmp + @if [ -r $@ ] && cmp -s $@ $@.tmp; then \ + echo ' (unchanged)'; \ + rm -f $@.tmp; \ + else \ + echo ' (updated)'; \ + mv -f $@.tmp $@; \ + fi $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : - $(MAKE) -C util clean - $(RM) -f include/skas_ptregs.h --- linux-2.6.8-rc1/arch/um/kernel/skas/mem_user.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/arch/um/kernel/skas/mem_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -7,6 +7,7 @@ #include #include #include "mem_user.h" +#include "mem.h" #include "user.h" #include "os.h" #include "proc_mm.h" @@ -15,12 +16,12 @@ void map(int fd, unsigned long virt, uns int r, int w, int x) { struct proc_mm_op map; - struct mem_region *region; - int prot, n; + __u64 offset; + int prot, n, phys_fd; prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - region = phys_region(phys); + phys_fd = phys_mapping(phys, &offset); map = ((struct proc_mm_op) { .op = MM_MMAP, .u = @@ -30,12 +31,12 @@ void map(int fd, unsigned long virt, uns .prot = prot, .flags = MAP_SHARED | MAP_FIXED, - .fd = region->fd, - .offset = phys_offset(phys) + .fd = phys_fd, + .offset = offset } } } ); n = os_write_file(fd, &map, sizeof(map)); if(n != sizeof(map)) - printk("map : /proc/mm map failed, errno = %d\n", errno); + printk("map : /proc/mm map failed, err = %d\n", -n); } int unmap(int fd, void *addr, int len) @@ -49,8 +50,13 @@ int unmap(int fd, void *addr, int len) { .addr = (unsigned long) addr, .len = len } } } ); n = os_write_file(fd, &unmap, sizeof(unmap)); - if((n != 0) && (n != sizeof(unmap))) - return(-errno); + if(n != sizeof(unmap)) { + if(n < 0) + return(n); + else if(n > 0) + return(-EIO); + } + return(0); } @@ -71,11 +77,15 @@ int protect(int fd, unsigned long addr, .prot = prot } } } ); n = os_write_file(fd, &protect, sizeof(protect)); - if((n != 0) && (n != sizeof(protect))){ + if(n != sizeof(protect)) { + if(n == 0) return(0); + if(must_succeed) - panic("protect failed, errno = %d", errno); - return(-errno); + panic("protect failed, err = %d", -n); + + return(-EIO); } + return(0); } --- linux-2.6.8-rc1/arch/um/kernel/skas/mmu.c 2003-06-14 12:18:52.000000000 -0700 +++ 25/arch/um/kernel/skas/mmu.c 2004-07-13 17:09:45.000000000 -0700 @@ -22,9 +22,11 @@ int init_new_context_skas(struct task_st else from = -1; mm->context.skas.mm_fd = new_mm(from); - if(mm->context.skas.mm_fd < 0) - panic("init_new_context_skas - new_mm failed, errno = %d\n", - mm->context.skas.mm_fd); + if(mm->context.skas.mm_fd < 0){ + printk("init_new_context_skas - new_mm failed, errno = %d\n", + mm->context.skas.mm_fd); + return(mm->context.skas.mm_fd); + } return(0); } --- linux-2.6.8-rc1/arch/um/kernel/skas/process.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/arch/um/kernel/skas/process.c 2004-07-13 17:09:48.000000000 -0700 @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -24,6 +25,19 @@ #include "os.h" #include "proc_mm.h" #include "skas_ptrace.h" +#include "chan_user.h" +#include "signal_user.h" + +int is_skas_winch(int pid, int fd, void *data) +{ + if(pid != getpid()) + return(0); + + register_winch_irq(-1, fd, -1, data); + return(1); +} + +/* These are set once at boot time and not changed thereafter */ unsigned long exec_regs[FRAME_SIZE]; unsigned long exec_fp_regs[HOST_FP_SIZE]; @@ -43,37 +57,39 @@ static void handle_segv(int pid) segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); } -static void handle_trap(int pid, union uml_pt_regs *regs) +/*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ +static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) { int err, syscall_nr, status; syscall_nr = PT_SYSCALL_NR(regs->skas.regs); + UPT_SYSCALL_NR(regs) = syscall_nr; if(syscall_nr < 1){ relay_signal(SIGTRAP, regs); return; } - UPT_SYSCALL_NR(regs) = syscall_nr; - err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); - if(err < 0) - panic("handle_trap - nullifying syscall failed errno = %d\n", - errno); + if (!local_using_sysemu) + { + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); + if(err < 0) + panic("handle_trap - nullifying syscall failed errno = %d\n", + errno); + + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); + if(err < 0) + panic("handle_trap - continuing to end of syscall failed, " + "errno = %d\n", errno); - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if(err < 0) - panic("handle_trap - continuing to end of syscall failed, " - "errno = %d\n", errno); - - err = waitpid(pid, &status, WUNTRACED); - if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("handle_trap - failed to wait at end of syscall, " - "errno = %d, status = %d\n", errno, status); + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("handle_trap - failed to wait at end of syscall, " + "errno = %d, status = %d\n", errno, status); + } handle_syscall(regs); } -int userspace_pid; - static int userspace_tramp(void *arg) { init_new_thread_signals(0); @@ -83,7 +99,11 @@ static int userspace_tramp(void *arg) return(0); } -void start_userspace(void) +/* Each element set once, and only accessed by a single processor anyway */ +#define NR_CPUS 1 +int userspace_pid[NR_CPUS]; + +void start_userspace(int cpu) { void *stack; unsigned long sp; @@ -101,7 +121,7 @@ void start_userspace(void) panic("start_userspace : clone failed, errno = %d", errno); do { - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("start_userspace : wait failed, errno = %d", errno); @@ -114,21 +134,27 @@ void start_userspace(void) if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); - userspace_pid = pid; + userspace_pid[cpu] = pid; } void userspace(union uml_pt_regs *regs) { - int err, status, op; + int err, status, op, pid = userspace_pid[0]; + int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ restore_registers(regs); - err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + local_using_sysemu = get_using_sysemu(); + + if (local_using_sysemu) + err = ptrace(PTRACE_SYSEMU, pid, 0, 0); + else + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); if(err) - panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", - errno); + panic("userspace - PTRACE_%s failed, errno = %d\n", + local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); while(1){ - err = waitpid(userspace_pid, &status, WUNTRACED); + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); @@ -139,16 +165,17 @@ void userspace(union uml_pt_regs *regs) if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: - handle_segv(userspace_pid); + handle_segv(pid); break; case SIGTRAP: - handle_trap(userspace_pid, regs); + handle_trap(pid, regs, local_using_sysemu); break; case SIGIO: case SIGVTALRM: case SIGILL: case SIGBUS: case SIGFPE: + case SIGWINCH: user_signal(WSTOPSIG(status), regs); break; default: @@ -160,25 +187,46 @@ void userspace(union uml_pt_regs *regs) restore_registers(regs); - op = singlestepping_skas() ? PTRACE_SINGLESTEP : - PTRACE_SYSCALL; - err = ptrace(op, userspace_pid, 0, 0); + /*Now we ended the syscall, so re-read local_using_sysemu.*/ + local_using_sysemu = get_using_sysemu(); + + if (local_using_sysemu) + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSEMU; + else + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSCALL; + + err = ptrace(op, pid, 0, 0); if(err) - panic("userspace - PTRACE_SYSCALL failed, " - "errno = %d\n", errno); + panic("userspace - PTRACE_%s failed, " + "errno = %d\n", + local_using_sysemu ? "SYSEMU" : "SYSCALL", errno); } } void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { + unsigned long flags; jmp_buf switch_buf, fork_buf; *switch_buf_ptr = &switch_buf; *fork_buf_ptr = &fork_buf; - if(setjmp(fork_buf) == 0) + /* Somewhat subtle - siglongjmp restores the signal mask before doing + * the longjmp. This means that when jumping from one stack to another + * when the target stack has interrupts enabled, an interrupt may occur + * on the source stack. This is bad when starting up a process because + * it's not supposed to get timer ticks until it has been scheduled. + * So, we disable interrupts around the sigsetjmp to ensure that + * they can't happen until we get back here where they are safe. + */ + flags = get_signals(); + block_signals(); + if(sigsetjmp(fork_buf, 1) == 0) new_thread_proc(stack, handler); + set_signals(flags); remove_sigstack(); } @@ -189,16 +237,16 @@ void thread_wait(void *sw, void *fb) *switch_buf = &buf; fork_buf = fb; - if(setjmp(buf) == 0) - longjmp(*fork_buf, 1); + if(sigsetjmp(buf, 1) == 0) + siglongjmp(*fork_buf, 1); } -static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs, - unsigned long *fp_regs) +static int move_registers(int pid, int int_op, int fp_op, + union uml_pt_regs *regs, unsigned long *fp_regs) { - if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0) + if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) return(-errno); - if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) + if(ptrace(fp_op, pid, 0, fp_regs) < 0) return(-errno); return(0); } @@ -217,10 +265,11 @@ void save_registers(union uml_pt_regs *r fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs, + fp_regs); if(err) panic("save_registers - saving registers failed, errno = %d\n", - err); + -err); } void restore_registers(union uml_pt_regs *regs) @@ -237,10 +286,11 @@ void restore_registers(union uml_pt_regs fp_regs = regs->skas.fp; } - err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); + err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs, + fp_regs); if(err) panic("restore_registers - saving registers failed, " - "errno = %d\n", err); + "errno = %d\n", -err); } void switch_threads(void *me, void *next) @@ -248,8 +298,8 @@ void switch_threads(void *me, void *next jmp_buf my_buf, **me_ptr = me, *next_buf = next; *me_ptr = &my_buf; - if(setjmp(my_buf) == 0) - longjmp(*next_buf, 1); + if(sigsetjmp(my_buf, 1) == 0) + siglongjmp(*next_buf, 1); } static jmp_buf initial_jmpbuf; @@ -265,14 +315,14 @@ int start_idle_thread(void *stack, void int n; *fork_buf_ptr = &initial_jmpbuf; - n = setjmp(initial_jmpbuf); + n = sigsetjmp(initial_jmpbuf, 1); if(n == 0) new_thread_proc((void *) stack, new_thread_handler); else if(n == 1) remove_sigstack(); else if(n == 2){ (*cb_proc)(cb_arg); - longjmp(*cb_back, 1); + siglongjmp(*cb_back, 1); } else if(n == 3){ kmalloc_ok = 0; @@ -282,7 +332,7 @@ int start_idle_thread(void *stack, void kmalloc_ok = 0; return(1); } - longjmp(**switch_buf, 1); + siglongjmp(**switch_buf, 1); } void remove_sigstack(void) @@ -304,8 +354,8 @@ void initial_thread_cb_skas(void (*proc) cb_back = &here; block_signals(); - if(setjmp(here) == 0) - longjmp(initial_jmpbuf, 2); + if(sigsetjmp(here, 1) == 0) + siglongjmp(initial_jmpbuf, 2); unblock_signals(); cb_proc = NULL; @@ -316,22 +366,23 @@ void initial_thread_cb_skas(void (*proc) void halt_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 3); + siglongjmp(initial_jmpbuf, 3); } void reboot_skas(void) { block_signals(); - longjmp(initial_jmpbuf, 4); + siglongjmp(initial_jmpbuf, 4); } int new_mm(int from) { struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + int n, fd = os_open_file("/proc/mm", + of_cloexec(of_write(OPENFLAGS())), 0); if(fd < 0) - return(-errno); + return(fd); if(from != -1){ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, @@ -340,8 +391,9 @@ int new_mm(int from) n = os_write_file(fd, ©, sizeof(copy)); if(n != sizeof(copy)) printk("new_mm : /proc/mm copy_segments failed, " - "errno = %d\n", errno); + "err = %d\n", -n); } + return(fd); } @@ -349,7 +401,8 @@ void switch_mm_skas(int mm_fd) { int err; - err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); +#warning need cpu pid in switch_mm_skas + err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); if(err) panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", errno); @@ -357,7 +410,8 @@ void switch_mm_skas(int mm_fd) void kill_off_processes_skas(void) { - os_kill_process(userspace_pid, 1); +#warning need to loop over userspace_pids in kill_off_processes_skas + os_kill_process(userspace_pid[0], 1); } void init_registers(int pid) --- linux-2.6.8-rc1/arch/um/kernel/skas/process_kern.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/um/kernel/skas/process_kern.c 2004-07-13 17:09:48.000000000 -0700 @@ -6,6 +6,12 @@ #include "linux/sched.h" #include "linux/slab.h" #include "linux/ptrace.h" +#include "linux/proc_fs.h" +#include "linux/file.h" +#include "linux/errno.h" +#include "linux/init.h" +#include "asm/uaccess.h" +#include "asm/atomic.h" #include "kern_util.h" #include "time_user.h" #include "signal_user.h" @@ -17,6 +23,61 @@ #include "kern.h" #include "mode.h" +static atomic_t using_sysemu; +int sysemu_supported; + +void set_using_sysemu(int value) +{ + atomic_set(&using_sysemu, sysemu_supported && value); +} + +int get_using_sysemu(void) +{ + return atomic_read(&using_sysemu); +} + +int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data) +{ + if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/ + *eof = 1; + + return strlen(buf); +} + +int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) +{ + char tmp[2]; + + if (copy_from_user(tmp, buf, 1)) + return -EFAULT; + + if (tmp[0] == '0' || tmp[0] == '1') + set_using_sysemu(tmp[0] - '0'); + return count; /*We use the first char, but pretend to write everything*/ +} + +int __init make_proc_sysemu(void) +{ + struct proc_dir_entry *ent; + if (mode_tt || !sysemu_supported) + return 0; + + ent = create_proc_entry("sysemu", 0600, &proc_root); + + if (ent == NULL) + { + printk("Failed to register /proc/sysemu\n"); + return(0); + } + + ent->read_proc = proc_read_sysemu; + ent->write_proc = proc_write_sysemu; + + return 0; +} + +late_initcall(make_proc_sysemu); + int singlestepping_skas(void) { int ret = current->ptrace & PT_DTRACE; @@ -61,11 +122,13 @@ void new_thread_handler(int sig) thread_wait(¤t->thread.mode.skas.switch_buf, current->thread.mode.skas.fork_buf); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + /* The return value is 1 if the kernel thread execs a process, + * 0 if it just exits + */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); if(n == 1) userspace(¤t->thread.regs.regs); @@ -93,11 +156,11 @@ void fork_handler(int sig) current->thread.mode.skas.fork_buf); force_flush_all(); -#ifdef CONFIG_SMP + if(current->thread.prev_sched == NULL) + panic("blech"); + schedule_tail(current->thread.prev_sched); -#endif current->thread.prev_sched = NULL; - unblock_signals(); userspace(¤t->thread.regs.regs); } @@ -136,7 +199,7 @@ int copy_thread_skas(int nr, unsigned lo void init_idle_skas(void) { - cpu_tasks[current->thread_info->cpu].pid = os_getpid(); + cpu_tasks[current_thread->cpu].pid = os_getpid(); default_idle(); } @@ -160,11 +223,11 @@ static int start_kernel_proc(void *unuse int start_uml_skas(void) { - start_userspace(); + start_userspace(0); capture_signal_stack(); + uml_idle_timer(); init_new_thread_signals(1); - idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; @@ -175,12 +238,14 @@ int start_uml_skas(void) int external_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } int thread_pid_skas(struct task_struct *task) { - return(userspace_pid); +#warning Need to look up userspace_pid by cpu + return(userspace_pid[0]); } /* --- linux-2.6.8-rc1/arch/um/kernel/skas/syscall_kern.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/kernel/skas/syscall_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ --- linux-2.6.8-rc1/arch/um/kernel/skas/syscall_user.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/arch/um/kernel/skas/syscall_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -22,7 +22,7 @@ void handle_syscall(union uml_pt_regs *r index = record_syscall_start(UPT_SYSCALL_NR(regs)); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); @@ -30,7 +30,7 @@ void handle_syscall(union uml_pt_regs *r (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } --- linux-2.6.8-rc1/arch/um/kernel/skas/sys-i386/Makefile 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/kernel/skas/sys-i386/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : --- linux-2.6.8-rc1/arch/um/kernel/skas/sys-i386/sigcontext.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/kernel/skas/sys-i386/sigcontext.c 2004-07-13 17:09:45.000000000 -0700 @@ -12,10 +12,9 @@ #include "kern_util.h" #include "user.h" #include "sigcontext.h" +#include "mode.h" -extern int userspace_pid; - -int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr) +int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr) { struct sigcontext sc, *from = from_ptr; unsigned long fpregs[FP_FRAME_SIZE]; @@ -41,13 +40,12 @@ int copy_sc_from_user_skas(union uml_pt_ regs->skas.regs[EIP] = sc.eip; regs->skas.regs[CS] = sc.cs; regs->skas.regs[EFL] = sc.eflags; - regs->skas.regs[UESP] = sc.esp_at_signal; regs->skas.regs[SS] = sc.ss; regs->skas.fault_addr = sc.cr2; regs->skas.fault_type = FAULT_WRITE(sc.err); regs->skas.trap_type = sc.trapno; - err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " "errno = %d\n", errno); @@ -57,8 +55,9 @@ int copy_sc_from_user_skas(union uml_pt_ return(0); } -int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs, - unsigned long fault_addr, int fault_type) +int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, + union uml_pt_regs *regs, unsigned long fault_addr, + int fault_type) { struct sigcontext sc, *to = to_ptr; struct _fpstate *to_fp; @@ -86,7 +85,7 @@ int copy_sc_to_user_skas(void *to_ptr, v sc.err = TO_SC_ERR(fault_type); sc.trapno = regs->skas.trap_type; - err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs); + err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs); if(err < 0){ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " "errno = %d\n", errno); --- linux-2.6.8-rc1/arch/um/kernel/skas/trap_user.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/skas/trap_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -35,14 +35,10 @@ void sig_handler_common_skas(int sig, vo errno = save_errno; } -extern int missed_ticks[]; - void user_signal(int sig, union uml_pt_regs *regs) { struct signal_info *info; - if(sig == SIGVTALRM) - missed_ticks[cpu()]++; regs->skas.is_user = 1; regs->skas.fault_addr = 0; regs->skas.fault_type = 0; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/kernel/skas/uaccess.c 2004-07-13 17:09:48.000000000 -0700 @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/kernel.h" +#include "linux/string.h" +#include "linux/fs.h" +#include "linux/highmem.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/uaccess.h" +#include "kern_util.h" + +extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, + pte_t *pte_out); + +static unsigned long maybe_map(unsigned long virt, int is_write) +{ + pte_t pte; + int err; + + void *phys = um_virt_to_phys(current, virt, &pte); + int dummy_code; + + if(IS_ERR(phys) || (is_write && !pte_write(pte))){ + err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); + if(err) + return(0); + phys = um_virt_to_phys(current, virt, NULL); + } + return((unsigned long) phys); +} + +static int do_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), void *arg) +{ + struct page *page; + int n; + + addr = maybe_map(addr, is_write); + if(addr == -1) + return(-1); + + page = phys_to_page(addr); + addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); + n = (*op)(addr, len, arg); + kunmap(page); + + return(n); +} + +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); + int remain = len, n; + + n = do_op(addr, size, is_write, op, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += size; + remain -= size; + if(remain == 0) + return(0); + + while(addr < ((addr + remain) & PAGE_MASK)){ + n = do_op(addr, PAGE_SIZE, is_write, op, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += PAGE_SIZE; + remain -= PAGE_SIZE; + } + if(remain == 0) + return(0); + + n = do_op(addr, remain, is_write, op, arg); + if(n != 0) + return(n < 0 ? remain : 0); + return(0); +} + +static int copy_chunk_from_user(unsigned long from, int len, void *arg) +{ + unsigned long *to_ptr = arg, to = *to_ptr; + + memcpy((void *) to, (void *) from, len); + *to_ptr += len; + return(0); +} + +int copy_from_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_READ, from, n) ? + buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to): + n); +} + +static int copy_chunk_to_user(unsigned long to, int len, void *arg) +{ + unsigned long *from_ptr = arg, from = *from_ptr; + + memcpy((void *) to, (void *) from, len); + *from_ptr += len; + return(0); +} + +int copy_to_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, to, n) ? + buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) : + n); +} + +static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) +{ + char **to_ptr = arg, *to = *to_ptr; + int n; + + strncpy(to, (void *) from, len); + n = strnlen(to, len); + *to_ptr += n; + + if(n < len) + return(1); + return(0); +} + +int strncpy_from_user_skas(char *dst, const char *src, int count) +{ + int n; + char *ptr = dst; + + if(segment_eq(get_fs(), KERNEL_DS)){ + strncpy(dst, src, count); + return(strnlen(dst, count)); + } + + if(!access_ok_skas(VERIFY_READ, src, 1)) + return(-EFAULT); + + n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, + &ptr); + if(n != 0) + return(-EFAULT); + return(strnlen(dst, count)); +} + +static int clear_chunk(unsigned long addr, int len, void *unused) +{ + memset((void *) addr, 0, len); + return(0); +} + +int __clear_user_skas(void *mem, int len) +{ + return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); +} + +int clear_user_skas(void *mem, int len) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memset(mem, 0, len); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, mem, len) ? + buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len); +} + +static int strnlen_chunk(unsigned long str, int len, void *arg) +{ + int *len_ptr = arg, n; + + n = strnlen((void *) str, len); + *len_ptr += n; + + if(n < len) + return(1); + return(0); +} + +int strnlen_user_skas(const void *str, int len) +{ + int count = 0, n; + + if(segment_eq(get_fs(), KERNEL_DS)) + return(strnlen(str, len) + 1); + + n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); + if(n == 0) + return(count + 1); + return(-EFAULT); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/kernel/skas/util/Makefile 2003-06-14 12:18:30.000000000 -0700 +++ 25/arch/um/kernel/skas/util/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -1,10 +1,9 @@ all: mk_ptregs mk_ptregs : mk_ptregs.o - $(CC) -o mk_ptregs mk_ptregs.o + $(HOSTCC) -o mk_ptregs mk_ptregs.o mk_ptregs.o : mk_ptregs.c - $(CC) -c $< + $(HOSTCC) -c $< -clean : - $(RM) -f mk_ptregs *.o *~ +clean-files := mk_ptregs *.o *~ --- linux-2.6.8-rc1/arch/um/kernel/skas/util/mk_ptregs.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/skas/util/mk_ptregs.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,3 +1,4 @@ +#include #include #include --- linux-2.6.8-rc1/arch/um/kernel/smp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/um/kernel/smp.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,9 +1,15 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ #include "linux/config.h" +#include "linux/percpu.h" +#include "asm/pgalloc.h" +#include "asm/tlb.h" + +/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); #ifdef CONFIG_SMP @@ -23,7 +29,7 @@ #include "os.h" /* CPU online map, set by smp_boot_cpus */ -unsigned long cpu_online_map = cpumask_of_cpu(0); +unsigned long cpu_online_map = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); @@ -55,7 +61,7 @@ struct task_struct *idle_threads[NR_CPUS void smp_send_reschedule(int cpu) { - write(cpu_data[cpu].ipi_pipe[1], "R", 1); + os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1); num_reschedules_sent++; } @@ -100,35 +106,34 @@ void smp_send_stop(void) printk(KERN_INFO "Stopping all CPUs..."); for(i = 0; i < num_online_cpus(); i++){ - if(i == current->thread_info->cpu) + if(i == current_thread->cpu) continue; - write(cpu_data[i].ipi_pipe[1], "S", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); } printk("done\n"); } -static cpumask_t smp_commenced_mask; -static cpumask_t smp_callin_map = CPU_MASK_NONE; +static cpumask_t smp_commenced_mask = CPU_MASK_NONE; +static cpumask_t cpu_callin_map = CPU_MASK_NONE; static int idle_proc(void *cpup) { int cpu = (int) cpup, err; err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); - if(err) - panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, - -err); + if(err < 0) + panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.mode.tt.extern_pid); wmb(); - if (cpu_test_and_set(cpu, &smp_callin_map)) { + if (cpu_test_and_set(cpu, cpu_callin_map)) { printk("huh, CPU#%d already present??\n", cpu); BUG(); } - while (!cpu_isset(cpu, &smp_commenced_mask)) + while (!cpu_isset(cpu, smp_commenced_mask)) cpu_relax(); cpu_set(cpu, cpu_online_map); @@ -143,16 +148,20 @@ static struct task_struct *idle_thread(i current->thread.request.u.thread.proc = idle_proc; current->thread.request.u.thread.arg = (void *) cpu; - new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL); - if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); + new_task = copy_process(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, + NULL); + if(IS_ERR(new_task)) + panic("copy_process failed in idle_thread, error = %ld", + PTR_ERR(new_task)); cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, sizeof(c)), ({ panic("skas mode doesn't support SMP"); })); + wake_up_forked_process(new_task); return(new_task); } @@ -160,15 +169,17 @@ void smp_prepare_cpus(unsigned int maxcp { struct task_struct *idle; unsigned long waittime; - int err, cpu; + int err, cpu, me = smp_processor_id(); - cpu_set(0, cpu_online_map); - cpu_set(0, smp_callin_map); + cpu_clear(me, cpu_online_map); + cpu_set(me, cpu_online_map); + cpu_set(me, cpu_callin_map); - err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); - if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); + err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); + if(err < 0) + panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[0].ipi_pipe[0], + activate_ipi(cpu_data[me].ipi_pipe[0], current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ @@ -180,10 +191,10 @@ void smp_prepare_cpus(unsigned int maxcp unhash_process(idle); waittime = 200000000; - while (waittime-- && !cpu_isset(cpu, smp_callin_map)) + while (waittime-- && !cpu_isset(cpu, cpu_callin_map)) cpu_relax(); - if (cpu_isset(cpu, smp_callin_map)) + if (cpu_isset(cpu, cpu_callin_map)) printk("done\n"); else printk("failed\n"); } @@ -216,7 +227,7 @@ void IPI_handler(int cpu) int fd; fd = cpu_data[cpu].ipi_pipe[0]; - while (read(fd, &c, 1) == 1) { + while (os_read_file(fd, &c, 1) == 1) { switch (c) { case 'C': smp_call_function_slave(cpu); @@ -276,9 +287,9 @@ int smp_call_function(void (*_func)(void info = _info; for (i=0;ithread_info->cpu) && + if((i != current_thread->cpu) && cpu_isset(i, cpu_online_map)) - write(cpu_data[i].ipi_pipe[1], "C", 1); + os_write_file(cpu_data[i].ipi_pipe[1], "C", 1); while (atomic_read(&scf_started) != cpus) barrier(); --- linux-2.6.8-rc1/arch/um/kernel/syscall_kern.c 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/um/kernel/syscall_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -36,32 +36,34 @@ long um_mount(char * dev_name, char * di long sys_fork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } -long sys_clone(unsigned long clone_flags, unsigned long newsp) +long sys_clone(unsigned long clone_flags, unsigned long newsp, + int *parent_tid, int *child_tid) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } long sys_vfork(void) { - struct task_struct *p; + long ret; current->thread.forking = 1; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL); + ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, + NULL); current->thread.forking = 0; - return(IS_ERR(p) ? PTR_ERR(p) : p->pid); + return(ret); } /* common code for old and new mmaps */ @@ -136,43 +138,12 @@ int sys_pipe(unsigned long * fildes) error = do_pipe(fd); if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) + if (copy_to_user(fildes, fd, sizeof(fd))) error = -EFAULT; } return error; } -int sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * @@ -254,7 +225,7 @@ int sys_ipc (uint call, int first, int s return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: - return -EINVAL; + return -ENOSYS; } } @@ -303,11 +274,6 @@ int sys_olduname(struct oldold_utsname * return error; } -int sys_sigaltstack(const stack_t *uss, stack_t *uoss) -{ - return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); -} - long execute_syscall(void *r) { return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); --- linux-2.6.8-rc1/arch/um/kernel/sys_call_table.c 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/um/kernel/sys_call_table.c 2004-07-13 17:09:45.000000000 -0700 @@ -5,7 +5,6 @@ #include "linux/config.h" #include "linux/unistd.h" -#include "linux/version.h" #include "linux/sys.h" #include "linux/swap.h" #include "linux/syscalls.h" @@ -14,251 +13,50 @@ #include "sysdep/syscalls.h" #include "kern_util.h" -extern syscall_handler_t sys_restart_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_exit; +#ifdef CONFIG_NFSD +#define NFSSERVCTL sys_nfsservctl +#else +#define NFSSERVCTL sys_ni_syscall +#endif + +#define LAST_GENERIC_SYSCALL __NR_vserver + +#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL +#define LAST_SYSCALL LAST_GENERIC_SYSCALL +#else +#define LAST_SYSCALL LAST_ARCH_SYSCALL +#endif + extern syscall_handler_t sys_fork; -extern syscall_handler_t sys_creat; -extern syscall_handler_t sys_link; -extern syscall_handler_t sys_unlink; -extern syscall_handler_t sys_chdir; -extern syscall_handler_t sys_mknod; -extern syscall_handler_t sys_chmod; -extern syscall_handler_t sys_lchown16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_stat; -extern syscall_handler_t sys_getpid; -extern syscall_handler_t sys_oldumount; -extern syscall_handler_t sys_setuid16; -extern syscall_handler_t sys_getuid16; +extern syscall_handler_t sys_execve; +extern syscall_handler_t um_time; +extern syscall_handler_t um_mount; +extern syscall_handler_t um_stime; extern syscall_handler_t sys_ptrace; -extern syscall_handler_t sys_alarm; -extern syscall_handler_t sys_fstat; -extern syscall_handler_t sys_pause; -extern syscall_handler_t sys_utime; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_access; -extern syscall_handler_t sys_nice; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_sync; -extern syscall_handler_t sys_kill; -extern syscall_handler_t sys_rename; -extern syscall_handler_t sys_mkdir; -extern syscall_handler_t sys_rmdir; extern syscall_handler_t sys_pipe; -extern syscall_handler_t sys_times; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_brk; -extern syscall_handler_t sys_setgid16; -extern syscall_handler_t sys_getgid16; -extern syscall_handler_t sys_signal; -extern syscall_handler_t sys_geteuid16; -extern syscall_handler_t sys_getegid16; -extern syscall_handler_t sys_acct; -extern syscall_handler_t sys_umount; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ioctl; -extern syscall_handler_t sys_fcntl; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setpgid; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_olduname; -extern syscall_handler_t sys_umask; -extern syscall_handler_t sys_chroot; -extern syscall_handler_t sys_ustat; -extern syscall_handler_t sys_dup2; -extern syscall_handler_t sys_getppid; -extern syscall_handler_t sys_getpgrp; extern syscall_handler_t sys_sigaction; -extern syscall_handler_t sys_sgetmask; -extern syscall_handler_t sys_ssetmask; -extern syscall_handler_t sys_setreuid16; -extern syscall_handler_t sys_setregid16; extern syscall_handler_t sys_sigsuspend; -extern syscall_handler_t sys_sigpending; -extern syscall_handler_t sys_sethostname; -extern syscall_handler_t sys_setrlimit; -extern syscall_handler_t sys_old_getrlimit; -extern syscall_handler_t sys_getrusage; -extern syscall_handler_t sys_gettimeofday; -extern syscall_handler_t sys_settimeofday; -extern syscall_handler_t sys_getgroups16; -extern syscall_handler_t sys_setgroups16; -extern syscall_handler_t sys_symlink; -extern syscall_handler_t sys_lstat; -extern syscall_handler_t sys_readlink; -extern syscall_handler_t sys_swapon; -extern syscall_handler_t sys_uselib; -extern syscall_handler_t sys_reboot; extern syscall_handler_t old_readdir; -extern syscall_handler_t sys_munmap; -extern syscall_handler_t sys_truncate; -extern syscall_handler_t sys_ftruncate; -extern syscall_handler_t sys_fchmod; -extern syscall_handler_t sys_fchown16; -extern syscall_handler_t sys_getpriority; -extern syscall_handler_t sys_setpriority; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_statfs; -extern syscall_handler_t sys_fstatfs; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_socketcall; -extern syscall_handler_t sys_syslog; -extern syscall_handler_t sys_setitimer; -extern syscall_handler_t sys_getitimer; -extern syscall_handler_t sys_newstat; -extern syscall_handler_t sys_newlstat; -extern syscall_handler_t sys_newfstat; extern syscall_handler_t sys_uname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_vhangup; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_swapoff; -extern syscall_handler_t sys_sysinfo; extern syscall_handler_t sys_ipc; -extern syscall_handler_t sys_fsync; extern syscall_handler_t sys_sigreturn; -extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_clone; -extern syscall_handler_t sys_setdomainname; -extern syscall_handler_t sys_newuname; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_adjtimex; -extern syscall_handler_t sys_mprotect; -extern syscall_handler_t sys_sigprocmask; -extern syscall_handler_t sys_init_module; -extern syscall_handler_t sys_delete_module; -extern syscall_handler_t sys_quotactl; -extern syscall_handler_t sys_getpgid; -extern syscall_handler_t sys_fchdir; -extern syscall_handler_t sys_bdflush; -extern syscall_handler_t sys_sysfs; -extern syscall_handler_t sys_personality; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_setfsuid16; -extern syscall_handler_t sys_setfsgid16; -extern syscall_handler_t sys_llseek; -extern syscall_handler_t sys_getdents; -extern syscall_handler_t sys_flock; -extern syscall_handler_t sys_msync; -extern syscall_handler_t sys_readv; -extern syscall_handler_t sys_writev; -extern syscall_handler_t sys_getsid; -extern syscall_handler_t sys_fdatasync; -extern syscall_handler_t sys_mlock; -extern syscall_handler_t sys_munlock; -extern syscall_handler_t sys_mlockall; -extern syscall_handler_t sys_munlockall; -extern syscall_handler_t sys_sched_setparam; -extern syscall_handler_t sys_sched_getparam; -extern syscall_handler_t sys_sched_setscheduler; -extern syscall_handler_t sys_sched_getscheduler; -extern syscall_handler_t sys_sched_get_priority_max; -extern syscall_handler_t sys_sched_get_priority_min; -extern syscall_handler_t sys_sched_rr_get_interval; -extern syscall_handler_t sys_nanosleep; -extern syscall_handler_t sys_mremap; -extern syscall_handler_t sys_setresuid16; -extern syscall_handler_t sys_getresuid16; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_poll; -extern syscall_handler_t sys_nfsservctl; -extern syscall_handler_t sys_setresgid16; -extern syscall_handler_t sys_getresgid16; -extern syscall_handler_t sys_prctl; -extern syscall_handler_t sys_ni_syscall; +extern syscall_handler_t sys_rt_sigreturn; extern syscall_handler_t sys_rt_sigaction; -extern syscall_handler_t sys_rt_sigprocmask; -extern syscall_handler_t sys_rt_sigpending; -extern syscall_handler_t sys_rt_sigtimedwait; -extern syscall_handler_t sys_rt_sigqueueinfo; -extern syscall_handler_t sys_rt_sigsuspend; -extern syscall_handler_t sys_pread64; -extern syscall_handler_t sys_pwrite64; -extern syscall_handler_t sys_chown16; -extern syscall_handler_t sys_getcwd; -extern syscall_handler_t sys_capget; -extern syscall_handler_t sys_capset; extern syscall_handler_t sys_sigaltstack; -extern syscall_handler_t sys_sendfile; -extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_vfork; -extern syscall_handler_t sys_getrlimit; extern syscall_handler_t sys_mmap2; -extern syscall_handler_t sys_truncate64; -extern syscall_handler_t sys_ftruncate64; -extern syscall_handler_t sys_stat64; -extern syscall_handler_t sys_lstat64; -extern syscall_handler_t sys_fstat64; -extern syscall_handler_t sys_lchown; -extern syscall_handler_t sys_getuid; -extern syscall_handler_t sys_getgid; -extern syscall_handler_t sys_geteuid; -extern syscall_handler_t sys_getegid; -extern syscall_handler_t sys_setreuid; -extern syscall_handler_t sys_setregid; -extern syscall_handler_t sys_getgroups; -extern syscall_handler_t sys_setgroups; -extern syscall_handler_t sys_fchown; -extern syscall_handler_t sys_setresuid; -extern syscall_handler_t sys_getresuid; -extern syscall_handler_t sys_setresgid; -extern syscall_handler_t sys_getresgid; -extern syscall_handler_t sys_chown; -extern syscall_handler_t sys_setuid; -extern syscall_handler_t sys_setgid; -extern syscall_handler_t sys_setfsuid; -extern syscall_handler_t sys_setfsgid; -extern syscall_handler_t sys_pivot_root; -extern syscall_handler_t sys_mincore; -extern syscall_handler_t sys_madvise; -extern syscall_handler_t sys_fcntl64; -extern syscall_handler_t sys_getdents64; -extern syscall_handler_t sys_gettid; -extern syscall_handler_t sys_readahead; -extern syscall_handler_t sys_tkill; -extern syscall_handler_t sys_sendfile64; -extern syscall_handler_t sys_futex; -extern syscall_handler_t sys_sched_setaffinity; -extern syscall_handler_t sys_sched_getaffinity; -extern syscall_handler_t sys_io_setup; -extern syscall_handler_t sys_io_destroy; -extern syscall_handler_t sys_io_getevents; -extern syscall_handler_t sys_io_submit; -extern syscall_handler_t sys_io_cancel; -extern syscall_handler_t sys_exit_group; -extern syscall_handler_t sys_lookup_dcookie; -extern syscall_handler_t sys_epoll_create; -extern syscall_handler_t sys_epoll_ctl; -extern syscall_handler_t sys_epoll_wait; -extern syscall_handler_t sys_remap_file_pages; -extern syscall_handler_t sys_set_tid_address; - -#ifdef CONFIG_NFSD -#define NFSSERVCTL sys_nfsservctl -#else -#define NFSSERVCTL sys_ni_syscall -#endif - -extern syscall_handler_t um_mount; -extern syscall_handler_t um_time; -extern syscall_handler_t um_stime; - -#define LAST_GENERIC_SYSCALL __NR_set_tid_address - -#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL -#define LAST_SYSCALL LAST_GENERIC_SYSCALL -#else -#define LAST_SYSCALL LAST_ARCH_SYSCALL -#endif +extern syscall_handler_t sys_timer_create; +extern syscall_handler_t old_mmap_i386; +extern syscall_handler_t old_select; +extern syscall_handler_t sys_modify_ldt; +extern syscall_handler_t sys_rt_sigsuspend; syscall_handler_t *sys_call_table[] = { - [ __NR_restart_syscall ] = sys_restart_syscall, - [ __NR_exit ] = sys_exit, - [ __NR_fork ] = sys_fork, + [ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall, + [ __NR_exit ] (syscall_handler_t *) sys_exit, + [ __NR_fork ] (syscall_handler_t *) sys_fork, [ __NR_read ] = (syscall_handler_t *) sys_read, [ __NR_write ] = (syscall_handler_t *) sys_write, @@ -266,229 +64,249 @@ syscall_handler_t *sys_call_table[] = { [ __NR_open ] = (syscall_handler_t *) sys_open, [ __NR_close ] = (syscall_handler_t *) sys_close, [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, - [ __NR_creat ] = sys_creat, - [ __NR_link ] = sys_link, - [ __NR_unlink ] = sys_unlink, + [ __NR_creat ] (syscall_handler_t *) sys_creat, + [ __NR_link ] (syscall_handler_t *) sys_link, + [ __NR_unlink ] (syscall_handler_t *) sys_unlink, [ __NR_execve ] = (syscall_handler_t *) sys_execve, /* declared differently in kern_util.h */ - [ __NR_chdir ] = sys_chdir, + [ __NR_chdir ] (syscall_handler_t *) sys_chdir, [ __NR_time ] = um_time, - [ __NR_mknod ] = sys_mknod, - [ __NR_chmod ] = sys_chmod, - [ __NR_lchown ] = sys_lchown16, - [ __NR_break ] = sys_ni_syscall, - [ __NR_oldstat ] = sys_stat, + [ __NR_mknod ] (syscall_handler_t *) sys_mknod, + [ __NR_chmod ] (syscall_handler_t *) sys_chmod, + [ __NR_lchown ] (syscall_handler_t *) sys_lchown16, + [ __NR_break ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldstat ] (syscall_handler_t *) sys_stat, [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, - [ __NR_getpid ] = sys_getpid, + [ __NR_getpid ] (syscall_handler_t *) sys_getpid, [ __NR_mount ] = um_mount, - [ __NR_umount ] = sys_oldumount, - [ __NR_setuid ] = sys_setuid16, - [ __NR_getuid ] = sys_getuid16, + [ __NR_umount ] (syscall_handler_t *) sys_oldumount, + [ __NR_setuid ] (syscall_handler_t *) sys_setuid16, + [ __NR_getuid ] (syscall_handler_t *) sys_getuid16, [ __NR_stime ] = um_stime, - [ __NR_ptrace ] = sys_ptrace, - [ __NR_alarm ] = sys_alarm, - [ __NR_oldfstat ] = sys_fstat, - [ __NR_pause ] = sys_pause, - [ __NR_utime ] = sys_utime, - [ __NR_stty ] = sys_ni_syscall, - [ __NR_gtty ] = sys_ni_syscall, - [ __NR_access ] = sys_access, - [ __NR_nice ] = sys_nice, - [ __NR_ftime ] = sys_ni_syscall, - [ __NR_sync ] = sys_sync, - [ __NR_kill ] = sys_kill, - [ __NR_rename ] = sys_rename, - [ __NR_mkdir ] = sys_mkdir, - [ __NR_rmdir ] = sys_rmdir, + [ __NR_ptrace ] (syscall_handler_t *) sys_ptrace, + [ __NR_alarm ] (syscall_handler_t *) sys_alarm, + [ __NR_oldfstat ] (syscall_handler_t *) sys_fstat, + [ __NR_pause ] (syscall_handler_t *) sys_pause, + [ __NR_utime ] (syscall_handler_t *) sys_utime, + [ __NR_stty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gtty ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_access ] (syscall_handler_t *) sys_access, + [ __NR_nice ] (syscall_handler_t *) sys_nice, + [ __NR_ftime ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_sync ] (syscall_handler_t *) sys_sync, + [ __NR_kill ] (syscall_handler_t *) sys_kill, + [ __NR_rename ] (syscall_handler_t *) sys_rename, + [ __NR_mkdir ] (syscall_handler_t *) sys_mkdir, + [ __NR_rmdir ] (syscall_handler_t *) sys_rmdir, /* Declared differently in asm/unistd.h */ [ __NR_dup ] = (syscall_handler_t *) sys_dup, - [ __NR_pipe ] = sys_pipe, - [ __NR_times ] = sys_times, - [ __NR_prof ] = sys_ni_syscall, - [ __NR_brk ] = sys_brk, - [ __NR_setgid ] = sys_setgid16, - [ __NR_getgid ] = sys_getgid16, - [ __NR_signal ] = sys_signal, - [ __NR_geteuid ] = sys_geteuid16, - [ __NR_getegid ] = sys_getegid16, - [ __NR_acct ] = sys_acct, - [ __NR_umount2 ] = sys_umount, - [ __NR_lock ] = sys_ni_syscall, - [ __NR_ioctl ] = sys_ioctl, - [ __NR_fcntl ] = sys_fcntl, - [ __NR_mpx ] = sys_ni_syscall, - [ __NR_setpgid ] = sys_setpgid, - [ __NR_ulimit ] = sys_ni_syscall, - [ __NR_oldolduname ] = sys_olduname, - [ __NR_umask ] = sys_umask, - [ __NR_chroot ] = sys_chroot, - [ __NR_ustat ] = sys_ustat, - [ __NR_dup2 ] = sys_dup2, - [ __NR_getppid ] = sys_getppid, - [ __NR_getpgrp ] = sys_getpgrp, + [ __NR_pipe ] (syscall_handler_t *) sys_pipe, + [ __NR_times ] (syscall_handler_t *) sys_times, + [ __NR_prof ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_brk ] (syscall_handler_t *) sys_brk, + [ __NR_setgid ] (syscall_handler_t *) sys_setgid16, + [ __NR_getgid ] (syscall_handler_t *) sys_getgid16, + [ __NR_signal ] (syscall_handler_t *) sys_signal, + [ __NR_geteuid ] (syscall_handler_t *) sys_geteuid16, + [ __NR_getegid ] (syscall_handler_t *) sys_getegid16, + [ __NR_acct ] (syscall_handler_t *) sys_acct, + [ __NR_umount2 ] (syscall_handler_t *) sys_umount, + [ __NR_lock ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_ioctl ] (syscall_handler_t *) sys_ioctl, + [ __NR_fcntl ] (syscall_handler_t *) sys_fcntl, + [ __NR_mpx ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setpgid ] (syscall_handler_t *) sys_setpgid, + [ __NR_ulimit ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_oldolduname ] (syscall_handler_t *) sys_olduname, + [ __NR_umask ] (syscall_handler_t *) sys_umask, + [ __NR_chroot ] (syscall_handler_t *) sys_chroot, + [ __NR_ustat ] (syscall_handler_t *) sys_ustat, + [ __NR_dup2 ] (syscall_handler_t *) sys_dup2, + [ __NR_getppid ] (syscall_handler_t *) sys_getppid, + [ __NR_getpgrp ] (syscall_handler_t *) sys_getpgrp, [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, - [ __NR_sigaction ] = sys_sigaction, - [ __NR_sgetmask ] = sys_sgetmask, - [ __NR_ssetmask ] = sys_ssetmask, - [ __NR_setreuid ] = sys_setreuid16, - [ __NR_setregid ] = sys_setregid16, - [ __NR_sigsuspend ] = sys_sigsuspend, - [ __NR_sigpending ] = sys_sigpending, - [ __NR_sethostname ] = sys_sethostname, - [ __NR_setrlimit ] = sys_setrlimit, - [ __NR_getrlimit ] = sys_old_getrlimit, - [ __NR_getrusage ] = sys_getrusage, - [ __NR_gettimeofday ] = sys_gettimeofday, - [ __NR_settimeofday ] = sys_settimeofday, - [ __NR_getgroups ] = sys_getgroups16, - [ __NR_setgroups ] = sys_setgroups16, - [ __NR_symlink ] = sys_symlink, - [ __NR_oldlstat ] = sys_lstat, - [ __NR_readlink ] = sys_readlink, - [ __NR_uselib ] = sys_uselib, + [ __NR_sigaction ] (syscall_handler_t *) sys_sigaction, + [ __NR_sgetmask ] (syscall_handler_t *) sys_sgetmask, + [ __NR_ssetmask ] (syscall_handler_t *) sys_ssetmask, + [ __NR_setreuid ] (syscall_handler_t *) sys_setreuid16, + [ __NR_setregid ] (syscall_handler_t *) sys_setregid16, + [ __NR_sigsuspend ] (syscall_handler_t *) sys_sigsuspend, + [ __NR_sigpending ] (syscall_handler_t *) sys_sigpending, + [ __NR_sethostname ] (syscall_handler_t *) sys_sethostname, + [ __NR_setrlimit ] (syscall_handler_t *) sys_setrlimit, + [ __NR_getrlimit ] (syscall_handler_t *) sys_old_getrlimit, + [ __NR_getrusage ] (syscall_handler_t *) sys_getrusage, + [ __NR_gettimeofday ] (syscall_handler_t *) sys_gettimeofday, + [ __NR_settimeofday ] (syscall_handler_t *) sys_settimeofday, + [ __NR_getgroups ] (syscall_handler_t *) sys_getgroups16, + [ __NR_setgroups ] (syscall_handler_t *) sys_setgroups16, + [ __NR_symlink ] (syscall_handler_t *) sys_symlink, + [ __NR_oldlstat ] (syscall_handler_t *) sys_lstat, + [ __NR_readlink ] (syscall_handler_t *) sys_readlink, + [ __NR_uselib ] (syscall_handler_t *) sys_uselib, [ __NR_swapon ] = (syscall_handler_t *) sys_swapon, - [ __NR_reboot ] = sys_reboot, + [ __NR_reboot ] (syscall_handler_t *) sys_reboot, [ __NR_readdir ] = old_readdir, - [ __NR_munmap ] = sys_munmap, - [ __NR_truncate ] = sys_truncate, - [ __NR_ftruncate ] = sys_ftruncate, - [ __NR_fchmod ] = sys_fchmod, - [ __NR_fchown ] = sys_fchown16, - [ __NR_getpriority ] = sys_getpriority, - [ __NR_setpriority ] = sys_setpriority, - [ __NR_profil ] = sys_ni_syscall, - [ __NR_statfs ] = sys_statfs, - [ __NR_fstatfs ] = sys_fstatfs, - [ __NR_ioperm ] = sys_ni_syscall, - [ __NR_socketcall ] = sys_socketcall, - [ __NR_syslog ] = sys_syslog, - [ __NR_setitimer ] = sys_setitimer, - [ __NR_getitimer ] = sys_getitimer, - [ __NR_stat ] = sys_newstat, - [ __NR_lstat ] = sys_newlstat, - [ __NR_fstat ] = sys_newfstat, - [ __NR_olduname ] = sys_uname, - [ __NR_iopl ] = sys_ni_syscall, - [ __NR_vhangup ] = sys_vhangup, - [ __NR_idle ] = sys_ni_syscall, + [ __NR_munmap ] (syscall_handler_t *) sys_munmap, + [ __NR_truncate ] (syscall_handler_t *) sys_truncate, + [ __NR_ftruncate ] (syscall_handler_t *) sys_ftruncate, + [ __NR_fchmod ] (syscall_handler_t *) sys_fchmod, + [ __NR_fchown ] (syscall_handler_t *) sys_fchown16, + [ __NR_getpriority ] (syscall_handler_t *) sys_getpriority, + [ __NR_setpriority ] (syscall_handler_t *) sys_setpriority, + [ __NR_profil ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_statfs ] (syscall_handler_t *) sys_statfs, + [ __NR_fstatfs ] (syscall_handler_t *) sys_fstatfs, + [ __NR_ioperm ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_socketcall ] (syscall_handler_t *) sys_socketcall, + [ __NR_syslog ] (syscall_handler_t *) sys_syslog, + [ __NR_setitimer ] (syscall_handler_t *) sys_setitimer, + [ __NR_getitimer ] (syscall_handler_t *) sys_getitimer, + [ __NR_stat ] (syscall_handler_t *) sys_newstat, + [ __NR_lstat ] (syscall_handler_t *) sys_newlstat, + [ __NR_fstat ] (syscall_handler_t *) sys_newfstat, + [ __NR_olduname ] (syscall_handler_t *) sys_uname, + [ __NR_iopl ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vhangup ] (syscall_handler_t *) sys_vhangup, + [ __NR_idle ] (syscall_handler_t *) sys_ni_syscall, [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, [ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff, - [ __NR_sysinfo ] = sys_sysinfo, - [ __NR_ipc ] = sys_ipc, - [ __NR_fsync ] = sys_fsync, - [ __NR_sigreturn ] = sys_sigreturn, - [ __NR_clone ] = sys_clone, - [ __NR_setdomainname ] = sys_setdomainname, - [ __NR_uname ] = sys_newuname, - [ __NR_adjtimex ] = sys_adjtimex, - [ __NR_mprotect ] = sys_mprotect, - [ __NR_sigprocmask ] = sys_sigprocmask, - [ __NR_create_module ] = sys_ni_syscall, - [ __NR_init_module ] = sys_init_module, - [ __NR_delete_module ] = sys_delete_module, - [ __NR_get_kernel_syms ] = sys_ni_syscall, - [ __NR_quotactl ] = sys_quotactl, - [ __NR_getpgid ] = sys_getpgid, - [ __NR_fchdir ] = sys_fchdir, - [ __NR_bdflush ] = sys_bdflush, - [ __NR_sysfs ] = sys_sysfs, - [ __NR_personality ] = sys_personality, - [ __NR_afs_syscall ] = sys_ni_syscall, - [ __NR_setfsuid ] = sys_setfsuid16, - [ __NR_setfsgid ] = sys_setfsgid16, - [ __NR__llseek ] = sys_llseek, - [ __NR_getdents ] = sys_getdents, + [ __NR_sysinfo ] (syscall_handler_t *) sys_sysinfo, + [ __NR_ipc ] (syscall_handler_t *) sys_ipc, + [ __NR_fsync ] (syscall_handler_t *) sys_fsync, + [ __NR_sigreturn ] (syscall_handler_t *) sys_sigreturn, + [ __NR_clone ] (syscall_handler_t *) sys_clone, + [ __NR_setdomainname ] (syscall_handler_t *) sys_setdomainname, + [ __NR_uname ] (syscall_handler_t *) sys_newuname, + [ __NR_adjtimex ] (syscall_handler_t *) sys_adjtimex, + [ __NR_mprotect ] (syscall_handler_t *) sys_mprotect, + [ __NR_sigprocmask ] (syscall_handler_t *) sys_sigprocmask, + [ __NR_create_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_init_module ] (syscall_handler_t *) sys_init_module, + [ __NR_delete_module ] (syscall_handler_t *) sys_delete_module, + [ __NR_get_kernel_syms ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_quotactl ] (syscall_handler_t *) sys_quotactl, + [ __NR_getpgid ] (syscall_handler_t *) sys_getpgid, + [ __NR_fchdir ] (syscall_handler_t *) sys_fchdir, + [ __NR_bdflush ] (syscall_handler_t *) sys_bdflush, + [ __NR_sysfs ] (syscall_handler_t *) sys_sysfs, + [ __NR_personality ] (syscall_handler_t *) sys_personality, + [ __NR_afs_syscall ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_setfsuid ] (syscall_handler_t *) sys_setfsuid16, + [ __NR_setfsgid ] (syscall_handler_t *) sys_setfsgid16, + [ __NR__llseek ] (syscall_handler_t *) sys_llseek, + [ __NR_getdents ] (syscall_handler_t *) sys_getdents, [ __NR__newselect ] = (syscall_handler_t *) sys_select, - [ __NR_flock ] = sys_flock, - [ __NR_msync ] = sys_msync, - [ __NR_readv ] = sys_readv, - [ __NR_writev ] = sys_writev, - [ __NR_getsid ] = sys_getsid, - [ __NR_fdatasync ] = sys_fdatasync, + [ __NR_flock ] (syscall_handler_t *) sys_flock, + [ __NR_msync ] (syscall_handler_t *) sys_msync, + [ __NR_readv ] (syscall_handler_t *) sys_readv, + [ __NR_writev ] (syscall_handler_t *) sys_writev, + [ __NR_getsid ] (syscall_handler_t *) sys_getsid, + [ __NR_fdatasync ] (syscall_handler_t *) sys_fdatasync, [ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl, - [ __NR_mlock ] = sys_mlock, - [ __NR_munlock ] = sys_munlock, - [ __NR_mlockall ] = sys_mlockall, - [ __NR_munlockall ] = sys_munlockall, - [ __NR_sched_setparam ] = sys_sched_setparam, - [ __NR_sched_getparam ] = sys_sched_getparam, - [ __NR_sched_setscheduler ] = sys_sched_setscheduler, - [ __NR_sched_getscheduler ] = sys_sched_getscheduler, + [ __NR_mlock ] (syscall_handler_t *) sys_mlock, + [ __NR_munlock ] (syscall_handler_t *) sys_munlock, + [ __NR_mlockall ] (syscall_handler_t *) sys_mlockall, + [ __NR_munlockall ] (syscall_handler_t *) sys_munlockall, + [ __NR_sched_setparam ] (syscall_handler_t *) sys_sched_setparam, + [ __NR_sched_getparam ] (syscall_handler_t *) sys_sched_getparam, + [ __NR_sched_setscheduler ] (syscall_handler_t *) sys_sched_setscheduler, + [ __NR_sched_getscheduler ] (syscall_handler_t *) sys_sched_getscheduler, [ __NR_sched_yield ] = (syscall_handler_t *) yield, - [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, - [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min, - [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval, - [ __NR_nanosleep ] = sys_nanosleep, - [ __NR_mremap ] = sys_mremap, - [ __NR_setresuid ] = sys_setresuid16, - [ __NR_getresuid ] = sys_getresuid16, - [ __NR_vm86 ] = sys_ni_syscall, - [ __NR_query_module ] = sys_ni_syscall, - [ __NR_poll ] = sys_poll, - [ __NR_nfsservctl ] = NFSSERVCTL, - [ __NR_setresgid ] = sys_setresgid16, - [ __NR_getresgid ] = sys_getresgid16, - [ __NR_prctl ] = sys_prctl, - [ __NR_rt_sigreturn ] = sys_rt_sigreturn, - [ __NR_rt_sigaction ] = sys_rt_sigaction, - [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask, - [ __NR_rt_sigpending ] = sys_rt_sigpending, - [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait, - [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo, - [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend, - [ __NR_pread64 ] = sys_pread64, - [ __NR_pwrite64 ] = sys_pwrite64, - [ __NR_chown ] = sys_chown16, - [ __NR_getcwd ] = sys_getcwd, - [ __NR_capget ] = sys_capget, - [ __NR_capset ] = sys_capset, - [ __NR_sigaltstack ] = sys_sigaltstack, - [ __NR_sendfile ] = sys_sendfile, - [ __NR_getpmsg ] = sys_ni_syscall, - [ __NR_putpmsg ] = sys_ni_syscall, - [ __NR_vfork ] = sys_vfork, - [ __NR_ugetrlimit ] = sys_getrlimit, - [ __NR_mmap2 ] = sys_mmap2, - [ __NR_truncate64 ] = sys_truncate64, - [ __NR_ftruncate64 ] = sys_ftruncate64, - [ __NR_stat64 ] = sys_stat64, - [ __NR_lstat64 ] = sys_lstat64, - [ __NR_fstat64 ] = sys_fstat64, - [ __NR_fcntl64 ] = sys_fcntl64, - [ __NR_getdents64 ] = sys_getdents64, - [ __NR_gettid ] = sys_gettid, - [ __NR_readahead ] = sys_readahead, - [ __NR_setxattr ] = sys_ni_syscall, - [ __NR_lsetxattr ] = sys_ni_syscall, - [ __NR_fsetxattr ] = sys_ni_syscall, - [ __NR_getxattr ] = sys_ni_syscall, - [ __NR_lgetxattr ] = sys_ni_syscall, - [ __NR_fgetxattr ] = sys_ni_syscall, - [ __NR_listxattr ] = sys_ni_syscall, - [ __NR_llistxattr ] = sys_ni_syscall, - [ __NR_flistxattr ] = sys_ni_syscall, - [ __NR_removexattr ] = sys_ni_syscall, - [ __NR_lremovexattr ] = sys_ni_syscall, - [ __NR_fremovexattr ] = sys_ni_syscall, - [ __NR_tkill ] = sys_tkill, - [ __NR_sendfile64 ] = sys_sendfile64, - [ __NR_futex ] = sys_futex, - [ __NR_sched_setaffinity ] = sys_sched_setaffinity, - [ __NR_sched_getaffinity ] = sys_sched_getaffinity, - [ __NR_io_setup ] = sys_io_setup, - [ __NR_io_destroy ] = sys_io_destroy, - [ __NR_io_getevents ] = sys_io_getevents, - [ __NR_io_submit ] = sys_io_submit, - [ __NR_io_cancel ] = sys_io_cancel, - [ __NR_exit_group ] = sys_exit_group, - [ __NR_lookup_dcookie ] = sys_lookup_dcookie, - [ __NR_epoll_create ] = sys_epoll_create, - [ __NR_epoll_ctl ] = sys_epoll_ctl, - [ __NR_epoll_wait ] = sys_epoll_wait, - [ __NR_remap_file_pages ] = sys_remap_file_pages, - [ __NR_set_tid_address ] = sys_set_tid_address, + [ __NR_sched_get_priority_max ] (syscall_handler_t *) sys_sched_get_priority_max, + [ __NR_sched_get_priority_min ] (syscall_handler_t *) sys_sched_get_priority_min, + [ __NR_sched_rr_get_interval ] (syscall_handler_t *) sys_sched_rr_get_interval, + [ __NR_nanosleep ] (syscall_handler_t *) sys_nanosleep, + [ __NR_mremap ] (syscall_handler_t *) sys_mremap, + [ __NR_setresuid ] (syscall_handler_t *) sys_setresuid16, + [ __NR_getresuid ] (syscall_handler_t *) sys_getresuid16, + [ __NR_vm86 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_query_module ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_poll ] (syscall_handler_t *) sys_poll, + [ __NR_nfsservctl ] = (syscall_handler_t *) NFSSERVCTL, + [ __NR_setresgid ] (syscall_handler_t *) sys_setresgid16, + [ __NR_getresgid ] (syscall_handler_t *) sys_getresgid16, + [ __NR_prctl ] (syscall_handler_t *) sys_prctl, + [ __NR_rt_sigreturn ] (syscall_handler_t *) sys_rt_sigreturn, + [ __NR_rt_sigaction ] (syscall_handler_t *) sys_rt_sigaction, + [ __NR_rt_sigprocmask ] (syscall_handler_t *) sys_rt_sigprocmask, + [ __NR_rt_sigpending ] (syscall_handler_t *) sys_rt_sigpending, + [ __NR_rt_sigtimedwait ] (syscall_handler_t *) sys_rt_sigtimedwait, + [ __NR_rt_sigqueueinfo ] (syscall_handler_t *) sys_rt_sigqueueinfo, + [ __NR_rt_sigsuspend ] (syscall_handler_t *) sys_rt_sigsuspend, + [ __NR_pread64 ] (syscall_handler_t *) sys_pread64, + [ __NR_pwrite64 ] (syscall_handler_t *) sys_pwrite64, + [ __NR_chown ] (syscall_handler_t *) sys_chown16, + [ __NR_getcwd ] (syscall_handler_t *) sys_getcwd, + [ __NR_capget ] (syscall_handler_t *) sys_capget, + [ __NR_capset ] (syscall_handler_t *) sys_capset, + [ __NR_sigaltstack ] (syscall_handler_t *) sys_sigaltstack, + [ __NR_sendfile ] (syscall_handler_t *) sys_sendfile, + [ __NR_getpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_putpmsg ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_vfork ] (syscall_handler_t *) sys_vfork, + [ __NR_ugetrlimit ] (syscall_handler_t *) sys_getrlimit, + [ __NR_mmap2 ] (syscall_handler_t *) sys_mmap2, + [ __NR_truncate64 ] (syscall_handler_t *) sys_truncate64, + [ __NR_ftruncate64 ] (syscall_handler_t *) sys_ftruncate64, + [ __NR_stat64 ] (syscall_handler_t *) sys_stat64, + [ __NR_lstat64 ] (syscall_handler_t *) sys_lstat64, + [ __NR_fstat64 ] (syscall_handler_t *) sys_fstat64, + [ __NR_getdents64 ] (syscall_handler_t *) sys_getdents64, + [ __NR_fcntl64 ] (syscall_handler_t *) sys_fcntl64, + [ 223 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_gettid ] (syscall_handler_t *) sys_gettid, + [ __NR_readahead ] (syscall_handler_t *) sys_readahead, + [ __NR_setxattr ] (syscall_handler_t *) sys_setxattr, + [ __NR_lsetxattr ] (syscall_handler_t *) sys_lsetxattr, + [ __NR_fsetxattr ] (syscall_handler_t *) sys_fsetxattr, + [ __NR_getxattr ] (syscall_handler_t *) sys_getxattr, + [ __NR_lgetxattr ] (syscall_handler_t *) sys_lgetxattr, + [ __NR_fgetxattr ] (syscall_handler_t *) sys_fgetxattr, + [ __NR_listxattr ] (syscall_handler_t *) sys_listxattr, + [ __NR_llistxattr ] (syscall_handler_t *) sys_llistxattr, + [ __NR_flistxattr ] (syscall_handler_t *) sys_flistxattr, + [ __NR_removexattr ] (syscall_handler_t *) sys_removexattr, + [ __NR_lremovexattr ] (syscall_handler_t *) sys_lremovexattr, + [ __NR_fremovexattr ] (syscall_handler_t *) sys_fremovexattr, + [ __NR_tkill ] (syscall_handler_t *) sys_tkill, + [ __NR_sendfile64 ] (syscall_handler_t *) sys_sendfile64, + [ __NR_futex ] (syscall_handler_t *) sys_futex, + [ __NR_sched_setaffinity ] (syscall_handler_t *) sys_sched_setaffinity, + [ __NR_sched_getaffinity ] (syscall_handler_t *) sys_sched_getaffinity, + [ __NR_set_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_get_thread_area ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_io_setup ] (syscall_handler_t *) sys_io_setup, + [ __NR_io_destroy ] (syscall_handler_t *) sys_io_destroy, + [ __NR_io_getevents ] (syscall_handler_t *) sys_io_getevents, + [ __NR_io_submit ] (syscall_handler_t *) sys_io_submit, + [ __NR_io_cancel ] (syscall_handler_t *) sys_io_cancel, + [ __NR_fadvise64 ] (syscall_handler_t *) sys_fadvise64, + [ 251 ] (syscall_handler_t *) sys_ni_syscall, + [ __NR_exit_group ] (syscall_handler_t *) sys_exit_group, + [ __NR_lookup_dcookie ] (syscall_handler_t *) sys_lookup_dcookie, + [ __NR_epoll_create ] (syscall_handler_t *) sys_epoll_create, + [ __NR_epoll_ctl ] (syscall_handler_t *) sys_epoll_ctl, + [ __NR_epoll_wait ] (syscall_handler_t *) sys_epoll_wait, + [ __NR_remap_file_pages ] (syscall_handler_t *) sys_remap_file_pages, + [ __NR_set_tid_address ] (syscall_handler_t *) sys_set_tid_address, + [ __NR_timer_create ] (syscall_handler_t *) sys_timer_create, + [ __NR_timer_settime ] (syscall_handler_t *) sys_timer_settime, + [ __NR_timer_gettime ] (syscall_handler_t *) sys_timer_gettime, + [ __NR_timer_getoverrun ] (syscall_handler_t *) sys_timer_getoverrun, + [ __NR_timer_delete ] (syscall_handler_t *) sys_timer_delete, + [ __NR_clock_settime ] (syscall_handler_t *) sys_clock_settime, + [ __NR_clock_gettime ] (syscall_handler_t *) sys_clock_gettime, + [ __NR_clock_getres ] (syscall_handler_t *) sys_clock_getres, + [ __NR_clock_nanosleep ] (syscall_handler_t *) sys_clock_nanosleep, + [ __NR_statfs64 ] (syscall_handler_t *) sys_statfs64, + [ __NR_fstatfs64 ] (syscall_handler_t *) sys_fstatfs64, + [ __NR_tgkill ] (syscall_handler_t *) sys_tgkill, + [ __NR_utimes ] (syscall_handler_t *) sys_utimes, + [ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64, + [ __NR_vserver ] (syscall_handler_t *) sys_ni_syscall, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = --- linux-2.6.8-rc1/arch/um/kernel/sysrq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/um/kernel/sysrq.c 2004-07-13 17:09:45.000000000 -0700 @@ -44,6 +44,11 @@ void dump_stack(void) } EXPORT_SYMBOL(dump_stack); +void show_stack(struct task_struct *task, unsigned long *sp) +{ + show_trace(sp); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- linux-2.6.8-rc1/arch/um/kernel/tempfile.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/kernel/tempfile.c 2004-07-13 17:09:45.000000000 -0700 @@ -28,6 +28,7 @@ static void __init find_tempdir(void) } if((dir == NULL) || (*dir == '\0')) dir = "/tmp"; + tempdir = malloc(strlen(dir) + 2); if(tempdir == NULL){ fprintf(stderr, "Failed to malloc tempdir, " @@ -49,7 +50,8 @@ int make_tempfile(const char *template, else *tempname = 0; strcat(tempname, template); - if((fd = mkstemp(tempname)) < 0){ + fd = mkstemp(tempname); + if(fd < 0){ fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); return -1; @@ -59,7 +61,8 @@ int make_tempfile(const char *template, return -1; } if(out_tempname){ - if((*out_tempname = strdup(tempname)) == NULL){ + *out_tempname = strdup(tempname); + if(*out_tempname == NULL){ perror("strdup"); return -1; } --- linux-2.6.8-rc1/arch/um/kernel/time.c 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/um/kernel/time.c 2004-07-13 17:09:47.000000000 -0700 @@ -4,24 +4,34 @@ */ #include +#include #include #include #include #include #include -#include "linux/module.h" +#include #include "user_util.h" #include "kern_util.h" #include "user.h" #include "process.h" #include "signal_user.h" #include "time_user.h" +#include "kern_constants.h" + +/* XXX This really needs to be declared and initialized in a kernel file since + * it's in + */ +extern struct timespec wall_to_monotonic; extern struct timeval xtime; +struct timeval local_offset = { 0, 0 }; + void timer(void) { gettimeofday(&xtime, NULL); + timeradd(&xtime, &local_offset, &xtime); } void set_interval(int timer_type) @@ -66,7 +76,7 @@ void switch_timers(int to_real) errno); } -void idle_timer(void) +void uml_idle_timer(void) { if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) panic("Couldn't unset SIGVTALRM handler"); @@ -76,14 +86,60 @@ void idle_timer(void) set_interval(ITIMER_REAL); } +static unsigned long long get_host_hz(void) +{ + char mhzline[16], *end; + unsigned long long mhz; + int ret, mult, rest, len; + + ret = cpu_feature("cpu MHz", mhzline, + sizeof(mhzline) / sizeof(mhzline[0])); + if(!ret) + panic ("Could not get host MHZ"); + + mhz = strtoul(mhzline, &end, 10); + + /* This business is to parse a floating point number without using + * floating types. + */ + + rest = 0; + mult = 0; + if(*end == '.'){ + end++; + len = strlen(end); + if(len < 6) + mult = 6 - len; + else if(len > 6) + end[6] = '\0'; + rest = strtoul(end, NULL, 10); + while(mult-- > 0) + rest *= 10; + } + + return(1000000 * mhz + rest); +} + +unsigned long long host_hz = 0; + +extern int do_posix_clock_monotonic_gettime(struct timespec *tp); + void time_init(void) { + struct timespec now; + + host_hz = get_host_hz(); if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) panic("Couldn't set SIGVTALRM handler"); set_interval(ITIMER_VIRTUAL); + + do_posix_clock_monotonic_gettime(&now); + wall_to_monotonic.tv_sec = -now.tv_sec; + wall_to_monotonic.tv_nsec = -now.tv_nsec; } -struct timeval local_offset = { 0, 0 }; +/* Declared in linux/time.h, which can't be included here */ +extern void clock_was_set(void); void do_gettimeofday(struct timeval *tv) { @@ -96,15 +152,13 @@ void do_gettimeofday(struct timeval *tv) clock_was_set(); } -EXPORT_SYMBOL(do_gettimeofday); - int do_settimeofday(struct timespec *tv) { struct timeval now; unsigned long flags; struct timeval tv_in; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC) return -EINVAL; tv_in.tv_sec = tv->tv_sec; @@ -114,9 +168,9 @@ int do_settimeofday(struct timespec *tv) gettimeofday(&now, NULL); timersub(&tv_in, &now, &local_offset); time_unlock(flags); -} -EXPORT_SYMBOL(do_settimeofday); + return(0); +} void idle_sleep(int secs) { --- linux-2.6.8-rc1/arch/um/kernel/time_kern.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/arch/um/kernel/time_kern.c 2004-07-13 17:09:47.000000000 -0700 @@ -30,22 +30,60 @@ int hz(void) return(HZ); } +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies_64 * (1000000000 / HZ); +} + /* Changed at early boot */ int timer_irq_inited = 0; -/* missed_ticks will be modified after kernel memory has been - * write-protected, so this puts it in a section which will be left - * write-enabled. - */ -int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; +static int first_tick; +static unsigned long long prev_tsc; +#ifdef CONFIG_UML_REAL_TIME_CLOCK +static long long delta; /* Deviation per interval */ +#endif + +extern unsigned long long host_hz; void timer_irq(union uml_pt_regs *regs) { - int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu]; + unsigned long long ticks = 0; + + if(!timer_irq_inited){ + /* This is to ensure that ticks don't pile up when + * the timer handler is suspended */ + first_tick = 0; + return; + } - if(!timer_irq_inited) return; - missed_ticks[cpu] = 0; - while(ticks--) do_IRQ(TIMER_IRQ, regs); + if(first_tick){ +#ifdef CONFIG_UML_REAL_TIME_CLOCK + unsigned long long tsc; + /* We've had 1 tick */ + tsc = time_stamp(); + + delta += tsc - prev_tsc; + prev_tsc = tsc; + + ticks += (delta * HZ) / host_hz; + delta -= (ticks * host_hz) / HZ; +#else + ticks = 1; +#endif + } + else { + prev_tsc = time_stamp(); + first_tick = 1; + } + + while(ticks > 0){ + do_IRQ(TIMER_IRQ, regs); + ticks--; + } } void boot_timer_handler(int sig) @@ -58,12 +96,15 @@ void boot_timer_handler(int sig) do_timer(®s); } -void um_timer(int irq, void *dev, struct pt_regs *regs) +irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs) { + unsigned long flags; + do_timer(regs); - write_seqlock(&xtime_lock); + write_seqlock_irqsave(&xtime_lock, flags); timer(); - write_sequnlock(&xtime_lock); + write_sequnlock_irqrestore(&xtime_lock, flags); + return(IRQ_HANDLED); } long um_time(int * tloc) @@ -81,12 +122,12 @@ long um_time(int * tloc) long um_stime(int * tptr) { int value; - struct timeval new; + struct timespec new; if (get_user(value, tptr)) return -EFAULT; new.tv_sec = value; - new.tv_usec = 0; + new.tv_nsec = 0; do_settimeofday(&new); return 0; } @@ -125,9 +166,11 @@ void __const_udelay(um_udelay_t usecs) void timer_handler(int sig, union uml_pt_regs *regs) { #ifdef CONFIG_SMP + local_irq_disable(); update_process_times(user_context(UPT_SP(regs))); + local_irq_enable(); #endif - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) timer_irq(regs); } @@ -136,6 +179,7 @@ static spinlock_t timer_spinlock = SPIN_ unsigned long time_lock(void) { unsigned long flags; + spin_lock_irqsave(&timer_spinlock, flags); return(flags); } @@ -150,8 +194,8 @@ int __init timer_init(void) int err; CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); - if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", - NULL)) != 0) + err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); + if(err != 0) printk(KERN_ERR "timer_init : request_irq failed - " "errno = %d\n", -err); timer_irq_inited = 1; @@ -160,7 +204,6 @@ int __init timer_init(void) __initcall(timer_init); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- linux-2.6.8-rc1/arch/um/kernel/trap_kern.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/kernel/trap_kern.c 2004-07-13 17:09:48.000000000 -0700 @@ -16,12 +16,15 @@ #include "asm/tlbflush.h" #include "asm/a.out.h" #include "asm/current.h" +#include "asm/irq.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" #include "2_5compat.h" +#include "mem.h" +#include "mem_kern.h" int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out) @@ -51,12 +54,12 @@ int handle_page_fault(unsigned long addr if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; page = address & PAGE_MASK; - if(page == (unsigned long) current->thread_info + PAGE_SIZE) + if(address < (unsigned long) current_thread + 1024 && !is_user) panic("Kernel stack overflow"); pgd = pgd_offset(mm, page); pmd = pmd_offset(pgd, page); - survive: do { + survive: switch (handle_mm_fault(mm, vma, address, is_write)){ case VM_FAULT_MINOR: current->min_flt++; @@ -75,10 +78,10 @@ int handle_page_fault(unsigned long addr } pte = pte_offset_kernel(pmd, page); } while(!pte_present(*pte)); + err = 0; *pte = pte_mkyoung(*pte); if(pte_write(*pte)) *pte = pte_mkdirty(*pte); flush_tlb_page(vma, page); - err = 0; out: up_read(&mm->mmap_sem); return(err); @@ -94,10 +97,36 @@ out_of_memory: down_read(&mm->mmap_sem); goto survive; } - err = -ENOMEM; goto out; } +LIST_HEAD(physmem_remappers); + +void register_remapper(struct remapper *info) +{ + list_add(&info->list, &physmem_remappers); +} + +static int check_remapped_addr(unsigned long address, int is_write) +{ + struct remapper *remapper; + struct list_head *ele; + __u64 offset; + int fd; + + fd = phys_mapping(__pa(address), &offset); + if(fd == -1) + return(0); + + list_for_each(ele, &physmem_remappers){ + remapper = list_entry(ele, struct remapper, list); + if((*remapper->proc)(fd, address, is_write, offset)) + return(1); + } + + return(0); +} + unsigned long segv(unsigned long address, unsigned long ip, int is_write, int is_user, void *sc) { @@ -109,7 +138,9 @@ unsigned long segv(unsigned long address flush_tlb_kernel_vm(); return(0); } - if(current->mm == NULL) + else if(check_remapped_addr(address & PAGE_MASK, is_write)) + return(0); + else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); @@ -120,9 +151,8 @@ unsigned long segv(unsigned long address current->thread.fault_addr = (void *) address; do_longjmp(catcher, 1); } - else if(current->thread.fault_addr != NULL){ + else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); - } else if(arch_fixup(ip, sc)) return(0); @@ -155,8 +185,6 @@ void bad_segv(unsigned long address, uns { struct siginfo si; - printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx " - "(ip 0x%lx)\n", current->comm, current->pid, address, ip); si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; si.si_addr = (void *) address; @@ -180,6 +208,11 @@ void bus_handler(int sig, union uml_pt_r else relay_signal(sig, regs); } +void winch(int sig, union uml_pt_regs *regs) +{ + do_IRQ(WINCH_IRQ, regs); +} + void trap_init(void) { } --- linux-2.6.8-rc1/arch/um/kernel/trap_user.c 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/um/kernel/trap_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -5,11 +5,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -34,7 +32,14 @@ void kill_child_dead(int pid) { kill(pid, SIGKILL); kill(pid, SIGCONT); - while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); } /* Unlocked - don't care if this is a bit off */ @@ -82,6 +87,8 @@ struct signal_info sig_info[] = { .is_irq = 0 }, [ SIGILL ] { .handler = relay_signal, .is_irq = 0 }, + [ SIGWINCH ] { .handler = winch, + .is_irq = 1 }, [ SIGBUS ] { .handler = bus_handler, .is_irq = 0 }, [ SIGSEGV] { .handler = segv_handler, @@ -102,12 +109,11 @@ void sig_handler(int sig, struct sigcont sig, &sc); } -extern int timer_irq_inited, missed_ticks[]; +extern int timer_irq_inited; void alarm_handler(int sig, struct sigcontext sc) { if(!timer_irq_inited) return; - missed_ticks[cpu()]++; if(sig == SIGALRM) switch_timers(0); @@ -123,7 +129,7 @@ void do_longjmp(void *b, int val) { jmp_buf *buf = b; - longjmp(*buf, val); + siglongjmp(*buf, val); } /* --- linux-2.6.8-rc1/arch/um/kernel/tt/exec_kern.c 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/kernel/tt/exec_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -17,6 +17,7 @@ #include "mem_user.h" #include "os.h" #include "tlb.h" +#include "mode.h" static int exec_tramp(void *sig_stack) { @@ -47,17 +48,17 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - if(current->thread_info->cpu == 0) + if(current_thread->cpu == 0) forward_interrupts(new_pid); current->thread.request.op = OP_EXEC; current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current->thread_info); + unprotect_stack((unsigned long) current_thread); os_usr1_process(os_getpid()); enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); + task_protections((unsigned long) current_thread); force_flush_all(); unblock_signals(); } --- linux-2.6.8-rc1/arch/um/kernel/tt/exec_user.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/arch/um/kernel/tt/exec_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -19,13 +19,18 @@ void do_exec(int old_pid, int new_pid) { unsigned long regs[FRAME_SIZE]; + int err; if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || - (waitpid(new_pid, 0, WUNTRACED) < 0)) + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) tracer_panic("do_exec failed to attach proc - errno = %d", errno); + CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); + if (err < 0) + tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", + errno); + if(ptrace_getregs(old_pid, regs) < 0) tracer_panic("do_exec failed to get registers - errno = %d", errno); --- linux-2.6.8-rc1/arch/um/kernel/tt/include/mode.h 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/kernel/tt/include/mode.h 2004-07-13 17:09:45.000000000 -0700 @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; + extern int tracing_pid; extern int tracer(int (*init_proc)(void *), void *sp); --- linux-2.6.8-rc1/arch/um/kernel/tt/include/uaccess.h 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/kernel/tt/include/uaccess.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -43,65 +43,19 @@ extern unsigned long get_fault_addr(void extern int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher); - -static inline int copy_from_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - -static inline int copy_to_user_tt(void *to, const void *from, int n) -{ - return(access_ok_tt(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, void **fault_addr, void **fault_catcher); - -static inline int strncpy_from_user_tt(char *dst, const char *src, int count) -{ - int n; - - if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - extern int __do_clear_user(void *mem, size_t len, void **fault_addr, void **fault_catcher); - -static inline int __clear_user_tt(void *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user_tt(void *mem, int len) -{ - return(access_ok_tt(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); -} - extern int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher); -static inline int strnlen_user_tt(const void *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} +extern int copy_from_user_tt(void *to, const void *from, int n); +extern int copy_to_user_tt(void *to, const void *from, int n); +extern int strncpy_from_user_tt(char *dst, const char *src, int count); +extern int __clear_user_tt(void *mem, int len); +extern int clear_user_tt(void *mem, int len); +extern int strnlen_user_tt(const void *str, int len); #endif --- linux-2.6.8-rc1/arch/um/kernel/tt/Makefile 2003-06-14 12:18:22.000000000 -0700 +++ 25/arch/um/kernel/tt/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ # -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) # Licensed under the GPL # @@ -7,7 +7,7 @@ extra-y := unmap_fin.o obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ - uaccess_user.o sys-$(SUBARCH)/ + uaccess.o uaccess_user.o sys-$(SUBARCH)/ obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ @@ -27,5 +27,3 @@ $(obj)/unmap.o: $(src)/unmap.c $(obj)/unmap_fin.o : $(src)/unmap.o ld -r -o $@ $< -lc -L/usr/lib - -clean : --- linux-2.6.8-rc1/arch/um/kernel/tt/mem_user.c 2003-06-14 12:18:05.000000000 -0700 +++ 25/arch/um/kernel/tt/mem_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -25,14 +25,13 @@ void remap_data(void *segment_start, voi size = (unsigned long) segment_end - (unsigned long) segment_start; data = create_mem_file(size); - if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, - MAP_SHARED, data, 0)) == MAP_FAILED){ + addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); + if(addr == MAP_FAILED){ perror("mapping new data segment"); exit(1); } memcpy(addr, segment_start, size); - if(switcheroo(data, prot, addr, segment_start, - size) < 0){ + if(switcheroo(data, prot, addr, segment_start, size) < 0){ printf("switcheroo failed\n"); exit(1); } --- linux-2.6.8-rc1/arch/um/kernel/tt/process_kern.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/arch/um/kernel/tt/process_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -62,7 +62,7 @@ void *switch_to_tt(void *prev, void *nex reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) - panic("write of switch_pipe failed, errno = %d", -err); + panic("write of switch_pipe failed, err = %d", -err); reading = 1; if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) @@ -104,48 +104,72 @@ void *switch_to_tt(void *prev, void *nex void release_thread_tt(struct task_struct *task) { - os_kill_process(task->thread.mode.tt.extern_pid, 0); + int pid = task->thread.mode.tt.extern_pid; + + if(os_getpid() != pid) + os_kill_process(pid, 0); } void exit_thread_tt(void) { - close(current->thread.mode.tt.switch_pipe[0]); - close(current->thread.mode.tt.switch_pipe[1]); + os_close_file(current->thread.mode.tt.switch_pipe[0]); + os_close_file(current->thread.mode.tt.switch_pipe[1]); } void schedule_tail(task_t *prev); static void new_thread_handler(int sig) { + unsigned long disable; int (*fn)(void *); void *arg; fn = current->thread.request.u.thread.proc; arg = current->thread.request.u.thread.arg; + UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); + disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | + (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); + SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); - block_signals(); + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + init_new_thread_signals(1); -#ifdef CONFIG_SMP - schedule_tail(current->thread.prev_sched); -#endif enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); - force_flush_all(); - current->thread.prev_sched = NULL; change_sig(SIGUSR1, 1); change_sig(SIGVTALRM, 1); change_sig(SIGPROF, 1); - unblock_signals(); + local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) do_exit(0); } static int new_thread_proc(void *stack) { + /* local_irq_disable is needed to block out signals until this thread is + * properly scheduled. Otherwise, the tracing thread will get mighty + * upset about any signals that arrive before that. + * This has the complication that it sets the saved signal mask in + * the sigcontext to block signals. This gets restored when this + * thread (or a descendant, since they get a copy of this sigcontext) + * returns to userspace. + * So, this is compensated for elsewhere. + * XXX There is still a small window until local_irq_disable() actually + * finishes where signals are possible - shouldn't be a problem in + * practice since SIGIO hasn't been forwarded here yet, and the + * local_irq_disable should finish before a SIGVTALRM has time to be + * delivered. + */ + + local_irq_disable(); init_new_thread_stack(stack, new_thread_handler); os_usr1_process(os_getpid()); return(0); @@ -156,7 +180,7 @@ static int new_thread_proc(void *stack) * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, * so it is blocked before it's called. They are re-enabled on sigreturn * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's signcontext, including the signal mask + * copy_thread copies the parent's sigcontext, including the signal mask * onto the signal frame. */ @@ -165,35 +189,32 @@ void finish_fork_handler(int sig) UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif + force_flush_all(); + if(current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + enable_timer(); change_sig(SIGVTALRM, 1); local_irq_enable(); - force_flush_all(); if(current->mm != current->parent->mm) protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - - current->thread.prev_sched = NULL; + task_protections((unsigned long) current_thread); free_page(current->thread.temp_stack); + local_irq_disable(); change_sig(SIGUSR1, 0); set_user_mode(current); } -static int sigusr1 = SIGUSR1; - int fork_tramp(void *stack) { - int sig = sigusr1; - local_irq_disable(); + arch_init_thread(); init_new_thread_stack(stack, finish_fork_handler); - kill(os_getpid(), sig); + os_usr1_process(os_getpid()); return(0); } @@ -213,8 +234,8 @@ int copy_thread_tt(int nr, unsigned long } err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); - if(err){ - printk("copy_thread : pipe failed, errno = %d\n", -err); + if(err < 0){ + printk("copy_thread : pipe failed, err = %d\n", -err); return(err); } @@ -377,8 +398,8 @@ static void mprotect_kernel_mem(int w) pages = (1 << CONFIG_KERNEL_STACK_ORDER); - start = (unsigned long) current->thread_info + PAGE_SIZE; - end = (unsigned long) current + PAGE_SIZE * pages; + start = (unsigned long) current_thread + PAGE_SIZE; + end = (unsigned long) current_thread + PAGE_SIZE * pages; protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); protect_memory(end, high_physmem - end, 1, w, 1, 1); @@ -454,8 +475,9 @@ void set_init_pid(int pid) init_task.thread.mode.tt.extern_pid = pid; err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); - if(err) panic("Can't create switch pipe for init_task, errno = %d", - err); + if(err) + panic("Can't create switch pipe for init_task, errno = %d", + -err); } int singlestepping_tt(void *t) --- linux-2.6.8-rc1/arch/um/kernel/tt/ptproxy/Makefile 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/tt/ptproxy/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -9,5 +9,3 @@ USER_OBJS := $(foreach file,$(obj-y),$(s $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean: --- linux-2.6.8-rc1/arch/um/kernel/tt/ptproxy/proxy.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/kernel/tt/ptproxy/proxy.c 2004-07-13 17:09:48.000000000 -0700 @@ -15,7 +15,6 @@ Jeff Dike (jdike@karaya.com) : Modified #include #include #include -#include #include #include #include @@ -273,7 +272,7 @@ void fake_child_exit(void) child_proxy(1, W_EXITCODE(0, 0)); while(debugger.waiting == 1){ - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); @@ -281,7 +280,7 @@ void fake_child_exit(void) } debugger_proxy(status, debugger.pid); } - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); @@ -293,10 +292,10 @@ void fake_child_exit(void) } char gdb_init_string[] = -"att 1 -b panic -b stop -handle SIGWINCH nostop noprint pass +"att 1 \n\ +b panic \n\ +b stop \n\ +handle SIGWINCH nostop noprint pass \n\ "; int start_debugger(char *prog, int startup, int stop, int *fd_out) @@ -304,7 +303,8 @@ int start_debugger(char *prog, int start int slave, child; slave = open_gdb_chan(); - if((child = fork()) == 0){ + child = fork(); + if(child == 0){ char *tempname = NULL; int fd; @@ -327,18 +327,19 @@ int start_debugger(char *prog, int start exit(1); #endif } - if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){ - printk("start_debugger : make_tempfile failed, errno = %d\n", - errno); + fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); + if(fd < 0){ + printk("start_debugger : make_tempfile failed," + "err = %d\n", -fd); exit(1); } - write(fd, gdb_init_string, sizeof(gdb_init_string) - 1); + os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); if(startup){ if(stop){ - write(fd, "b start_kernel\n", + os_write_file(fd, "b start_kernel\n", strlen("b start_kernel\n")); } - write(fd, "c\n", strlen("c\n")); + os_write_file(fd, "c\n", strlen("c\n")); } if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ printk("start_debugger : PTRACE_TRACEME failed, " --- linux-2.6.8-rc1/arch/um/kernel/tt/ptproxy/sysdep.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/kernel/tt/ptproxy/sysdep.c 2004-07-13 17:09:45.000000000 -0700 @@ -9,6 +9,7 @@ terms and conditions. #include #include #include +#include #include #include #include --- linux-2.6.8-rc1/arch/um/kernel/tt/ptproxy/wait.c 2003-06-14 12:18:32.000000000 -0700 +++ 25/arch/um/kernel/tt/ptproxy/wait.c 2004-07-13 17:09:45.000000000 -0700 @@ -56,21 +56,23 @@ int parent_wait_return(struct debugger * int real_wait_return(struct debugger *debugger) { unsigned long ip; - int err, pid; + int pid; pid = debugger->pid; + ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); - ip = IP_RESTART_SYSCALL(ip); - err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip); + IP_RESTART_SYSCALL(ip); + if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) tracer_panic("real_wait_return : Failed to restart system " - "call, errno = %d\n"); + "call, errno = %d\n", errno); + if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || debugger_normal_return(debugger, -1)) tracer_panic("real_wait_return : gdb failed to wait, " - "errno = %d\n"); + "errno = %d\n", errno); return(0); } --- linux-2.6.8-rc1/arch/um/kernel/tt/syscall_kern.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/kernel/tt/syscall_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ --- linux-2.6.8-rc1/arch/um/kernel/tt/syscall_user.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/kernel/tt/syscall_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -33,7 +33,7 @@ void syscall_handler_tt(int sig, union u SC_START_SYSCALL(sc); index = record_syscall_start(syscall); - syscall_trace(); + syscall_trace(regs, 1); result = execute_syscall(regs); /* regs->sc may have changed while the system call ran (there may @@ -46,7 +46,7 @@ void syscall_handler_tt(int sig, union u (result == -ERESTARTNOINTR)) do_signal(result); - syscall_trace(); + syscall_trace(regs, 0); record_syscall_end(index, result); } --- linux-2.6.8-rc1/arch/um/kernel/tt/sys-i386/Makefile 2003-06-14 12:18:08.000000000 -0700 +++ 25/arch/um/kernel/tt/sys-i386/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -10,5 +10,3 @@ USER_OBJS := $(foreach file,$(USER_OBJS) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : --- linux-2.6.8-rc1/arch/um/kernel/tt/tlb.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/kernel/tt/tlb.c 2004-07-13 17:09:45.000000000 -0700 @@ -10,6 +10,7 @@ #include "asm/page.h" #include "asm/pgtable.h" #include "asm/uaccess.h" +#include "asm/tlbflush.h" #include "user_util.h" #include "mem_user.h" #include "os.h" --- linux-2.6.8-rc1/arch/um/kernel/tt/tracer.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/kernel/tt/tracer.c 2004-07-13 17:09:48.000000000 -0700 @@ -39,16 +39,17 @@ int is_tracer_winch(int pid, int fd, voi return(0); register_winch_irq(tracer_winch[0], fd, -1, data); - return(0); + return(1); } static void tracer_winch_handler(int sig) { + int n; char c = 1; - if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) - printk("tracer_winch_handler - write failed, errno = %d\n", - errno); + n = os_write_file(tracer_winch[1], &c, sizeof(c)); + if(n != sizeof(c)) + printk("tracer_winch_handler - write failed, err = %d\n", -n); } /* Called only by the tracing thread during initialization */ @@ -58,9 +59,8 @@ static void setup_tracer_winch(void) int err; err = os_pipe(tracer_winch, 1, 1); - if(err){ - printk("setup_tracer_winch : os_pipe failed, errno = %d\n", - -err); + if(err < 0){ + printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); return; } signal(SIGWINCH, tracer_winch_handler); @@ -130,8 +130,8 @@ static void sleeping_process_signal(int case SIGTSTP: if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, errno = %d\n", pid, - sig); + "continue pid %d, signal = %d, " + "errno = %d\n", pid, sig, errno); break; /* This happens when the debugger (e.g. strace) is doing system call @@ -145,7 +145,7 @@ static void sleeping_process_signal(int if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) tracer_panic("sleeping_process_signal : Failed to " "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, sig); + pid, errno); break; case SIGSTOP: break; @@ -192,7 +192,7 @@ int tracer(int (*init_proc)(void *), voi printf("tracing thread pid = %d\n", tracing_pid); pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("waitpid on idle thread failed, errno = %d\n", errno); exit(1); @@ -218,7 +218,7 @@ int tracer(int (*init_proc)(void *), voi err = attach(debugger_parent); if(err){ printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, err); + "errno = %d\n", debugger_parent, -err); debugger_parent = -1; } else { @@ -233,7 +233,8 @@ int tracer(int (*init_proc)(void *), voi } set_cmdline("(tracing thread)"); while(1){ - if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); + if(pid <= 0){ if(errno != ECHILD){ printf("wait failed - errno = %d\n", errno); } @@ -401,7 +402,7 @@ static int __init uml_debug_setup(char * if(!strcmp(line, "go")) debug_stop = 0; else if(!strcmp(line, "parent")) debug_parent = 1; - else printk("Unknown debug option : '%s'\n", line); + else printf("Unknown debug option : '%s'\n", line); line = next; } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/kernel/tt/uaccess.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "asm/uaccess.h" + +int copy_from_user_tt(void *to, const void *from, int n) +{ + if(!access_ok_tt(VERIFY_READ, from, n)) + return(n); + + return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int copy_to_user_tt(void *to, const void *from, int n) +{ + if(!access_ok_tt(VERIFY_WRITE, to, n)) + return(n); + + return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int strncpy_from_user_tt(char *dst, const char *src, int count) +{ + int n; + + if(!access_ok_tt(VERIFY_READ, src, 1)) + return(-EFAULT); + + n = __do_strncpy_from_user(dst, src, count, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher); + if(n < 0) return(-EFAULT); + return(n); +} + +int __clear_user_tt(void *mem, int len) +{ + return(__do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int clear_user_tt(void *mem, int len) +{ + if(!access_ok_tt(VERIFY_WRITE, mem, len)) + return(len); + + return(__do_clear_user(mem, len, ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +int strnlen_user_tt(const void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/kernel/tt/uaccess_user.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/arch/um/kernel/tt/uaccess_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -8,15 +8,20 @@ #include #include "user_util.h" #include "uml_uaccess.h" +#include "task.h" +#include "kern_util.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, __do_copy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(n - (fault - (unsigned long) from)); } @@ -29,11 +34,14 @@ static void __do_strncpy(void *dst, cons int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, __do_strncpy, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(strlen(dst)); else return(-1); } @@ -46,11 +54,14 @@ static void __do_clear(void *to, const v int __do_clear_user(void *mem, unsigned long len, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; unsigned long fault; int faulted; fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, __do_clear, &faulted); + TASK_REGS(get_current())->tt = save; + if(!faulted) return(0); else return(len - (fault - (unsigned long) mem)); } @@ -58,19 +69,20 @@ int __do_clear_user(void *mem, unsigned int __do_strnlen_user(const char *str, unsigned long n, void **fault_addr, void **fault_catcher) { + struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0) ret = strlen(str) + 1; - } - else { - ret = *faddrp - (unsigned long) str; - } + else ret = *faddrp - (unsigned long) str; + *fault_addr = NULL; *fault_catcher = NULL; + + TASK_REGS(get_current())->tt = save; return ret; } --- linux-2.6.8-rc1/arch/um/kernel/tt/unmap.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/kernel/tt/unmap.c 2004-07-13 17:09:45.000000000 -0700 @@ -3,10 +3,7 @@ * Licensed under the GPL */ -#include -#include #include -#include "user.h" int switcheroo(int fd, int prot, void *from, void *to, int size) { --- linux-2.6.8-rc1/arch/um/kernel/tty_log.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/arch/um/kernel/tty_log.c 2004-07-13 17:09:45.000000000 -0700 @@ -9,10 +9,10 @@ #include #include #include -#include #include #include "init.h" #include "user.h" +#include "kern_util.h" #include "os.h" #define TTY_LOG_DIR "./" @@ -24,29 +24,40 @@ static int tty_log_fd = -1; #define TTY_LOG_OPEN 1 #define TTY_LOG_CLOSE 2 #define TTY_LOG_WRITE 3 +#define TTY_LOG_EXEC 4 + +#define TTY_READ 1 +#define TTY_WRITE 2 struct tty_log_buf { int what; unsigned long tty; int len; + int direction; + unsigned long sec; + unsigned long usec; }; -int open_tty_log(void *tty) +int open_tty_log(void *tty, void *current_tty) { struct timeval tv; struct tty_log_buf data; char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; int fd; + gettimeofday(&tv, NULL); if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_OPEN, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, + .tty = (unsigned long) tty, + .len = sizeof(current_tty), + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + os_write_file(tty_log_fd, ¤t_tty, data.len); return(tty_log_fd); } - gettimeofday(&tv, NULL); sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec); @@ -62,30 +73,117 @@ int open_tty_log(void *tty) void close_tty_log(int fd, void *tty) { struct tty_log_buf data; + struct timeval tv; if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { what : TTY_LOG_CLOSE, - tty : (unsigned long) tty, - len : 0 }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, + .tty = (unsigned long) tty, + .len = 0, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); return; } - close(fd); + os_close_file(fd); } -int write_tty_log(int fd, char *buf, int len, void *tty) +static int log_chunk(int fd, const char *buf, int len) { + int total = 0, try, missed, n; + char chunk[64]; + + while(len > 0){ + try = (len > sizeof(chunk)) ? sizeof(chunk) : len; + missed = copy_from_user_proc(chunk, (char *) buf, try); + try -= missed; + n = os_write_file(fd, chunk, try); + if(n != try) { + if(n < 0) + return(n); + return(-EIO); + } + if(missed != 0) + return(-EFAULT); + + len -= try; + total += try; + buf += try; + } + + return(total); +} + +int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) +{ + struct timeval tv; struct tty_log_buf data; + int direction; if(fd == tty_log_fd){ - data = ((struct tty_log_buf) { what : TTY_LOG_WRITE, - tty : (unsigned long) tty, - len : len }); - write(tty_log_fd, &data, sizeof(data)); + gettimeofday(&tv, NULL); + direction = is_read ? TTY_READ : TTY_WRITE; + data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, + .tty = (unsigned long) tty, + .len = len, + .direction = direction, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + } + + return(log_chunk(fd, buf, len)); +} + +void log_exec(char **argv, void *tty) +{ + struct timeval tv; + struct tty_log_buf data; + char **ptr,*arg; + int len; + + if(tty_log_fd == -1) return; + + gettimeofday(&tv, NULL); + + len = 0; + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + len += strlen_user_proc(arg); + } + + data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, + .tty = (unsigned long) tty, + .len = len, + .direction = 0, + .sec = tv.tv_sec, + .usec = tv.tv_usec } ); + os_write_file(tty_log_fd, &data, sizeof(data)); + + for(ptr = argv; ; ptr++){ + if(copy_from_user_proc(&arg, ptr, sizeof(arg))) + return; + if(arg == NULL) break; + log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); } - return(write(fd, buf, len)); } +extern void register_tty_logger(int (*opener)(void *, void *), + int (*writer)(int, const char *, int, + void *, int), + void (*closer)(int, void *)); + +static int register_logger(void) +{ + register_tty_logger(open_tty_log, write_tty_log, close_tty_log); + return(0); +} + +__uml_initcall(register_logger); + static int __init set_tty_log_dir(char *name, int *add) { tty_log_dir = name; @@ -104,7 +202,7 @@ static int __init set_tty_log_fd(char *n tty_log_fd = strtoul(name, &end, 0); if((*end != '\0') || (end == name)){ - printk("set_tty_log_fd - strtoul failed on '%s'\n", name); + printf("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } return 0; --- linux-2.6.8-rc1/arch/um/kernel/uaccess_user.c 2003-06-14 12:18:28.000000000 -0700 +++ 25/arch/um/kernel/uaccess_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -20,7 +20,7 @@ unsigned long __do_user_copy(void *to, c jmp_buf jbuf; *fault_catcher = &jbuf; - if(setjmp(jbuf) == 0){ + if(sigsetjmp(jbuf, 1) == 0){ (*op)(to, from, n); ret = 0; *faulted_out = 0; --- linux-2.6.8-rc1/arch/um/kernel/um_arch.c 2004-02-17 20:48:42.000000000 -0800 +++ 25/arch/um/kernel/um_arch.c 2004-07-13 17:09:45.000000000 -0700 @@ -38,13 +38,18 @@ #include "mode_kern.h" #include "mode.h" -#define DEFAULT_COMMAND_LINE "root=6200" +#define DEFAULT_COMMAND_LINE "root=98:0" struct cpuinfo_um boot_cpu_data = { .loops_per_jiffy = 0, .ipi_pipe = { -1, -1 } }; +/* Placeholder to make UML link until the vsyscall stuff is actually + * implemented + */ +void *__kernel_vsyscall; + unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, @@ -53,18 +58,22 @@ unsigned long thread_saved_pc(struct tas static int show_cpuinfo(struct seq_file *m, void *v) { - int index; + int index = 0; - index = (struct cpuinfo_um *)v - cpu_data; #ifdef CONFIG_SMP + index = (struct cpuinfo_um *) v - cpu_data; if (!cpu_online(index)) return 0; #endif - seq_printf(m, "bogomips\t: %lu.%02lu\n", + seq_printf(m, "processor\t: %d\n", index); + seq_printf(m, "vendor_id\t: User Mode Linux\n"); + seq_printf(m, "model name\t: UML\n"); + seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); + seq_printf(m, "host\t\t: %s\n", host_info); + seq_printf(m, "bogomips\t: %lu.%02lu\n\n", loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100); - seq_printf(m, "host\t\t: %s\n", host_info); return(0); } @@ -134,12 +143,12 @@ void set_cmdline(char *cmd) if(umid != NULL){ snprintf(argv1_begin, (argv1_end - argv1_begin) * sizeof(*ptr), - "(%s)", umid); + "(%s) ", umid); ptr = &argv1_begin[strlen(argv1_begin)]; } else ptr = argv1_begin; - snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd); + snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); memset(argv1_begin + strlen(argv1_begin), '\0', argv1_end - argv1_begin - strlen(argv1_begin)); #endif @@ -179,7 +188,7 @@ __uml_setup("root=", uml_root_setup, static int __init uml_ncpus_setup(char *line, int *add) { if (!sscanf(line, "%d", &ncpus)) { - printk("Couldn't parse [%s]\n", line); + printf("Couldn't parse [%s]\n", line); return -1; } @@ -210,7 +219,7 @@ static int __init mode_tt_setup(char *li static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); + printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); return(0); } @@ -221,7 +230,7 @@ static int __init mode_tt_setup(char *li static int __init mode_tt_setup(char *line, int *add) { - printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); + printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); return(0); } @@ -291,7 +300,7 @@ static void __init uml_postsetup(void) /* Set during early boot */ unsigned long brk_start; -static struct vm_reserved kernel_vm_reserved; +unsigned long end_iomem; #define MIN_VMALLOC (32 * 1024 * 1024) @@ -299,7 +308,7 @@ int linux_main(int argc, char **argv) { unsigned long avail; unsigned long virtmem_size, max_physmem; - unsigned int i, add, err; + unsigned int i, add; for (i = 1; i < argc; i++){ if((i == 1) && (argv[i][0] == ' ')) continue; @@ -328,12 +337,16 @@ int linux_main(int argc, char **argv) argv1_end = &argv[1][strlen(argv[1])]; #endif - set_usable_vm(uml_physmem, get_kmem_end()); - highmem = 0; - max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC; - if(physmem_size > max_physmem){ - highmem = physmem_size - max_physmem; + iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + + /* Zones have to begin on a 1 << MAX_ORDER page boundary, + * so this makes sure that's true for highmem + */ + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + if(physmem_size + iomem_size > max_physmem){ + highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; @@ -343,11 +356,19 @@ int linux_main(int argc, char **argv) } high_physmem = uml_physmem + physmem_size; - high_memory = (void *) high_physmem; + end_iomem = high_physmem + iomem_size; + high_memory = (void *) end_iomem; start_vm = VMALLOC_START; - setup_physmem(uml_physmem, uml_reserved, physmem_size); + setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); + if(init_maps(physmem_size, iomem_size, highmem)){ + printf("Failed to allocate mem_map for %ld bytes of physical " + "memory and %ld bytes of highmem\n", physmem_size, + highmem); + exit(1); + } + virtmem_size = physmem_size; avail = get_kmem_end() - start_vm; if(physmem_size > avail) virtmem_size = avail; @@ -357,28 +378,26 @@ int linux_main(int argc, char **argv) printf("Kernel virtual memory size shrunk to %ld bytes\n", virtmem_size); - err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err){ - printf("Failed to reserve VM area for kernel VM\n"); - exit(1); - } - uml_postsetup(); init_task.thread.kernel_stack = (unsigned long) &init_thread_info + 2 * PAGE_SIZE; task_protections((unsigned long) &init_thread_info); + os_flush_stdout(); return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); } +extern int uml_exitcode; + static int panic_exit(struct notifier_block *self, unsigned long unused1, void *unused2) { #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('p', ¤t->thread.regs, NULL, NULL); + handle_sysrq('p', ¤t->thread.regs, NULL); #endif + uml_exitcode = 1; machine_halt(); return(0); } @@ -403,6 +422,11 @@ void __init check_bugs(void) arch_check_bugs(); check_ptrace(); check_sigio(); + check_devanon(); +} + +void apply_alternatives(void *start, void *end) +{ } /* --- linux-2.6.8-rc1/arch/um/kernel/umid.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/arch/um/kernel/umid.c 2004-07-13 17:09:45.000000000 -0700 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -33,18 +32,19 @@ static char *uml_dir = UML_DIR; static int umid_is_random = 1; static int umid_inited = 0; -static int make_umid(void); +static int make_umid(int (*printer)(const char *fmt, ...)); -static int __init set_umid(char *name, int is_random) +static int __init set_umid(char *name, int is_random, + int (*printer)(const char *fmt, ...)) { if(umid_inited){ - printk("Unique machine name can't be set twice\n"); + (*printer)("Unique machine name can't be set twice\n"); return(-1); } if(strlen(name) > UMID_LEN - 1) - printk("Unique machine name is being truncated to %s " - "characters\n", UMID_LEN); + (*printer)("Unique machine name is being truncated to %s " + "characters\n", UMID_LEN); strlcpy(umid, name, sizeof(umid)); umid_is_random = is_random; @@ -54,7 +54,7 @@ static int __init set_umid(char *name, i static int __init set_umid_arg(char *name, int *add) { - return(set_umid(name, 0)); + return(set_umid(name, 0, printf)); } __uml_setup("umid=", set_umid_arg, @@ -67,7 +67,7 @@ int __init umid_file_name(char *name, ch { int n; - if(!umid_inited && make_umid()) return(-1); + if(!umid_inited && make_umid(printk)) return(-1); n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; if(n > len){ @@ -85,22 +85,23 @@ static int __init create_pid_file(void) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")]; - int fd; + int fd, n; if(umid_file_name("pid", file, sizeof(file))) return 0; fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 0644); if(fd < 0){ - printk("Open of machine pid file \"%s\" failed - " - "errno = %d\n", file, -fd); + printf("Open of machine pid file \"%s\" failed - " + "err = %d\n", file, -fd); return 0; } sprintf(pid, "%d\n", os_getpid()); - if(write(fd, pid, strlen(pid)) != strlen(pid)) - printk("Write of pid file failed - errno = %d\n", errno); - close(fd); + n = os_write_file(fd, pid, strlen(pid)); + if(n != strlen(pid)) + printf("Write of pid file failed - err = %d\n", -n); + os_close_file(fd); return 0; } @@ -111,7 +112,8 @@ static int actually_do_remove(char *dir) int len; char file[256]; - if((directory = opendir(dir)) == NULL){ + directory = opendir(dir); + if(directory == NULL){ printk("actually_do_remove : couldn't open directory '%s', " "errno = %d\n", dir, errno); return(1); @@ -160,22 +162,24 @@ int not_dead_yet(char *dir) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; - int dead, fd, p; + int dead, fd, p, n; sprintf(file, "%s/pid", dir); dead = 0; - if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){ + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ if(fd != -ENOENT){ printk("not_dead_yet : couldn't open pid file '%s', " - "errno = %d\n", file, -fd); + "err = %d\n", file, -fd); return(1); } dead = 1; } if(fd > 0){ - if(read(fd, pid, sizeof(pid)) < 0){ + n = os_read_file(fd, pid, sizeof(pid)); + if(n < 0){ printk("not_dead_yet : couldn't read pid file '%s', " - "errno = %d\n", file, errno); + "err = %d\n", file, -n); return(1); } p = strtoul(pid, &end, 0); @@ -197,7 +201,7 @@ static int __init set_uml_dir(char *name if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ uml_dir = malloc(strlen(name) + 1); if(uml_dir == NULL){ - printk("Failed to malloc uml_dir - error = %d\n", + printf("Failed to malloc uml_dir - error = %d\n", errno); uml_dir = name; return(0); @@ -217,7 +221,7 @@ static int __init make_uml_dir(void) char *home = getenv("HOME"); if(home == NULL){ - printk("make_uml_dir : no value in environment for " + printf("make_uml_dir : no value in environment for " "$HOME\n"); exit(1); } @@ -232,57 +236,59 @@ static int __init make_uml_dir(void) dir[len + 1] = '\0'; } - if((uml_dir = malloc(strlen(dir) + 1)) == NULL){ + uml_dir = malloc(strlen(dir) + 1); + if(uml_dir == NULL){ printf("make_uml_dir : malloc failed, errno = %d\n", errno); exit(1); } strcpy(uml_dir, dir); if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ - printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno); + printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno); return(-1); } return 0; } -static int __init make_umid(void) +static int __init make_umid(int (*printer)(const char *fmt, ...)) { int fd, err; char tmp[strlen(uml_dir) + UMID_LEN + 1]; strlcpy(tmp, uml_dir, sizeof(tmp)); - if(*umid == 0){ + if(!umid_inited){ strcat(tmp, "XXXXXX"); fd = mkstemp(tmp); if(fd < 0){ - printk("make_umid - mkstemp failed, errno = %d\n", - errno); + (*printer)("make_umid - mkstemp failed, errno = %d\n", + errno); return(1); } - close(fd); + os_close_file(fd); /* There's a nice tiny little race between this unlink and * the mkdir below. It'd be nice if there were a mkstemp * for directories. */ unlink(tmp); - set_umid(&tmp[strlen(uml_dir)], 1); + set_umid(&tmp[strlen(uml_dir)], 1, printer); } sprintf(tmp, "%s%s", uml_dir, umid); - if((err = mkdir(tmp, 0777)) < 0){ + err = mkdir(tmp, 0777); + if(err < 0){ if(errno == EEXIST){ if(not_dead_yet(tmp)){ - printk("umid '%s' is in use\n", umid); + (*printer)("umid '%s' is in use\n", umid); return(-1); } err = mkdir(tmp, 0777); } } if(err < 0){ - printk("Failed to create %s - errno = %d\n", umid, errno); + (*printer)("Failed to create %s - errno = %d\n", umid, errno); return(-1); } @@ -295,7 +301,13 @@ __uml_setup("uml_dir=", set_uml_dir, ); __uml_postsetup(make_uml_dir); -__uml_postsetup(make_umid); + +static int __init make_umid_setup(void) +{ + return(make_umid(printf)); +} + +__uml_postsetup(make_umid_setup); __uml_postsetup(create_pid_file); /* --- linux-2.6.8-rc1/arch/um/kernel/user_syms.c 2003-06-14 12:18:33.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "user_util.h" -#include "mem_user.h" -#include "uml-config.h" - -/* Had to steal this from linux/module.h because that file can't be included - * since this includes various user-level headers. - */ - -struct module_symbol -{ - unsigned long value; - const char *name; -}; - -/* Indirect stringification. */ - -#define __MODULE_STRING_1(x) #x -#define __MODULE_STRING(x) __MODULE_STRING_1(x) - -#if !defined(__AUTOCONF_INCLUDED__) - -#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module -#define EXPORT_SYMBOL(var) error config_must_be_included_before_module -#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module - -#elif !defined(UML_CONFIG_MODULES) - -#define __EXPORT_SYMBOL(sym,str) -#define EXPORT_SYMBOL(var) -#define EXPORT_SYMBOL_NOVERS(var) - -#else - -#define __EXPORT_SYMBOL(sym, str) \ -const char __kstrtab_##sym[] \ -__attribute__((section(".kstrtab"))) = str; \ -const struct module_symbol __ksymtab_##sym \ -__attribute__((section("__ksymtab"))) = \ -{ (unsigned long)&sym, __kstrtab_##sym } - -#if defined(__MODVERSIONS__) || !defined(UML_CONFIG_MODVERSIONS) -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) -#else -#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var))) -#endif - -#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) - -#endif - -EXPORT_SYMBOL(__errno_location); - -EXPORT_SYMBOL(access); -EXPORT_SYMBOL(open); -EXPORT_SYMBOL(open64); -EXPORT_SYMBOL(close); -EXPORT_SYMBOL(read); -EXPORT_SYMBOL(write); -EXPORT_SYMBOL(dup2); -EXPORT_SYMBOL(__xstat); -EXPORT_SYMBOL(__lxstat); -EXPORT_SYMBOL(__lxstat64); -EXPORT_SYMBOL(lseek); -EXPORT_SYMBOL(lseek64); -EXPORT_SYMBOL(chown); -EXPORT_SYMBOL(truncate); -EXPORT_SYMBOL(utime); -EXPORT_SYMBOL(chmod); -EXPORT_SYMBOL(rename); -EXPORT_SYMBOL(__xmknod); - -EXPORT_SYMBOL(symlink); -EXPORT_SYMBOL(link); -EXPORT_SYMBOL(unlink); -EXPORT_SYMBOL(readlink); - -EXPORT_SYMBOL(mkdir); -EXPORT_SYMBOL(rmdir); -EXPORT_SYMBOL(opendir); -EXPORT_SYMBOL(readdir); -EXPORT_SYMBOL(closedir); -EXPORT_SYMBOL(seekdir); -EXPORT_SYMBOL(telldir); - -EXPORT_SYMBOL(ioctl); - -extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes, - __off64_t __offset); -extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, - __off64_t __offset); -EXPORT_SYMBOL(pread64); -EXPORT_SYMBOL(pwrite64); - -EXPORT_SYMBOL(statfs); -EXPORT_SYMBOL(statfs64); - -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(getuid); - -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strstr); - -EXPORT_SYMBOL(find_iomem); --- linux-2.6.8-rc1/arch/um/kernel/user_util.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/um/kernel/user_util.c 2004-07-13 17:09:48.000000000 -0700 @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -81,10 +80,10 @@ int wait_for_stop(int pid, int sig, int int status, ret; while(1){ - if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) || + CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); + if((ret < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ if(ret < 0){ - if(errno == EINTR) continue; printk("wait failed, errno = %d\n", errno); } @@ -118,29 +117,36 @@ int wait_for_stop(int pid, int sig, int } } -int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags) -{ - int pid; - - pid = clone(fn, sp, flags, arg); - if(pid < 0) return(-1); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - ptrace(PTRACE_CONT, pid, 0, 0); - return(pid); -} - -int raw(int fd, int complain) +int __raw(int fd, int complain, int now) { struct termios tt; int err; + int when; + + CATCH_EINTR(err = tcgetattr(fd, &tt)); + + if (err < 0) { + if (complain) + printk("tcgetattr failed, errno = %d\n", errno); + return(-errno); + } - tcgetattr(fd, &tt); cfmakeraw(&tt); - err = tcsetattr(fd, TCSANOW, &tt); - if((err < 0) && complain){ - printk("tcsetattr failed, errno = %d\n", errno); + + if (now) + when = TCSANOW; + else + when = TCSADRAIN; + + CATCH_EINTR(err = tcsetattr(fd, when, &tt)); + + if (err < 0) { + if (complain) + printk("tcsetattr failed, errno = %d\n", errno); return(-errno); } + /*XXX: tcsetattr could have applied only some changes + * (and cfmakeraw() is a set of changes) */ return(0); } --- linux-2.6.8-rc1/arch/um/main.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/main.c 2004-07-13 17:09:49.000000000 -0700 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -123,12 +124,14 @@ int main(int argc, char **argv, char **e set_stklim(); - if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ + new_argv = malloc((argc + 1) * sizeof(char *)); + if(new_argv == NULL){ perror("Mallocing argv"); exit(1); } for(i=0;i= uml_physmem) && (addr <= high_physmem)) + kfree(ptr); + else if((addr >= start_vm) && (addr <= end_vm)) + vfree(ptr); + else + __real_free(ptr); + } else __real_free(ptr); } --- linux-2.6.8-rc1/arch/um/Makefile 2003-08-08 22:55:11.000000000 -0700 +++ 25/arch/um/Makefile 2004-07-13 17:09:46.000000000 -0700 @@ -22,17 +22,21 @@ core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ # Have to precede the include because the included Makefiles reference them. -SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ - include/asm-um/sigcontext.h include/asm-um/processor.h \ - include/asm-um/ptrace.h include/asm-um/arch-signal.h +SYMLINK_HEADERS = archparam.h system.h sigcontext.h processor.h ptrace.h \ + arch-signal.h module.h +SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h -include $(ARCH_DIR)/Makefile-$(SUBARCH) -include $(ARCH_DIR)/Makefile-os-$(OS) +# This target adds dependencies to "prepare". They are defined in the included +# Makefiles (see Makefile-i386). + +.PHONY: sys_prepare +sys_prepare: + @: MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas @@ -41,6 +45,9 @@ ifneq ($(MAKEFILE-y),) include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) endif +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) + EXTRAVERSION := $(EXTRAVERSION)-1um ARCH_INCLUDE = -I$(ARCH_DIR)/include @@ -52,14 +59,22 @@ ARCH_INCLUDE = -I$(ARCH_DIR)/include CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ - $(MODE_INCLUDE) + -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE) + +CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc +# These are needed for clean and mrproper, since in that case .config is not +# included; the values here are meaningless + +CONFIG_NEST_LEVEL ?= 0 +CONFIG_KERNEL_HALF_GIGS ?= 0 + SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) ifeq ($(CONFIG_MODE_SKAS), y) -$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h endif include/linux/version.h: arch/$(ARCH)/Makefile @@ -98,17 +113,17 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_ CONFIG_KERNEL_STACK_ORDER ?= 2 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) -AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \ +AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \ -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ - -DKERNEL_STACK_SIZE=$(STACK_SIZE) + -DKERNEL_STACK_SIZE=$(STACK_SIZE)) -AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum +export AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) -$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE - $(call if_changed_dep,as_s_S) +#$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE +# $(call if_changed_dep,as_s_S) linux: vmlinux $(LD_SCRIPT-y) $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ @@ -116,37 +131,47 @@ linux: vmlinux $(LD_SCRIPT-y) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) +USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS)) USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE +# From main Makefile, these options are set after including the ARCH makefile. +# So copy them here. + +ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +USER_CFLAGS += -Os +else +USER_CFLAGS += -O2 +endif + +ifndef CONFIG_FRAME_POINTER +USER_CFLAGS += -fomit-frame-pointer +endif + +ifdef CONFIG_DEBUG_INFO +USER_CFLAGS += -g +endif + CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \ - $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS) + $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \ + $(GEN_HEADERS) + +MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ + $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) -$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c - $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< +$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare + @ echo ' MAIN $@' + @ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< archmrproper: - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d archmrproper; \ - done - rm -f $(CLEAN_FILES) $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) - -archclean: sysclean - for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \ - do \ - $(MAKE) -C $$d clean; \ - done - find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ - -o -name '*.gcov' \) -type f -print | xargs rm -f - rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) + @: -archdep: - for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done +archclean: + @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ + -o -name '*.gcov' \) -type f -print | xargs rm -f $(SYMLINK_HEADERS): cd $(TOPDIR)/$(dir $@) ; \ @@ -161,19 +186,32 @@ $(ARCH_DIR)/include/sysdep: $(ARCH_DIR)/os: cd $(ARCH_DIR) && ln -sf os-$(OS) os -$(ARCH_DIR)/include/uml-config.h : - sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ +# Generated files +define filechk_umlconfig + sed 's/ CONFIG/ UML_CONFIG/' +endef + +$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h + $(call filechk,umlconfig) + +filechk_gen_header = $< $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task - $< > $@ + $(call filechk,gen_header) $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants - $< > $@ + $(call filechk,gen_header) -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ - $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \ + sys_prepare FORCE ; $(ARCH_DIR)/util: FORCE - @$(call descend,$@,) + $(Q)$(MAKE) $(build)=$@ export SUBARCH USER_CFLAGS OS + +all: linux + +define archhelp + echo '* linux - Binary kernel image (./linux)' +endef --- linux-2.6.8-rc1/arch/um/Makefile-i386 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/Makefile-i386 2004-07-13 17:09:45.000000000 -0700 @@ -16,22 +16,27 @@ SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/uti SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h +sys_prepare: $(SYS_DIR)/sc.h + prepare: $(SYS_HEADERS) +filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc + $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc - $< > $@ + $(call filechk,$@) + +filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread - $< > $@ + $(call filechk,$@) -$(SYS_UTIL_DIR)/mk_sc: FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_sc: scripts/basic/fixdep include/config/MARKER FORCE ; + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; - @$(call descend,$(SYS_UTIL_DIR),$@) +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ; + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@ $(SYS_UTIL_DIR): include/asm FORCE - @$(call descend,$@,) + $(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) -sysclean : - rm -f $(SYS_HEADERS) +CLEAN_FILES += $(SYS_HEADERS) --- linux-2.6.8-rc1/arch/um/Makefile-skas 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/um/Makefile-skas 2004-07-13 17:09:45.000000000 -0700 @@ -14,7 +14,7 @@ MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/ LINK_SKAS = -Wl,-rpath,/lib LD_SCRIPT_SKAS = dyn.lds.s -GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h -$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : - $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h : + $(Q)$(MAKE) $(build)=$(ARCH_DIR)/kernel/skas $@ --- linux-2.6.8-rc1/arch/um/os-Linux/drivers/ethertap_kern.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/os-Linux/drivers/ethertap_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -8,7 +8,6 @@ #include "linux/init.h" #include "linux/netdevice.h" #include "linux/etherdevice.h" -#include "linux/init.h" #include "net_kern.h" #include "net_user.h" #include "etap.h" --- linux-2.6.8-rc1/arch/um/os-Linux/drivers/ethertap_user.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/arch/um/os-Linux/drivers/ethertap_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "net_user.h" #include "etap.h" #include "helper.h" @@ -42,13 +42,14 @@ static void etap_change(int op, unsigned { struct addr_change change; void *output; + int n; change.what = op; memcpy(change.addr, addr, sizeof(change.addr)); memcpy(change.netmask, netmask, sizeof(change.netmask)); - if(write(fd, &change, sizeof(change)) != sizeof(change)) - printk("etap_change - request failed, errno = %d\n", - errno); + n = os_write_file(fd, &change, sizeof(change)); + if(n != sizeof(change)) + printk("etap_change - request failed, err = %d\n", -n); output = um_kmalloc(page_size()); if(output == NULL) printk("etap_change : Failed to allocate output buffer\n"); @@ -82,15 +83,15 @@ static void etap_pre_exec(void *arg) struct etap_pre_exec_data *data = arg; dup2(data->control_remote, 1); - close(data->data_me); - close(data->control_me); + os_close_file(data->data_me); + os_close_file(data->control_me); } static int etap_tramp(char *dev, char *gate, int control_me, int control_remote, int data_me, int data_remote) { struct etap_pre_exec_data pe_data; - int pid, status, err; + int pid, status, err, n; char version_buf[sizeof("nnnnn\0")]; char data_fd_buf[sizeof("nnnnnn\0")]; char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; @@ -114,21 +115,22 @@ static int etap_tramp(char *dev, char *g pe_data.data_me = data_me; pid = run_helper(etap_pre_exec, &pe_data, args, NULL); - if(pid < 0) err = errno; - close(data_remote); - close(control_remote); - if(read(control_me, &c, sizeof(c)) != sizeof(c)){ - printk("etap_tramp : read of status failed, errno = %d\n", - errno); - return(EINVAL); + if(pid < 0) err = pid; + os_close_file(data_remote); + os_close_file(control_remote); + n = os_read_file(control_me, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("etap_tramp : read of status failed, err = %d\n", -n); + return(-EINVAL); } if(c != 1){ printk("etap_tramp : uml_net failed\n"); - err = EINVAL; - if(waitpid(pid, &status, 0) < 0) err = errno; - else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){ + err = -EINVAL; + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0) + err = -errno; + else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); - } } return(err); } @@ -143,14 +145,14 @@ static int etap_open(void *data) if(err) return(err); err = os_pipe(data_fds, 0, 0); - if(err){ - printk("data os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("data os_pipe failed - err = %d\n", -err); return(err); } err = os_pipe(control_fds, 1, 0); - if(err){ - printk("control os_pipe failed - errno = %d\n", -err); + if(err < 0){ + printk("control os_pipe failed - err = %d\n", -err); return(err); } @@ -167,9 +169,9 @@ static int etap_open(void *data) kfree(output); } - if(err != 0){ - printk("etap_tramp failed - errno = %d\n", err); - return(-err); + if(err < 0){ + printk("etap_tramp failed - err = %d\n", -err); + return(err); } pri->data_fd = data_fds[0]; @@ -183,11 +185,11 @@ static void etap_close(int fd, void *dat struct ethertap_data *pri = data; iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); - close(fd); + os_close_file(fd); os_shutdown_socket(pri->data_fd, 1, 1); - close(pri->data_fd); + os_close_file(pri->data_fd); pri->data_fd = -1; - close(pri->control_fd); + os_close_file(pri->control_fd); pri->control_fd = -1; } --- linux-2.6.8-rc1/arch/um/os-Linux/drivers/tuntap_user.c 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/um/os-Linux/drivers/tuntap_user.c 2004-07-13 17:09:48.000000000 -0700 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include "net_user.h" #include "tuntap.h" #include "kern_util.h" +#include "user_util.h" #include "user.h" #include "helper.h" #include "os.h" @@ -61,7 +61,7 @@ static void tuntap_pre_exec(void *arg) struct tuntap_pre_exec_data *data = arg; dup2(data->stdout, 1); - close(data->close_me); + os_close_file(data->close_me); } static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, @@ -86,7 +86,7 @@ static int tuntap_open_tramp(char *gate, if(pid < 0) return(-pid); - close(remote); + os_close_file(remote); msg.msg_name = NULL; msg.msg_namelen = 0; @@ -107,19 +107,19 @@ static int tuntap_open_tramp(char *gate, if(n < 0){ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", errno); - return(errno); + return(-errno); } - waitpid(pid, NULL, 0); + CATCH_EINTR(waitpid(pid, NULL, 0)); cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ printk("tuntap_open_tramp : didn't receive a message\n"); - return(EINVAL); + return(-EINVAL); } if((cmsg->cmsg_level != SOL_SOCKET) || (cmsg->cmsg_type != SCM_RIGHTS)){ printk("tuntap_open_tramp : didn't receive a descriptor\n"); - return(EINVAL); + return(-EINVAL); } *fd_out = ((int *) CMSG_DATA(cmsg))[0]; return(0); @@ -133,27 +133,29 @@ static int tuntap_open(void *data) int err, fds[2], len, used; err = tap_open_common(pri->dev, pri->gate_addr); - if(err) return(err); + if(err < 0) + return(err); if(pri->fixed_config){ - if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){ - printk("Failed to open /dev/net/tun, errno = %d\n", - errno); - return(-errno); + pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); + if(pri->fd < 0){ + printk("Failed to open /dev/net/tun, err = %d\n", + -pri->fd); + return(pri->fd); } memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP; + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ - printk("TUNSETIFF failed, errno = %d", errno); - close(pri->fd); + printk("TUNSETIFF failed, errno = %d\n", errno); + os_close_file(pri->fd); return(-errno); } } else { err = os_pipe(fds, 0, 0); - if(err){ - printk("tuntap_open : os_pipe failed - errno = %d\n", + if(err < 0){ + printk("tuntap_open : os_pipe failed - err = %d\n", -err); return(err); } @@ -166,19 +168,19 @@ static int tuntap_open(void *data) fds[1], buffer, len, &used); output = buffer; - if(err == 0){ - pri->dev_name = uml_strdup(buffer); - output += IFNAMSIZ; - printk(output); - free_output_buffer(buffer); - } - else { - printk(output); + if(err < 0) { + printk("%s", output); free_output_buffer(buffer); - printk("tuntap_open_tramp failed - errno = %d\n", err); - return(-err); + printk("tuntap_open_tramp failed - err = %d\n", -err); + return(err); } - close(fds[0]); + + pri->dev_name = uml_strdup(buffer); + output += IFNAMSIZ; + printk("%s", output); + free_output_buffer(buffer); + + os_close_file(fds[0]); iter_addresses(pri->dev, open_addr, pri->dev_name); } @@ -191,7 +193,7 @@ static void tuntap_close(int fd, void *d if(!pri->fixed_config) iter_addresses(pri->dev, close_addr, pri->dev_name); - close(fd); + os_close_file(fd); pri->fd = -1; } --- linux-2.6.8-rc1/arch/um/os-Linux/file.c 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/um/os-Linux/file.c 2004-07-13 17:09:45.000000000 -0700 @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,33 +19,235 @@ #include "user.h" #include "kern_util.h" -int os_file_type(char *file) +static void copy_stat(struct uml_stat *dst, struct stat64 *src) +{ + *dst = ((struct uml_stat) { + .ust_dev = src->st_dev, /* device */ + .ust_ino = src->st_ino, /* inode */ + .ust_mode = src->st_mode, /* protection */ + .ust_nlink = src->st_nlink, /* number of hard links */ + .ust_uid = src->st_uid, /* user ID of owner */ + .ust_gid = src->st_gid, /* group ID of owner */ + .ust_size = src->st_size, /* total size, in bytes */ + .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */ + .ust_blocks = src->st_blocks, /* number of blocks allocated */ + .ust_atime = src->st_atime, /* time of last access */ + .ust_mtime = src->st_mtime, /* time of last modification */ + .ust_ctime = src->st_ctime, /* time of last change */ + }); +} + +int os_stat_fd(const int fd, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = fstat64(fd, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_stat_file(const char *file_name, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = stat64(file_name, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_access(const char* file, int mode) +{ + int amode, err; + + amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | + (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + + err = access(file, amode); + if(err < 0) + return(-errno); + + return(0); +} + +void os_print_error(int error, const char* str) +{ + errno = error < 0 ? -error : error; + + perror(str); +} + +/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ +int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + err = ioctl(fd, cmd, arg); + if(err < 0) + return(-errno); + + return(err); +} + +int os_window_size(int fd, int *rows, int *cols) +{ + struct winsize size; + + if(ioctl(fd, TIOCGWINSZ, &size) < 0) + return(-errno); + + *rows = size.ws_row; + *cols = size.ws_col; + + return(0); +} + +int os_new_tty_pgrp(int fd, int pid) { - struct stat64 buf; + if(ioctl(fd, TIOCSCTTY, 0) < 0){ + printk("TIOCSCTTY failed, errno = %d\n", errno); + return(-errno); + } + + if(tcsetpgrp(fd, pid) < 0){ + printk("tcsetpgrp failed, errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +/* FIXME: ensure namebuf in os_get_if_name is big enough */ +int os_get_ifname(int fd, char* namebuf) +{ + if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) + return(-errno); + + return(0); +} + +int os_set_slip(int fd) +{ + int disc, sencap; + + disc = N_SLIP; + if(ioctl(fd, TIOCSETD, &disc) < 0){ + printk("Failed to set slip line discipline - " + "errno = %d\n", errno); + return(-errno); + } + + sencap = 0; + if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ + printk("Failed to set slip encapsulation - " + "errno = %d\n", errno); + return(-errno); + } + + return(0); +} + +int os_set_owner(int fd, int pid) +{ + if(fcntl(fd, F_SETOWN, pid) < 0){ + int save_errno = errno; + + if(fcntl(fd, F_GETOWN, 0) != pid) + return(-save_errno); + } + + return(0); +} + +/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ +int os_sigio_async(int master, int slave) +{ + int flags; - if(stat64(file, &buf) == -1) + flags = fcntl(master, F_GETFL); + if(flags < 0) { + printk("fcntl F_GETFL failed, errno = %d\n", errno); return(-errno); + } + + if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)){ + printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno); + return(-errno); + } + + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){ + printk("fcntl F_SETFL failed, errno = %d\n", errno); + return(-errno); + } - if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.st_mode)) return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.st_mode)) return(OS_TYPE_SOCK); + return(0); +} + +int os_mode_fd(int fd, int mode) +{ + int err; + + do { + err = fchmod(fd, mode); + } while((err < 0) && (errno==EINTR)) ; + + if(err < 0) + return(-errno); + + return(0); +} + +int os_file_type(char *file) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0) + return(err); + + if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); + else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); + else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); + else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); + else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); + else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); else return(OS_TYPE_FILE); } int os_file_mode(char *file, struct openflags *mode_out) { + int err; + *mode_out = OPENFLAGS(); - if(!access(file, W_OK)) *mode_out = of_write(*mode_out); - else if(errno != EACCES) - return(-errno); + err = os_access(file, OS_ACC_W_OK); + if((err < 0) && (err != -EACCES)) + return(err); - if(!access(file, R_OK)) *mode_out = of_read(*mode_out); - else if(errno != EACCES) - return(-errno); + *mode_out = of_write(*mode_out); + + err = os_access(file, OS_ACC_R_OK); + if((err < 0) && (err != -EACCES)) + return(err); + + *mode_out = of_read(*mode_out); return(0); } @@ -63,16 +267,14 @@ int os_open_file(char *file, struct open if(flags.e) f |= O_EXCL; fd = open64(file, f, mode); - if(fd < 0) return(-errno); - - if(flags.cl){ - if(fcntl(fd, F_SETFD, 1)){ - close(fd); - return(-errno); - } + if(fd < 0) + return(-errno); + + if(flags.cl && fcntl(fd, F_SETFD, 1)){ + os_close_file(fd); + return(-errno); } - return(fd); return(fd); } @@ -90,7 +292,7 @@ int os_connect_socket(char *name) err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); if(err) - return(err); + return(-errno); return(fd); } @@ -109,88 +311,162 @@ int os_seek_file(int fd, __u64 offset) return(0); } -int os_read_file(int fd, void *buf, int len) +static int fault_buffer(void *start, int len, + int (*copy_proc)(void *addr, void *buf, int len)) { - int n; + int page = getpagesize(), i; + char c; - /* Force buf into memory if it's not already. */ + for(i = 0; i < len; i += page){ + if((*copy_proc)(start + i, &c, sizeof(c))) + return(-EFAULT); + } + if((len % page) != 0){ + if((*copy_proc)(start + len - 1, &c, sizeof(c))) + return(-EFAULT); + } + return(0); +} - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, &c, sizeof(c))) - return(-EFAULT); -#endif +static int file_io(int fd, void *buf, int len, + int (*io_proc)(int fd, void *buf, int len), + int (*copy_user_proc)(void *addr, void *buf, int len)) +{ + int n, err; + + do { + n = (*io_proc)(fd, buf, len); + if((n < 0) && (errno == EFAULT)){ + err = fault_buffer(buf, len, copy_user_proc); + if(err) + return(err); + n = (*io_proc)(fd, buf, len); + } + } while((n < 0) && (errno == EINTR)); - n = read(fd, buf, len); if(n < 0) return(-errno); return(n); } -int os_write_file(int fd, void *buf, int count) +int os_read_file(int fd, void *buf, int len) { - int n; - - /* Force buf into memory if it's not already. */ - - /* XXX This fails if buf is kernel memory */ -#ifdef notdef - if(copy_to_user_proc(buf, buf, buf[0])) - return(-EFAULT); -#endif + return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, + copy_from_user_proc)); +} - n = write(fd, buf, count); - if(n < 0) - return(-errno); - return(n); +int os_write_file(int fd, const void *buf, int len) +{ + return(file_io(fd, (void *) buf, len, + (int (*)(int, void *, int)) write, copy_to_user_proc)); } int os_file_size(char *file, long long *size_out) { - struct stat64 buf; + struct uml_stat buf; + int err; - if(stat64(file, &buf) == -1){ - printk("Couldn't stat \"%s\" : errno = %d\n", file, errno); - return(-errno); + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); } - if(S_ISBLK(buf.st_mode)){ + + if(S_ISBLK(buf.ust_mode)){ int fd, blocks; - if((fd = open64(file, O_RDONLY)) < 0){ - printk("Couldn't open \"%s\", errno = %d\n", file, - errno); - return(-errno); + fd = os_open_file(file, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open \"%s\", errno = %d\n", file, -fd); + return(fd); } if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ printk("Couldn't get the block size of \"%s\", " "errno = %d\n", file, errno); - close(fd); - return(-errno); + err = -errno; + os_close_file(fd); + return(err); } *size_out = ((long long) blocks) * 512; - close(fd); + os_close_file(fd); return(0); } - *size_out = buf.st_size; + *size_out = buf.ust_size; + return(0); +} + +int os_file_modtime(char *file, unsigned long *modtime) +{ + struct uml_stat buf; + int err; + + err = os_stat_file(file, &buf); + if(err < 0){ + printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + return(err); + } + + *modtime = buf.ust_mtime; return(0); } +int os_get_exec_close(int fd, int* close_on_exec) +{ + int ret; + + do { + ret = fcntl(fd, F_GETFD); + } while((ret < 0) && (errno == EINTR)) ; + + if(ret < 0) + return(-errno); + + *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; + return(ret); +} + +int os_set_exec_close(int fd, int close_on_exec) +{ + int flag, err; + + if(close_on_exec) flag = FD_CLOEXEC; + else flag = 0; + + do { + err = fcntl(fd, F_SETFD, flag); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + return(err); +} + int os_pipe(int *fds, int stream, int close_on_exec) { int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err) + if(err < 0) return(-errno); if(!close_on_exec) return(0); - if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0)) - printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", - errno); + err = os_set_exec_close(fds[0], 1); + if(err < 0) + goto error; + + err = os_set_exec_close(fds[1], 1); + if(err < 0) + goto error; return(0); + + error: + printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); + os_close_file(fds[1]); + os_close_file(fds[0]); + return(err); } int os_set_fd_async(int fd, int owner) @@ -270,7 +546,7 @@ int os_shutdown_socket(int fd, int r, in return(-EINVAL); } err = shutdown(fd, what); - if(err) + if(err < 0) return(-errno); return(0); } @@ -315,7 +591,7 @@ int os_rcv_fd(int fd, int *helper_pid_ou return(new); } -int create_unix_socket(char *file, int len) +int os_create_unix_socket(char *file, int len, int close_on_exec) { struct sockaddr_un addr; int sock, err; @@ -327,6 +603,13 @@ int create_unix_socket(char *file, int l return(-errno); } + if(close_on_exec) { + err = os_set_exec_close(sock, 1); + if(err < 0) + printk("create_unix_socket : close_on_exec failed, " + "err = %d", -err); + } + addr.sun_family = AF_UNIX; /* XXX Be more careful about overflow */ @@ -334,14 +617,45 @@ int create_unix_socket(char *file, int l err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0){ - printk("create_listening_socket - bind failed, errno = %d\n", - errno); + printk("create_listening_socket at '%s' - bind failed, " + "errno = %d\n", file, errno); return(-errno); } return(sock); } +void os_flush_stdout(void) +{ + fflush(stdout); +} + +int os_lock_file(int fd, int excl) +{ + int type = excl ? F_WRLCK : F_RDLCK; + struct flock lock = ((struct flock) { .l_type = type, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0 } ); + int err, save; + + err = fcntl(fd, F_SETLK, &lock); + if(!err) + goto out; + + save = -errno; + err = fcntl(fd, F_GETLK, &lock); + if(err){ + err = -errno; + goto out; + } + + printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); + err = save; + out: + return(err); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically --- linux-2.6.8-rc1/arch/um/os-Linux/Makefile 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/os-Linux/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -3,13 +3,9 @@ # Licensed under the GPL # -obj-y = file.o process.o tty.o drivers/ +obj-y = file.o process.o tty.o user_syms.o drivers/ USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< - -clean : - -archmrproper: --- linux-2.6.8-rc1/arch/um/os-Linux/process.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/arch/um/os-Linux/process.c 2004-07-13 17:09:49.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,35 +7,44 @@ #include #include #include +#include #include #include #include "os.h" #include "user.h" +#include "user_util.h" + +#define ARBITRARY_ADDR -1 +#define FAILURE_PID -1 + +#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") +#define COMM_SCANF "%*[^)])" unsigned long os_process_pc(int pid) { - char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; + char proc_stat[STAT_PATH_LEN], buf[256]; unsigned long pc; - int fd; + int fd, err; sprintf(proc_stat, "/proc/%d/stat", pid); fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("os_process_pc - couldn't open '%s', errno = %d\n", - proc_stat, errno); - return(-1); + printk("os_process_pc - couldn't open '%s', err = %d\n", + proc_stat, -fd); + return(ARBITRARY_ADDR); } - if(read(fd, buf, sizeof(buf)) < 0){ - printk("os_process_pc - couldn't read '%s', errno = %d\n", - proc_stat, errno); - close(fd); - return(-1); + err = os_read_file(fd, buf, sizeof(buf)); + if(err < 0){ + printk("os_process_pc - couldn't read '%s', err = %d\n", + proc_stat, -err); + os_close_file(fd); + return(ARBITRARY_ADDR); } - close(fd); - pc = -1; - if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " + os_close_file(fd); + pc = ARBITRARY_ADDR; + if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %ld", &pc) != 1){ + "%*d %*d %*d %*d %lu", &pc) != 1){ printk("os_process_pc - couldn't find pc in '%s'\n", buf); } return(pc); @@ -43,7 +52,7 @@ unsigned long os_process_pc(int pid) int os_process_parent(int pid) { - char stat[sizeof("/proc/nnnnn/stat\0")]; + char stat[STAT_PATH_LEN]; char data[256]; int parent, n, fd; @@ -52,22 +61,22 @@ int os_process_parent(int pid) snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); fd = os_open_file(stat, of_read(OPENFLAGS()), 0); if(fd < 0){ - printk("Couldn't open '%s', errno = %d\n", stat, -fd); - return(-1); + printk("Couldn't open '%s', err = %d\n", stat, -fd); + return(FAILURE_PID); } - n = read(fd, data, sizeof(data)); - close(fd); + n = os_read_file(fd, data, sizeof(data)); + os_close_file(fd); if(n < 0){ - printk("Couldn't read '%s', errno = %d\n", stat); - return(-1); + printk("Couldn't read '%s', err = %d\n", stat, -n); + return(FAILURE_PID); } - parent = -1; - /* XXX This will break if there is a space in the command */ - n = sscanf(data, "%*d %*s %*c %d", &parent); - if(n != 1) printk("Failed to scan '%s'\n", data); + parent = FAILURE_PID; + n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); + if(n != 1) + printk("Failed to scan '%s'\n", data); return(parent); } @@ -81,13 +90,17 @@ void os_kill_process(int pid, int reap_c { kill(pid, SIGKILL); if(reap_child) - waitpid(pid, NULL, 0); + CATCH_EINTR(waitpid(pid, NULL, 0)); } void os_usr1_process(int pid) { +#ifdef __NR_tkill + syscall(__NR_tkill, pid, SIGUSR1); +#else kill(pid, SIGUSR1); +#endif } int os_getpid(void) @@ -95,7 +108,7 @@ int os_getpid(void) return(getpid()); } -int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, +int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x) { void *loc; @@ -104,8 +117,8 @@ int os_map_memory(void *virt, int fd, un prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); - loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, - fd, off); + loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, + fd, off); if(loc == MAP_FAILED) return(-errno); return(0); @@ -126,7 +139,8 @@ int os_unmap_memory(void *addr, int len) int err; err = munmap(addr, len); - if(err < 0) return(-errno); + if(err < 0) + return(-errno); return(0); } --- linux-2.6.8-rc1/arch/um/os-Linux/tty.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/arch/um/os-Linux/tty.c 2004-07-13 17:09:45.000000000 -0700 @@ -28,10 +28,10 @@ int get_pty(void) struct grantpt_info info; int fd; - if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){ - printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n", - errno); - return(-1); + fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); + if(fd < 0){ + printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); + return(fd); } info.fd = fd; @@ -39,7 +39,7 @@ int get_pty(void) if(info.res < 0){ printk("get_pty : Couldn't grant pty - errno = %d\n", - info.err); + -info.err); return(-1); } if(unlockpt(fd) < 0){ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/os-Linux/user_syms.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,88 @@ +#include "linux/types.h" +#include "linux/module.h" + +/* Some of this are builtin function (some are not but could in the future), + * so I *must* declare good prototypes for them and then EXPORT them. + * The kernel code uses the macro defined by include/linux/string.h, + * so I undef macros; the userspace code does not include that and I + * add an EXPORT for the glibc one.*/ + +#undef strlen +#undef strstr +#undef memcpy +#undef memset + +extern size_t strlen(const char *); +extern void *memcpy(void *, const void *, size_t); +extern void *memset(void *, int, size_t); +extern int printf(const char *, ...); + +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(printf); + +EXPORT_SYMBOL(strstr); + +/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. + * However, the modules will use the CRC defined *here*, no matter if it is + * good; so the versions of these symbols will always match + */ +#define EXPORT_SYMBOL_PROTO(sym) \ + int sym(void); \ + EXPORT_SYMBOL(sym); + +EXPORT_SYMBOL_PROTO(__errno_location); + +EXPORT_SYMBOL_PROTO(access); +EXPORT_SYMBOL_PROTO(open); +EXPORT_SYMBOL_PROTO(open64); +EXPORT_SYMBOL_PROTO(close); +EXPORT_SYMBOL_PROTO(read); +EXPORT_SYMBOL_PROTO(write); +EXPORT_SYMBOL_PROTO(dup2); +EXPORT_SYMBOL_PROTO(__xstat); +EXPORT_SYMBOL_PROTO(__lxstat); +EXPORT_SYMBOL_PROTO(__lxstat64); +EXPORT_SYMBOL_PROTO(lseek); +EXPORT_SYMBOL_PROTO(lseek64); +EXPORT_SYMBOL_PROTO(chown); +EXPORT_SYMBOL_PROTO(truncate); +EXPORT_SYMBOL_PROTO(utime); +EXPORT_SYMBOL_PROTO(chmod); +EXPORT_SYMBOL_PROTO(rename); +EXPORT_SYMBOL_PROTO(__xmknod); + +EXPORT_SYMBOL_PROTO(symlink); +EXPORT_SYMBOL_PROTO(link); +EXPORT_SYMBOL_PROTO(unlink); +EXPORT_SYMBOL_PROTO(readlink); + +EXPORT_SYMBOL_PROTO(mkdir); +EXPORT_SYMBOL_PROTO(rmdir); +EXPORT_SYMBOL_PROTO(opendir); +EXPORT_SYMBOL_PROTO(readdir); +EXPORT_SYMBOL_PROTO(closedir); +EXPORT_SYMBOL_PROTO(seekdir); +EXPORT_SYMBOL_PROTO(telldir); + +EXPORT_SYMBOL_PROTO(ioctl); + +EXPORT_SYMBOL_PROTO(pread64); +EXPORT_SYMBOL_PROTO(pwrite64); + +EXPORT_SYMBOL_PROTO(statfs); +EXPORT_SYMBOL_PROTO(statfs64); + +EXPORT_SYMBOL_PROTO(getuid); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/sys-i386/bugs.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/arch/um/sys-i386/bugs.c 2004-07-13 17:09:45.000000000 -0700 @@ -4,20 +4,21 @@ */ #include -#include #include #include #include +#include #include "kern_util.h" #include "user.h" #include "sysdep/ptrace.h" #include "task.h" +#include "os.h" #define MAXTOKEN 64 /* Set during early boot */ -int cpu_has_cmov = 1; -int cpu_has_xmm = 0; +int host_has_cmov = 1; +int host_has_xmm = 0; static char token(int fd, char *buf, int len, char stop) { @@ -27,13 +28,15 @@ static char token(int fd, char *buf, int ptr = buf; end = &buf[len]; do { - n = read(fd, ptr, sizeof(*ptr)); + n = os_read_file(fd, ptr, sizeof(*ptr)); c = *ptr++; - if(n == 0) return(0); - else if(n != sizeof(*ptr)){ - printk("Reading /proc/cpuinfo failed, " - "errno = %d\n", errno); - return(-errno); + if(n != sizeof(*ptr)){ + if(n == 0) return(0); + printk("Reading /proc/cpuinfo failed, err = %d\n", -n); + if(n < 0) + return(n); + else + return(-EIO); } } while((c != '\n') && (c != stop) && (ptr < end)); @@ -45,45 +48,79 @@ static char token(int fd, char *buf, int return(c); } -static int check_cpu_feature(char *feature, int *have_it) +static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) { - char buf[MAXTOKEN], c; - int fd, len = sizeof(buf)/sizeof(buf[0]), n; - - printk("Checking for host processor %s support...", feature); - fd = open("/proc/cpuinfo", O_RDONLY); - if(fd < 0){ - printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno); - return(0); - } + int n; + char c; - *have_it = 0; - buf[len - 1] = '\0'; + scratch[len - 1] = '\0'; while(1){ - c = token(fd, buf, len - 1, ':'); - if(c <= 0) goto out; + c = token(fd, scratch, len - 1, ':'); + if(c <= 0) + return(0); else if(c != ':'){ printk("Failed to find ':' in /proc/cpuinfo\n"); - goto out; + return(0); } - if(!strncmp(buf, "flags", strlen("flags"))) break; + if(!strncmp(scratch, key, strlen(key))) + return(1); do { - n = read(fd, &c, sizeof(c)); + n = os_read_file(fd, &c, sizeof(c)); if(n != sizeof(c)){ printk("Failed to find newline in " - "/proc/cpuinfo, n = %d, errno = %d\n", - n, errno); - goto out; + "/proc/cpuinfo, err = %d\n", -n); + return(0); } } while(c != '\n'); } + return(0); +} + +int cpu_feature(char *what, char *buf, int len) +{ + int fd, ret = 0; + + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + if(!find_cpuinfo_line(fd, what, buf, len)){ + printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); + goto out_close; + } + + token(fd, buf, len, '\n'); + ret = 1; + + out_close: + os_close_file(fd); + return(ret); +} + +static int check_cpu_flag(char *feature, int *have_it) +{ + char buf[MAXTOKEN], c; + int fd, len = sizeof(buf)/sizeof(buf[0]); + + printk("Checking for host processor %s support...", feature); + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + *have_it = 0; + if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0]))) + goto out; c = token(fd, buf, len - 1, ' '); if(c < 0) goto out; else if(c != ' '){ - printk("Failed to find ':' in /proc/cpuinfo\n"); + printk("Failed to find ' ' in /proc/cpuinfo\n"); goto out; } @@ -100,21 +137,48 @@ static int check_cpu_feature(char *featu out: if(*have_it == 0) printk("No\n"); else if(*have_it == 1) printk("Yes\n"); - close(fd); + os_close_file(fd); return(1); } +#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems + * for some people. + */ +static void disable_lcall(void) +{ + struct modify_ldt_ldt_s ldt; + int err; + + bzero(&ldt, sizeof(ldt)); + ldt.entry_number = 7; + ldt.base_addr = 0; + ldt.limit = 0; + err = modify_ldt(1, &ldt, sizeof(ldt)); + if(err) + printk("Failed to disable lcall7 - errno = %d\n", errno); +} +#endif + +void arch_init_thread(void) +{ +#if 0 + disable_lcall(); +#endif +} + void arch_check_bugs(void) { int have_it; - if(access("/proc/cpuinfo", R_OK)){ + if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){ printk("/proc/cpuinfo not available - skipping CPU capability " "checks\n"); return; } - if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it; - if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it; + if(check_cpu_flag("cmov", &have_it)) + host_has_cmov = have_it; + if(check_cpu_flag("xmm", &have_it)) + host_has_xmm = have_it; } int arch_handle_signal(int sig, union uml_pt_regs *regs) @@ -130,18 +194,18 @@ int arch_handle_signal(int sig, union um if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) return(0); - if(cpu_has_cmov == 0) + if(host_has_cmov == 0) panic("SIGILL caused by cmov, which this processor doesn't " "implement, boot a filesystem compiled for older " "processors"); - else if(cpu_has_cmov == 1) + else if(host_has_cmov == 1) panic("SIGILL caused by cmov, which this processor claims to " "implement"); - else if(cpu_has_cmov == -1) + else if(host_has_cmov == -1) panic("SIGILL caused by cmov, couldn't tell if this processor " "implements it, boot a filesystem compiled for older " "processors"); - else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov); + else panic("Bad value for host_has_cmov (%d)", host_has_cmov); return(0); } --- linux-2.6.8-rc1/arch/um/sys-i386/extable.c 2003-06-14 12:18:34.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,30 +0,0 @@ -/* - * linux/arch/i386/mm/extable.c - */ - -#include -#include -#include -#include - -/* Simple binary search */ -const struct exception_table_entry * -search_extable(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return NULL; -} --- linux-2.6.8-rc1/arch/um/sys-i386/fault.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/arch/um/sys-i386/fault.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -7,16 +7,24 @@ #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" -extern unsigned long search_exception_table(unsigned long addr); +/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ +struct exception_table_entry +{ + unsigned long insn; + unsigned long fixup; +}; +const struct exception_table_entry *search_exception_tables(unsigned long add); + +/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ int arch_fixup(unsigned long address, void *sc_ptr) { struct sigcontext *sc = sc_ptr; - unsigned long fixup; + const struct exception_table_entry *fixup; fixup = search_exception_tables(address); if(fixup != 0){ - sc->eip = fixup; + sc->eip = fixup->fixup; return(1); } return(0); --- linux-2.6.8-rc1/arch/um/sys-i386/Makefile 2003-06-14 12:17:59.000000000 -0700 +++ 25/arch/um/sys-i386/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -1,7 +1,8 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \ - ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o +obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \ + semaphore.o sigcontext.o syscalls.o sysrq.o time.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_MODULES) += module.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) @@ -9,6 +10,8 @@ USER_OBJS := $(foreach file,$(USER_OBJS) SYMLINKS = semaphore.c highmem.c module.c SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f) +clean-files := $(SYMLINKS) + semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel @@ -24,19 +27,4 @@ $(USER_OBJS) : %.o: %.c $(SYMLINKS): $(call make_link,$@) -clean: - $(MAKE) -C util clean - -fastdep: - -dep: - -archmrproper: - rm -f $(SYMLINKS) - -archclean: - -archdep: - -modules: - +subdir- := util --- linux-2.6.8-rc1/arch/um/sys-i386/ptrace_user.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/arch/um/sys-i386/ptrace_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -39,10 +39,10 @@ static void write_debugregs(int pid, uns nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ if((i == 4) || (i == 5)) continue; - if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], + if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i], regs[i]) < 0) - printk("write_debugregs - ptrace failed, " - "errno = %d\n", errno); + printk("write_debugregs - ptrace failed on " + "register %d, errno = %d\n", errno); } } @@ -54,7 +54,7 @@ static void read_debugregs(int pid, unsi dummy = NULL; nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); for(i = 0; i < nregs; i++){ - regs[i] = ptrace(PTRACE_PEEKUSR, pid, + regs[i] = ptrace(PTRACE_PEEKUSER, pid, &dummy->u_debugreg[i], 0); } } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/um/sys-i386/time.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,24 @@ +/* + * sys-i386/time.c + * Created 25.9.2002 Sapan Bhatia + * + */ + +unsigned long long time_stamp(void) +{ + unsigned long low, high; + + asm("rdtsc" : "=a" (low), "=d" (high)); + return((((unsigned long long) high) << 32) + low); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/arch/um/sys-i386/util/Makefile 2003-06-14 12:18:35.000000000 -0700 +++ 25/arch/um/sys-i386/util/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -1,15 +1,10 @@ +host-progs := mk_sc mk_thread +always := $(host-progs) -host-progs := mk_sc -always := $(host-progs) mk_thread -targets := mk_thread_kern.o mk_thread_user.o +mk_thread-objs := mk_thread_kern.o mk_thread_user.o -mk_sc-objs := mk_sc.o - -$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o - $(CC) $(CFLAGS) -o $@ $^ - -$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c - $(CC) $(USER_CFLAGS) -c -o $@ $< +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) clean : $(RM) -f $(build-targets) --- linux-2.6.8-rc1/arch/um/sys-i386/util/mk_sc.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/arch/um/sys-i386/util/mk_sc.c 2004-07-13 17:09:45.000000000 -0700 @@ -38,6 +38,7 @@ int main(int argc, char **argv) SC_OFFSET("SC_ERR", err); SC_OFFSET("SC_CR2", cr2); SC_OFFSET("SC_FPSTATE", fpstate); + SC_OFFSET("SC_SIGMASK", oldmask); SC_FP_OFFSET("SC_FP_CW", cw); SC_FP_OFFSET("SC_FP_SW", sw); SC_FP_OFFSET("SC_FP_TAG", tag); --- linux-2.6.8-rc1/arch/um/sys-ia64/Makefile 2003-06-14 12:17:56.000000000 -0700 +++ 25/arch/um/sys-ia64/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -7,18 +7,5 @@ all: $(OBJ) $(OBJ): $(OBJS) rm -f $@ $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ -clean: - rm -f $(OBJS) -fastdep: - -archmrproper: - -archclean: - rm -f link.ld - @$(MAKEBOOT) clean - -archdep: - @$(MAKEBOOT) dep - -modules: +clean-files := $(OBJS) link.ld --- linux-2.6.8-rc1/arch/um/sys-ppc/Makefile 2003-06-14 12:18:20.000000000 -0700 +++ 25/arch/um/sys-ppc/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -66,13 +66,4 @@ misc.o: misc.S ppc_defs.h $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm -clean: - rm -f $(OBJS) - rm -f ppc_defs.h - rm -f checksum.S semaphore.c mk_defs.c - -fastdep: - -dep: - -modules: +clean-files := $(OBJS) ppc_defs.h checksum.S semaphore.c mk_defs.c --- linux-2.6.8-rc1/arch/um/uml.lds.S 2003-06-14 12:18:09.000000000 -0700 +++ 25/arch/um/uml.lds.S 2004-07-13 17:09:45.000000000 -0700 @@ -9,7 +9,6 @@ SECTIONS { . = START + SIZEOF_HEADERS; - . = ALIGN(4096); __binary_start = .; #ifdef MODE_TT .thread_private : { @@ -26,11 +25,16 @@ SECTIONS . = ALIGN(4096); /* Init code and data */ _stext = .; __init_begin = .; - .text.init : { *(.text.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } . = ALIGN(4096); .text : { *(.text) + SCHED_TEXT /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) @@ -38,7 +42,7 @@ SECTIONS #include "asm/common.lds.S" - .data.init : { *(.data.init) } + init.data : { *(init.data) } .data : { . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ --- linux-2.6.8-rc1/arch/um/util/Makefile 2003-06-14 12:18:51.000000000 -0700 +++ 25/arch/um/util/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -1,23 +1,8 @@ -always := mk_task mk_constants -targets := mk_task_user.o mk_task_kern.o \ - mk_constants_user.o mk_constants_kern.o +host-progs := mk_task mk_constants +always := $(host-progs) -$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o - $(CC) -o $@ $^ +mk_task-objs := mk_task_user.o mk_task_kern.o +mk_constants-objs := mk_constants_user.o mk_constants_kern.o -$(obj)/mk_task_user.o: $(src)/mk_task_user.c - $(CC) -o $@ -c $< - -$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o - $(CC) -o $@ $^ - -$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c - $(CC) -c $< -o $@ - -$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - $(RM) $(build-targets) - -archmrproper: +HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS) --- linux-2.6.8-rc1/arch/um/util/mk_constants_kern.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/arch/um/util/mk_constants_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,6 @@ #include "linux/kernel.h" #include "linux/stringify.h" +#include "linux/time.h" #include "asm/page.h" extern void print_head(void); @@ -11,6 +12,7 @@ int main(int argc, char **argv) { print_head(); print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); + print_constant_str("UM_KERN_EMERG", KERN_EMERG); print_constant_str("UM_KERN_ALERT", KERN_ALERT); print_constant_str("UM_KERN_CRIT", KERN_CRIT); @@ -19,6 +21,8 @@ int main(int argc, char **argv) print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); print_constant_str("UM_KERN_INFO", KERN_INFO); print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); + + print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC); print_tail(); return(0); } --- linux-2.6.8-rc1/arch/x86_64/ia32/ia32entry.S 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/ia32/ia32entry.S 2004-07-13 17:09:34.000000000 -0700 @@ -589,6 +589,12 @@ ia32_sys_call_table: .quad compat_sys_mq_notify .quad compat_sys_mq_getsetattr .quad quiet_ni_syscall /* reserved for kexec */ + .quad sys_perfctr_info + .quad sys_vperfctr_open + .quad sys_vperfctr_control + .quad sys_vperfctr_unlink + .quad sys_vperfctr_iresume + .quad sys_vperfctr_read /* don't forget to change IA32_NR_syscalls */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 --- linux-2.6.8-rc1/arch/x86_64/ia32/ia32_signal.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/ia32/ia32_signal.c 2004-07-13 17:09:13.000000000 -0700 @@ -109,7 +109,7 @@ int ia32_copy_siginfo_from_user(siginfo_ err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(ptr32, &from->si_ptr); - to->si_ptr = (void*)(u64)ptr32; + to->si_ptr = compat_ptr(ptr32); return err; } @@ -146,12 +146,12 @@ sys32_sigaltstack(const stack_ia32_t __u if (uss_ptr) { u32 ptr; memset(&uss,0,sizeof(stack_t)); - if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) || - __get_user(ptr, &uss_ptr->ss_sp) || - __get_user(uss.ss_flags, &uss_ptr->ss_flags) || - __get_user(uss.ss_size, &uss_ptr->ss_size)) - return -EFAULT; - uss.ss_sp = (void *)(u64)ptr; + if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) || + __get_user(ptr, &uss_ptr->ss_sp) || + __get_user(uss.ss_flags, &uss_ptr->ss_flags) || + __get_user(uss.ss_size, &uss_ptr->ss_size)) + return -EFAULT; + uss.ss_sp = compat_ptr(ptr); } seg = get_fs(); set_fs(KERNEL_DS); @@ -448,7 +448,7 @@ void ia32_setup_frame(int sig, struct k_ /* Return stub is in 32bit vsyscall page */ { - void *restorer = VSYSCALL32_SIGRETURN; + void __user *restorer = VSYSCALL32_SIGRETURN; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; err |= __put_user(ptr_to_u32(restorer), &frame->pretcode); @@ -541,7 +541,7 @@ void ia32_setup_rt_frame(int sig, struct { - void *restorer = VSYSCALL32_RTSIGRETURN; + void __user *restorer = VSYSCALL32_RTSIGRETURN; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; err |= __put_user(ptr_to_u32(restorer), &frame->pretcode); --- linux-2.6.8-rc1/arch/x86_64/Kconfig 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/Kconfig 2004-07-13 17:09:34.000000000 -0700 @@ -318,6 +318,8 @@ config X86_MCE bool default y +source "drivers/perfctr/Kconfig" + endmenu @@ -455,6 +457,7 @@ config INIT_DEBUG config DEBUG_INFO bool "Compile the kernel with debug info" depends on DEBUG_KERNEL + default n help If you say Y here the resulting kernel image will include debugging info resulting in a larger kernel image. @@ -493,9 +496,8 @@ config IOMMU_LEAK help Add a simple leak tracer to the IOMMU code. This is useful when you are debugging a buggy device driver that leaks IOMMU mappings. - -#config X86_REMOTE_DEBUG -# bool "kgdb debugging stub" + +source "arch/x86_64/Kconfig.kgdb" endmenu --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/x86_64/Kconfig.kgdb 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,176 @@ +config KGDB + bool "Include kgdb kernel debugger" + depends on DEBUG_KERNEL + select DEBUG_INFO + help + If you say Y here, the system will be compiled with the debug + option (-g) and a debugging stub will be included in the + kernel. This stub communicates with gdb on another (host) + computer via a serial port. The host computer should have + access to the kernel binary file (vmlinux) and a serial port + that is connected to the target machine. Gdb can be made to + configure the serial port or you can use stty and setserial to + do this. See the 'target' command in gdb. This option also + configures in the ability to request a breakpoint early in the + boot process. To request the breakpoint just include 'kgdb' + as a boot option when booting the target machine. The system + will then break as soon as it looks at the boot options. This + option also installs a breakpoint in panic and sends any + kernel faults to the debugger. For more information see the + Documentation/i386/kgdb.txt file. + +choice + depends on KGDB + prompt "Debug serial port BAUD" + default KGDB_115200BAUD + help + Gdb and the kernel stub need to agree on the baud rate to be + used. Some systems (x86 family at this writing) allow this to + be configured. + +config KGDB_9600BAUD + bool "9600" + +config KGDB_19200BAUD + bool "19200" + +config KGDB_38400BAUD + bool "38400" + +config KGDB_57600BAUD + bool "57600" + +config KGDB_115200BAUD + bool "115200" +endchoice + +config KGDB_PORT + hex "hex I/O port address of the debug serial port" + depends on KGDB + default 3f8 + help + Some systems (x86 family at this writing) allow the port + address to be configured. The number entered is assumed to be + hex, don't put 0x in front of it. The standard address are: + COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx + will tell you what you have. It is good to test the serial + connection with a live system before trying to debug. + +config KGDB_IRQ + int "IRQ of the debug serial port" + depends on KGDB + default 4 + help + This is the irq for the debug port. If everything is working + correctly and the kernel has interrupts on a control C to the + port should cause a break into the kernel debug stub. + +config DEBUG_INFO + bool + depends on KGDB + default y + +config KGDB_MORE + bool "Add any additional compile options" + depends on KGDB + default n + help + Saying yes here turns on the ability to enter additional + compile options. + + +config KGDB_OPTIONS + depends on KGDB_MORE + string "Additional compile arguments" + default "-O1" + help + This option allows you enter additional compile options for + the whole kernel compile. Each platform will have a default + that seems right for it. For example on PPC "-ggdb -O1", and + for i386 "-O1". Note that by configuring KGDB "-g" is already + turned on. In addition, on i386 platforms + "-fomit-frame-pointer" is deleted from the standard compile + options. + +config NO_KGDB_CPUS + int "Number of CPUs" + depends on KGDB && SMP + default NR_CPUS + help + + This option sets the number of cpus for kgdb ONLY. It is used + to prune some internal structures so they look "nice" when + displayed with gdb. This is to overcome possibly larger + numbers that may have been entered above. Enter the real + number to get nice clean kgdb_info displays. + +config KGDB_TS + bool "Enable kgdb time stamp macros?" + depends on KGDB + default n + help + Kgdb event macros allow you to instrument your code with calls + to the kgdb event recording function. The event log may be + examined with gdb at a break point. Turning on this + capability also allows you to choose how many events to + keep. Kgdb always keeps the lastest events. + +choice + depends on KGDB_TS + prompt "Max number of time stamps to save?" + default KGDB_TS_128 + +config KGDB_TS_64 + bool "64" + +config KGDB_TS_128 + bool "128" + +config KGDB_TS_256 + bool "256" + +config KGDB_TS_512 + bool "512" + +config KGDB_TS_1024 + bool "1024" + +endchoice + +config STACK_OVERFLOW_TEST + bool "Turn on kernel stack overflow testing?" + depends on KGDB + default n + help + This option enables code in the front line interrupt handlers + to check for kernel stack overflow on interrupts and system + calls. This is part of the kgdb code on x86 systems. + +config KGDB_CONSOLE + bool "Enable serial console thru kgdb port" + depends on KGDB + default n + help + This option enables the command line "console=kgdb" option. + When the system is booted with this option in the command line + all kernel printk output is sent to gdb (as well as to other + consoles). For this to work gdb must be connected. For this + reason, this command line option will generate a breakpoint if + gdb has not yet connected. After the gdb continue command is + given all pent up console output will be printed by gdb on the + host machine. Neither this option, nor KGDB require the + serial driver to be configured. + +config KGDB_SYSRQ + bool "Turn on SysRq 'G' command to do a break?" + depends on KGDB + default y + help + This option includes an option in the SysRq code that allows + you to enter SysRq G which generates a breakpoint to the KGDB + stub. This will work if the keyboard is alive and can + interrupt the system. Because of constraints on when the + serial port interrupt can be enabled, this code may allow you + to interrupt the system before the serial port control C is + available. Just say yes here. + --- linux-2.6.8-rc1/arch/x86_64/kernel/cpufreq/Kconfig 2004-03-10 20:41:26.000000000 -0800 +++ 25/arch/x86_64/kernel/cpufreq/Kconfig 2004-07-13 17:09:21.000000000 -0700 @@ -41,4 +41,9 @@ config X86_POWERNOW_K8 If in doubt, say N. +config X86_POWERNOW_K8_ACPI + bool + depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y")) + default y + endmenu --- linux-2.6.8-rc1/arch/x86_64/kernel/entry.S 2004-05-09 21:07:23.000000000 -0700 +++ 25/arch/x86_64/kernel/entry.S 2004-07-13 17:09:34.000000000 -0700 @@ -297,7 +297,7 @@ int_very_careful: sti SAVE_REST /* Check for syscall exit trace */ - testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),%edx + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx jz int_signal pushq %rdi leaq 8(%rsp),%rdi # &ptregs -> arg1 @@ -557,6 +557,11 @@ ENTRY(spurious_interrupt) apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt #endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PERFCTR) +ENTRY(perfctr_interrupt) + apicinterrupt LOCAL_PERFCTR_VECTOR,smp_perfctr_interrupt +#endif + /* * Exception entry points. */ --- linux-2.6.8-rc1/arch/x86_64/kernel/i8259.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/i8259.c 2004-07-13 17:09:34.000000000 -0700 @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -402,7 +403,7 @@ void __init init_ISA_irqs (void) for (i = 0; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; + irq_desc[i].action = NULL; irq_desc[i].depth = 1; if (i < 16) { @@ -509,6 +510,8 @@ void __init init_IRQ(void) set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); #endif + perfctr_vector_init(); + /* * Set the clock to HZ Hz, we already have a valid * vector now: --- linux-2.6.8-rc1/arch/x86_64/kernel/irq.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/irq.c 2004-07-13 17:09:26.000000000 -0700 @@ -405,6 +405,9 @@ out: spin_unlock(&desc->lock); irq_exit(); + + kgdb_process_breakpoint(); + return 1; } @@ -930,7 +933,7 @@ void init_irq_proc (void) int i; /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", 0); + root_irq_dir = proc_mkdir("irq", NULL); /* create /proc/irq/prof_cpu_mask */ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/x86_64/kernel/kgdb_stub.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,2591 @@ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (c) 2000 VERITAS Software Corporation. + * + */ +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * Updated by: David Grothe + * Updated by: Robert Walsh + * Updated by: wangdi + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Compatibility with 2.1.xx kernel by David Grothe + * + * Changes to allow auto initilization. All that is needed is that it + * be linked with the kernel and a break point (int 3) be executed. + * The header file defines BREAKPOINT to allow one to do + * this. It should also be possible, once the interrupt system is up, to + * call putDebugChar("+"). Once this is done, the remote debugger should + * get our attention by sending a ^C in a packet. George Anzinger + * + * Integrated into 2.2.5 kernel by Tigran Aivazian + * Added thread support, support for multiple processors, + * support for ia-32(x86) hardware debugging. + * Amit S. Kale ( akale@veritas.com ) + * + * Modified to support debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + * X86_64 changes from Andi Kleen's patch merged by Jim Houston + * (jim.houston@ccur.com). If it works thank Andi if its broken + * blame me. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing an int 3. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ +#define KGDB_VERSION "<20030915.1651.33>" +#include +#include +#include /* for strcpy */ +#include +#include +#include +#include /* for linux pt_regs struct */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define Dearly_printk(x...) +int kgdb_enabled = 0; + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*Function) (void); /* pointer to a function */ + +/* Thread reference */ +typedef unsigned char threadref[8]; + +extern int tty_putDebugChar(int); /* write a single character */ +extern int tty_getDebugChar(void); /* read and return a single char */ +extern void tty_flushDebugChar(void); /* flush pending characters */ +extern int eth_putDebugChar(int); /* write a single character */ +extern int eth_getDebugChar(void); /* read and return a single char */ +extern void eth_flushDebugChar(void); /* flush pending characters */ + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +/* Longer buffer is needed to list all threads */ +#define BUFMAX 400 + +char *kgdb_version = KGDB_VERSION; + +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ +int debug_regs = 0; /* set to non-zero to print registers */ + +/* filled in by an external module */ +char *gdb_module_offsets; + +static const char hexchars[] = "0123456789abcdef"; + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * sizeof(unsigned long)) +/* + * Note that this register image is in a different order than + * the register image that Linux produces at interrupt time. + * + * Linux's register image is defined by struct pt_regs in ptrace.h. + * Just why GDB uses a different order is a historical mystery. + * + * Could add XMM and segment registers here. + */ +enum regnames {_RAX, + _RBX, + _RCX, + _RDX, + _RSI, + _RDI, + _RBP, + _RSP, + _R8, + _R9, + _R10, + _R11, + _R12, + _R13, + _R14, + _R15, + _PC, + _PS, + NUMREGS }; + + +/*************************** ASSEMBLY CODE MACROS *************************/ +/* + * Put the error code here just in case the user cares. + * Likewise, the vector number here (since GDB only gets the signal + * number through the usual means, and that's not very specific). + * The called_from is the return address so he can tell how we entered kgdb. + * This will allow him to seperate out the various possible entries. + */ +#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ + +#define PID_MAX PID_MAX_DEFAULT + +#ifdef CONFIG_SMP +void smp_send_nmi_allbutself(void); +#define IF_SMP(x) x +#undef MAX_NO_CPUS +#ifndef CONFIG_NO_KGDB_CPUS +#define CONFIG_NO_KGDB_CPUS 2 +#endif +#if CONFIG_NO_KGDB_CPUS > NR_CPUS +#define MAX_NO_CPUS NR_CPUS +#else +#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS +#endif +#define hold_init hold_on_sstep: 1, +#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) +#define NUM_CPUS num_online_cpus() +#else +#define IF_SMP(x) +#define hold_init +#undef MAX_NO_CPUS +#define MAX_NO_CPUS 1 +#define NUM_CPUS 1 +#endif +#define NOCPU (struct task_struct *)0xbad1fbad +/* *INDENT-OFF* */ +struct kgdb_info { + int used_malloc; + void *called_from; + long long entry_tsc; + int errcode; + int vector; + int print_debug_info; +#ifdef CONFIG_SMP + int hold_on_sstep; + struct { + volatile struct task_struct *task; + int pid; + int hold; + struct pt_regs *regs; + } cpus_waiting[MAX_NO_CPUS]; +#endif +} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; + +/* *INDENT-ON* */ + +#define used_m kgdb_info.used_malloc +/* + * This is little area we set aside to contain the stack we + * need to build to allow gdb to call functions. We use one + * per cpu to avoid locking issues. We will do all this work + * with interrupts off so that should take care of the protection + * issues. + */ +#define LOOKASIDE_SIZE 200 /* should be more than enough */ +#define MALLOC_MAX 200 /* Max malloc size */ +struct { + unsigned long rsp; + unsigned long array[LOOKASIDE_SIZE]; +} fn_call_lookaside[MAX_NO_CPUS]; + +static int trap_cpu; +static unsigned long OLD_esp; + +#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] +#define IF_BIT 0x200 +#define TF_BIT 0x100 + +#define MALLOC_ROUND 8-1 + +static char malloc_array[MALLOC_MAX]; +IF_SMP(static void to_gdb(const char *mess)); +void * +malloc(int size) +{ + + if (size <= (MALLOC_MAX - used_m)) { + int old_used = used_m; + used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); + return &malloc_array[old_used]; + } else { + return NULL; + } +} + +/* + * I/O dispatch functions... + * Based upon kgdboe, either call the ethernet + * handler or the serial one.. + */ +void +putDebugChar(int c) +{ + if (!kgdboe) { + tty_putDebugChar(c); + } else { + eth_putDebugChar(c); + } +} + +int +getDebugChar(void) +{ + if (!kgdboe) { + return tty_getDebugChar(); + } else { + return eth_getDebugChar(); + } +} + +void +flushDebugChar(void) +{ + if (!kgdboe) { + tty_flushDebugChar(); + } else { + eth_flushDebugChar(); + } +} + +/* + * Gdb calls functions by pushing agruments, including a return address + * on the stack and the adjusting EIP to point to the function. The + * whole assumption in GDB is that we are on a different stack than the + * one the "user" i.e. code that hit the break point, is on. This, of + * course is not true in the kernel. Thus various dodges are needed to + * do the call without directly messing with EIP (which we can not change + * as it is just a location and not a register. To adjust it would then + * require that we move every thing below EIP up or down as needed. This + * will not work as we may well have stack relative pointer on the stack + * (such as the pointer to regs, for example). + + * So here is what we do: + * We detect gdb attempting to store into the stack area and instead, store + * into the fn_call_lookaside.array at the same relative location as if it + * were the area ESP pointed at. We also trap ESP modifications + * and uses these to adjust fn_call_lookaside.esp. On entry + * fn_call_lookaside.esp will be set to point at the last entry in + * fn_call_lookaside.array. This allows us to check if it has changed, and + * if so, on exit, we add the registers we will use to do the move and a + * trap/ interrupt return exit sequence. We then adjust the eflags in the + * regs array (remember we now have a copy in the fn_call_lookaside.array) to + * kill the interrupt bit, AND we change EIP to point at our set up stub. + * As part of the register set up we preset the registers to point at the + * begining and end of the fn_call_lookaside.array, so all the stub needs to + * do is move words from the array to the stack until ESP= the desired value + * then do the rti. This will then transfer to the desired function with + * all the correct registers. Nifty huh? + */ +extern asmlinkage void fn_call_stub(void); +extern asmlinkage void fn_rtn_stub(void); +/* *INDENT-OFF* */ +__asm__("fn_rtn_stub:\n\t" + "movq %rax,%rsp\n\t" + "fn_call_stub:\n\t" + "1:\n\t" + "addq $-8,%rbx\n\t" + "movq (%rbx), %rax\n\t" + "pushq %rax\n\t" + "cmpq %rsp,%rcx\n\t" + "jne 1b\n\t" + "popq %rax\n\t" + "popq %rbx\n\t" + "popq %rcx\n\t" + "iret \n\t"); +/* *INDENT-ON* */ +#define gdb_i386vector kgdb_info.vector +#define gdb_i386errcode kgdb_info.errcode +#define waiting_cpus kgdb_info.cpus_waiting +#define remote_debug kgdb_info.print_debug_info +#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold +/* gdb locks */ + +#ifdef CONFIG_SMP +static int in_kgdb_called; +static spinlock_t waitlocks[MAX_NO_CPUS] = + {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; +/* + * The following array has the thread pointer of each of the "other" + * cpus. We make it global so it can be seen by gdb. + */ +volatile int in_kgdb_entry_log[MAX_NO_CPUS]; +volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; +/* +static spinlock_t continuelocks[MAX_NO_CPUS]; +*/ +spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; +/* waiters on our spinlock plus us */ +static atomic_t spinlock_waiters = ATOMIC_INIT(1); +static int spinlock_count = 0; +static int spinlock_cpu = 0; +/* + * Note we use nested spin locks to account for the case where a break + * point is encountered when calling a function by user direction from + * kgdb. Also there is the memory exception recursion to account for. + * Well, yes, but this lets other cpus thru too. Lets add a + * cpu id to the lock. + */ +#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ + spinlock_cpu != smp_processor_id()){\ + atomic_inc(&spinlock_waiters); \ + while (! spin_trylock(x)) {\ + in_kgdb(®s);\ + }\ + atomic_dec(&spinlock_waiters); \ + spinlock_count = 1; \ + spinlock_cpu = smp_processor_id(); \ + }else{ \ + spinlock_count++; \ + } +#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) +#else +unsigned kgdb_spinlock = 0; +#define KGDB_SPIN_LOCK(x) --*x +#define KGDB_SPIN_UNLOCK(x) ++*x +#endif + +int +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ +void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum += hex(getDebugChar() & 0x7f); + if ((remote_debug) && (checksum != xmitcsum)) { + printk + ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum, xmitcsum, buffer); + } + + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + + if (remote_debug) + printk("R:%s\n", buffer); + flushDebugChar(); +} + +/* send the packet in buffer. */ + +void +putpacket(char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + + if (!kgdboe) { + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + + } while ((getDebugChar() & 0x7f) != '+'); + } else { + /* + * For udp, we can not transfer too much bytes once. + * We only transfer MAX_SEND_COUNT size bytes each time + */ + +#define MAX_SEND_COUNT 30 + + int send_count = 0, i = 0; + char send_buf[MAX_SEND_COUNT]; + + do { + if (remote_debug) + printk("T:%s\n", buffer); + putDebugChar('$'); + checksum = 0; + count = 0; + send_count = 0; + while ((ch = buffer[count])) { + if (send_count >= MAX_SEND_COUNT) { + for(i = 0; i < MAX_SEND_COUNT; i++) { + putDebugChar(send_buf[i]); + } + flushDebugChar(); + send_count = 0; + } else { + send_buf[send_count] = ch; + checksum += ch; + count ++; + send_count++; + } + } + for(i = 0; i < send_count; i++) + putDebugChar(send_buf[i]); + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + flushDebugChar(); + } while ((getDebugChar() & 0x7f) != '+'); + } +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; +static char lbuf[BUFMAX]; +static short error; + +void +debug_error(char *format, char *parm) +{ + if (remote_debug) + printk(format, parm); +} + +static void +print_regs(struct pt_regs *regs) +{ + printk("RAX=%016lx RBX=%016lx RCX=%016lx\n", + regs->rax, regs->rbx, regs->rcx); + printk("RDX=%016lx RSI=%016lx RDI=%016lx\n", + regs->rdx, regs->rsi, regs->rdi); + printk("RBP=%016lx PS=%016lx PC=%016lx\n", + regs->rbp, regs->eflags, regs->rip); + printk("R8=%016lx R9=%016lx R10=%016lx\n", + regs->r8, regs->r9, regs->r10); + printk("R11=%016lx R12=%016lx R13=%016lx\n", + regs->r11, regs->r12, regs->r13); + printk("R14=%016lx R15=%016lx RSP=%016lx\n", + regs->r14, regs->r15, regs->rsp); +} + +#define NEW_esp fn_call_lookaside[trap_cpu].rsp + +static void +regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + gdb_regs[_RAX] = regs->rax; + gdb_regs[_RBX] = regs->rbx; + gdb_regs[_RCX] = regs->rcx; + gdb_regs[_RDX] = regs->rdx; + gdb_regs[_RSI] = regs->rsi; + gdb_regs[_RDI] = regs->rdi; + gdb_regs[_RBP] = regs->rbp; + gdb_regs[ _PS] = regs->eflags; + gdb_regs[ _PC] = regs->rip; + gdb_regs[ _R8] = regs->r8; + gdb_regs[ _R9] = regs->r9; + gdb_regs[_R10] = regs->r10; + gdb_regs[_R11] = regs->r11; + gdb_regs[_R12] = regs->r12; + gdb_regs[_R13] = regs->r13; + gdb_regs[_R14] = regs->r14; + gdb_regs[_R15] = regs->r15; + gdb_regs[_RSP] = regs->rsp; + + /* Note, as we are a debugging the kernel, we will always + * trap in kernel code, this means no priviledge change, + * and so the pt_regs structure is not completely valid. In a non + * privilege change trap, only EFLAGS, CS and EIP are put on the stack, + * SS and ESP are not stacked, this means that the last 2 elements of + * pt_regs is not valid (they would normally refer to the user stack) + * also, using regs+1 is no good because you end up will a value that is + * 2 longs (8) too high. This used to cause stepping over functions + * to fail, so my fix is to use the address of regs->esp, which + * should point at the end of the stack frame. Note I have ignored + * completely exceptions that cause an error code to be stacked, such + * as double fault. Stuart Hughes, Zentropix. + * original code: gdb_regs[_ESP] = (int) (regs + 1) ; + + * this is now done on entry and moved to OLD_esp (as well as NEW_esp). + */ +} + +static void +gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + regs->rax = gdb_regs[_RAX] ; + regs->rbx = gdb_regs[_RBX] ; + regs->rcx = gdb_regs[_RCX] ; + regs->rdx = gdb_regs[_RDX] ; + regs->rsi = gdb_regs[_RSI] ; + regs->rdi = gdb_regs[_RDI] ; + regs->rbp = gdb_regs[_RBP] ; + regs->eflags = gdb_regs[ _PS] ; + regs->rip = gdb_regs[ _PC] ; + regs->r8 = gdb_regs[ _R8] ; + regs->r9 = gdb_regs[ _R9] ; + regs->r10 = gdb_regs[ _R10] ; + regs->r11 = gdb_regs[ _R11] ; + regs->r12 = gdb_regs[ _R12] ; + regs->r13 = gdb_regs[ _R13] ; + regs->r14 = gdb_regs[ _R14] ; + regs->r15 = gdb_regs[ _R15] ; + #if 0 /* can't change these */ + regs->rsp = gdb_regs[_RSP] ; + regs->ss = gdb_regs[ _SS] ; + regs->fs = gdb_regs[_FS]; + regs->gs = gdb_regs[_GS]; +#endif +} /* gdb_regs_to_regs */ + +int thread_list = 0; +extern void thread_return(void); + +void +get_gdb_regs(struct task_struct *p, struct pt_regs *regs, unsigned long *gdb_regs) +{ + unsigned long **rbp, *rsp, *rsp0, pc; + int count = 0; + IF_SMP(int i); + if (!p || p == current) { + regs_to_gdb_regs(gdb_regs, regs); + return; + } +#ifdef CONFIG_SMP + for (i = 0; i < MAX_NO_CPUS; i++) { + if (p == kgdb_info.cpus_waiting[i].task) { + regs_to_gdb_regs(gdb_regs, + kgdb_info.cpus_waiting[i].regs); + gdb_regs[_RSP] = + (unsigned long)&kgdb_info.cpus_waiting[i].regs->rsp; + + return; + } + } +#endif + memset(gdb_regs, 0, NUMREGBYTES); + rsp = (unsigned long *)p->thread.rsp; + rbp = (unsigned long **)rsp[0]; + rsp += 2; + gdb_regs[_PC] = (unsigned long)thread_return; + gdb_regs[_RBP] = (unsigned long)rbp; + gdb_regs[_RSP] = (unsigned long)rsp; + +/* + * This code is to give a more informative notion of where a process + * is waiting. It is used only when the user asks for a thread info + * list. If he then switches to the thread, s/he will find the task + * is in schedule, but a back trace should show the same info we come + * up with. This code was shamelessly purloined from process.c. It was + * then enhanced to provide more registers than simply the program + * counter. + */ + + if (!thread_list) { + return; + } + + if (p->state == TASK_RUNNING) + return; + rsp0 = (unsigned long *)p->thread.rsp0; + if (rsp < (unsigned long *) p->thread_info || rsp > rsp0) + return; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + do { + if (*rbp < rsp || *rbp > rsp0) + break; + rbp = (unsigned long **)*rbp; + rsp = (unsigned long *)rbp; + pc = rsp[1]; + + if (!in_sched_functions(pc)) + break; + gdb_regs[_PC] = (unsigned long)pc; + gdb_regs[_RSP] = (unsigned long)rsp; + gdb_regs[_RBP] = (unsigned long)rbp; + } while (count++ < 16); + return; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* returns nonzero if any memory access fails. */ +int mem2hex( char* mem, char* buf, int count) +{ + int i; + unsigned char ch; + int ret = 0; + + for (i=0;i> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (ret) { + Dearly_printk("mem2hex: fault at accessing %p\n", mem); + } + return(ret); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return nonzero if any memory access fails. */ +int hex2mem( char* buf, char* mem, int count) +{ + int i; + unsigned char ch; + int ret = 0; + + for (i=0;i (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { + addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); + } + *addr = val; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +/* If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ +char * +mem2hex(char *mem, char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + /* printk("%lx = ", mem) ; */ + + ch = get_char(mem++); + + /* printk("%02x\n", ch & 0xFF) ; */ + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault fetching from addr %lx\n", + (long) (mem - 1)); + *buf = 0; /* truncate buffer */ + return (buf); + } + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_err_expected = 0; + return (buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +/* NOTE: We use the may fault flag to also indicate if the write is to + * the registers (0) or "other" memory (!=0) + */ +char * +hex2mem(char *buf, char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) { + mem_err_expected = 1; + mem_err = 0; + } + for (i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + set_char(mem++, ch, may_fault); + + if (may_fault && mem_err) { + if (remote_debug) + printk("Mem fault storing to addr %lx\n", + (long) (mem - 1)); + return (mem); + } + } + if (may_fault) + mem_err_expected = 0; + return (mem); +} +#endif + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int +hexToLong(char **ptr, unsigned long *value) +{ + int numChars = 0; + int hexValue; + + *value = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue >= 0) { + *value = (*value << 4) | hexValue; + numChars++; + } else + break; + + (*ptr)++; + } + + return (numChars); +} + +#define stubhex(h) hex(h) +#ifdef old_thread_list + +static int +stub_unpack_int(char *buff, int fieldlength) +{ + int nibble; + int retval = 0; + + while (fieldlength) { + nibble = stubhex(*buff++); + retval |= nibble; + fieldlength--; + if (fieldlength) + retval = retval << 4; + } + return retval; +} +#endif +static char * +pack_hex_byte(char *pkt, int byte) +{ + *pkt++ = hexchars[(byte >> 4) & 0xf]; + *pkt++ = hexchars[(byte & 0xf)]; + return pkt; +} + +#define BUF_THREAD_ID_SIZE 16 + +static char * +pack_threadid(char *pkt, threadref * id) +{ + char *limit; + unsigned char *altid; + + altid = (unsigned char *) id; + limit = pkt + BUF_THREAD_ID_SIZE; + while (pkt < limit) + pkt = pack_hex_byte(pkt, *altid++); + return pkt; +} + +#ifdef old_thread_list +static char * +unpack_byte(char *buf, int *value) +{ + *value = stub_unpack_int(buf, 2); + return buf + 2; +} + +static char * +unpack_threadid(char *inbuf, threadref * id) +{ + char *altref; + char *limit = inbuf + BUF_THREAD_ID_SIZE; + int x, y; + + altref = (char *) id; + + while (inbuf < limit) { + x = stubhex(*inbuf++); + y = stubhex(*inbuf++); + *altref++ = (x << 4) | y; + } + return inbuf; +} +#endif +void +int_to_threadref(threadref * id, int value) +{ + unsigned char *scan; + + scan = (unsigned char *) id; + { + int i = 4; + while (i--) + *scan++ = 0; + } + *scan++ = (value >> 24) & 0xff; + *scan++ = (value >> 16) & 0xff; + *scan++ = (value >> 8) & 0xff; + *scan++ = (value & 0xff); +} +int +int_to_hex_v(unsigned char * id, int value) +{ + unsigned char *start = id; + int shift; + int ch; + + for (shift = 28; shift >= 0; shift -= 4) { + if ((ch = (value >> shift) & 0xf) || (id != start)) { + *id = hexchars[ch]; + id++; + } + } + if (id == start) + *id++ = '0'; + return id - start; +} +#ifdef old_thread_list + +static int +threadref_to_int(threadref * ref) +{ + int i, value = 0; + unsigned char *scan; + + scan = (char *) ref; + scan += 4; + i = 4; + while (i-- > 0) + value = (value << 8) | ((*scan++) & 0xff); + return value; +} +#endif +static int +cmp_str(char *s1, char *s2, int count) +{ + while (count--) { + if (*s1++ != *s2++) + return 0; + } + return 1; +} + +#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ +extern struct task_struct *kgdb_get_idle(int cpu); +#define idle_task(cpu) kgdb_get_idle(cpu) +#else +#define idle_task(cpu) init_tasks[cpu] +#endif + +extern int kgdb_pid_init_done; + +struct task_struct * +getthread(int pid) +{ + struct task_struct *thread; + if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { + if (!cpu_online(pid - PID_MAX)) + return NULL; + + return idle_task(pid - PID_MAX); + } else { + /* + * find_task_by_pid is relatively safe all the time + * Other pid functions require lock downs which imply + * that we may be interrupting them (as we get here + * in the middle of most any lock down). + * Still we don't want to call until the table exists! + */ + if (kgdb_pid_init_done){ + thread = find_task_by_pid(pid); + if (thread) { + return thread; + } + } + } + return NULL; +} +/* *INDENT-OFF* */ +struct hw_breakpoint { + unsigned enabled; + unsigned type; + unsigned len; + unsigned long addr; +} breakinfo[4] = { {enabled:0}, + {enabled:0}, + {enabled:0}, + {enabled:0}}; +/* *INDENT-ON* */ +unsigned long hw_breakpoint_status; +void +correct_hw_break(void) +{ + int breakno; + int correctit; + int breakbit; + unsigned long dr7; + + asm volatile ("movq %%db7, %0\n":"=r" (dr7) + :); + /* *INDENT-OFF* */ + do { + unsigned long addr0, addr1, addr2, addr3; + asm volatile ("movq %%db0, %0\n" + "movq %%db1, %1\n" + "movq %%db2, %2\n" + "movq %%db3, %3\n" + :"=r" (addr0), "=r"(addr1), + "=r"(addr2), "=r"(addr3) + :); + } while (0); + /* *INDENT-ON* */ + correctit = 0; + for (breakno = 0; breakno < 3; breakno++) { + breakbit = 2 << (breakno << 1); + if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { + correctit = 1; + dr7 |= breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + dr7 |= (((breakinfo[breakno].len << 2) | + breakinfo[breakno].type) << 16) << + (breakno << 2); + switch (breakno) { + case 0: + asm volatile ("movq %0, %%dr0\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 1: + asm volatile ("movq %0, %%dr1\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 2: + asm volatile ("movq %0, %%dr2\n"::"r" + (breakinfo[breakno].addr)); + break; + + case 3: + asm volatile ("movq %0, %%dr3\n"::"r" + (breakinfo[breakno].addr)); + break; + } + } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { + correctit = 1; + dr7 &= ~breakbit; + dr7 &= ~(0xf0000 << (breakno << 2)); + } + } + if (correctit) { + asm volatile ("movq %0, %%db7\n"::"r" (dr7)); + } +} + +int +remove_hw_break(unsigned breakno) +{ + if (!breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 0; + return 0; +} + +int +set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) +{ + if (breakinfo[breakno].enabled) { + return -1; + } + breakinfo[breakno].enabled = 1; + breakinfo[breakno].type = type; + breakinfo[breakno].len = len; + breakinfo[breakno].addr = addr; + return 0; +} + +#ifdef CONFIG_SMP +static int in_kgdb_console = 0; + +int +in_kgdb(struct pt_regs *regs) +{ + unsigned long flags; + int cpu; + if (!kgdb_enabled) + return 0; + cpu = smp_processor_id(); + in_kgdb_called = 1; + if (!spin_is_locked(&kgdb_spinlock)) { + if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ + in_kgdb_console) { /* or we are doing slow i/o */ + return 1; + } + return 0; + } + + /* As I see it the only reason not to let all cpus spin on + * the same spin_lock is to allow selected ones to proceed. + * This would be a good thing, so we leave it this way. + * Maybe someday.... Done ! + + * in_kgdb() is called from an NMI so we don't pretend + * to have any resources, like printk() for example. + */ + + local_irq_save(flags); /* only local here, to avoid hanging */ + /* + * log arival of this cpu + * The NMI keeps on ticking. Protect against recurring more + * than once, and ignor the cpu that has the kgdb lock + */ + in_kgdb_entry_log[cpu]++; + in_kgdb_here_log[cpu] = regs; + if (cpu == spinlock_cpu || waiting_cpus[cpu].task) + goto exit_in_kgdb; + + /* + * For protection of the initilization of the spin locks by kgdb + * it locks the kgdb spinlock before it gets the wait locks set + * up. We wait here for the wait lock to be taken. If the + * kgdb lock goes away first?? Well, it could be a slow exit + * sequence where the wait lock is removed prior to the kgdb lock + * so if kgdb gets unlocked, we just exit. + */ + + while (spin_is_locked(&kgdb_spinlock) && + !spin_is_locked(waitlocks + cpu)) ; + if (!spin_is_locked(&kgdb_spinlock)) + goto exit_in_kgdb; + + waiting_cpus[cpu].task = current; + waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); + waiting_cpus[cpu].regs = regs; + + spin_unlock_wait(waitlocks + cpu); + + /* + * log departure of this cpu + */ + waiting_cpus[cpu].task = 0; + waiting_cpus[cpu].pid = 0; + waiting_cpus[cpu].regs = 0; + correct_hw_break(); + exit_in_kgdb: + in_kgdb_here_log[cpu] = 0; + local_irq_restore(flags); + return 1; + /* + spin_unlock(continuelocks + smp_processor_id()); + */ +} + +void +smp__in_kgdb(struct pt_regs regs) +{ + ack_APIC_irq(); + in_kgdb(®s); +} +#else +int +in_kgdb(struct pt_regs *regs) +{ + return (kgdb_spinlock); +} +#endif + +void +printexceptioninfo(int exceptionNo, int errorcode, char *buffer) +{ + unsigned long dr6; + int i; + switch (exceptionNo) { + case 1: /* debug exception */ + break; + case 3: /* breakpoint */ + sprintf(buffer, "Software breakpoint"); + return; + default: + sprintf(buffer, "Details not available"); + return; + } + asm volatile ("movq %%db6, %0\n":"=r" (dr6) + :); + if (dr6 & 0x4000) { + sprintf(buffer, "Single step"); + return; + } + for (i = 0; i < 4; ++i) { + if (dr6 & (1 << i)) { + sprintf(buffer, "Hardware breakpoint %d", i); + return; + } + } + sprintf(buffer, "Unknown trap"); + return; +} + +/* + * The ThreadExtraInfo query allows us to pass an arbitrary string + * for display with the "info threads" command. + */ + +void +print_extra_info(task_t *p, char *buf) +{ + if (!p) { + sprintf(buf, "Invalid thread"); + return; + } + sprintf(buf, "0x%p %8d %4d %c %s", + (void *)p, p->parent->pid, + task_cpu(p), + (p->state == 0) ? (task_curr(p)?'R':'r') : + (p->state < 0) ? 'U' : + (p->state & TASK_UNINTERRUPTIBLE) ? 'D' : + (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' : + (p->state & (TASK_ZOMBIE | TASK_DEAD)) ? 'Z' : + (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?', + p->comm); +} + +/* + * This function does all command procesing for interfacing to gdb. + * + * NOTE: The INT nn instruction leaves the state of the interrupt + * enable flag UNCHANGED. That means that when this routine + * is entered via a breakpoint (INT 3) instruction from code + * that has interrupts enabled, then interrupts will STILL BE + * enabled when this routine is entered. The first thing that + * we do here is disable interrupts so as to prevent recursive + * entries and bothersome serial interrupts while we are + * trying to run the serial port in polled mode. + * + * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so + * it is always necessary to do a restore_flags before returning + * so as to let go of that lock. + */ +int +kgdb_handle_exception(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs) +{ + struct task_struct *usethread = NULL; + struct task_struct *thread_list_start = 0, *thread = NULL; + struct task_struct *p; + unsigned long addr, length; + unsigned long breakno, breaktype; + char *ptr; + unsigned long newPC; + threadref thref; + unsigned long threadid, tmpid; + int thread_min = PID_MAX + MAX_NO_CPUS; +#ifdef old_thread_list + int maxthreads; +#endif + int nothreads; + unsigned long flags; + unsigned long gdb_regs[NUMREGS]; + unsigned long dr6; + IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ +#define NO_NMI 1 +#define NO_SYNC 2 +#define regs (*linux_regs) + /* + * If the entry is not from the kernel then return to the Linux + * trap handler and let it process the interrupt normally. + */ + if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->cs)) { + printk("ignoring non-kernel exception\n"); + print_regs(®s); + return (0); + } + /* + * If we're using eth mode, set the 'mode' in the netdevice. + */ + + if (kgdboe) + netpoll_set_trap(1); + + local_irq_save(flags); + + /* Get kgdb spinlock */ + + KGDB_SPIN_LOCK(&kgdb_spinlock); + rdtscll(kgdb_info.entry_tsc); + /* + * We depend on this spinlock and the NMI watch dog to control the + * other cpus. They will arrive at "in_kgdb()" as a result of the + * NMI and will wait there for the following spin locks to be + * released. + */ +#ifdef CONFIG_SMP + +#if 0 + if (cpu_callout_map & ~MAX_CPU_MASK) { + printk("kgdb : too many cpus, possibly not mapped" + " in contiguous space, change MAX_NO_CPUS" + " in kgdb_stub and make new kernel.\n" + " cpu_callout_map is %lx\n", cpu_callout_map); + goto exit_just_unlock; + } +#endif + if (spinlock_count == 1) { + int time, end_time, dum; + int i; + int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) + }; + if (remote_debug) { + printk("kgdb : cpu %d entry, syncing others\n", + smp_processor_id()); + } + for (i = 0; i < MAX_NO_CPUS; i++) { + /* + * Use trylock as we may already hold the lock if + * we are holding the cpu. Net result is all + * locked. + */ + spin_trylock(&waitlocks[i]); + } + for (i = 0; i < MAX_NO_CPUS; i++) + cpu_logged_in[i] = 0; + /* + * Wait for their arrival. We know the watch dog is active if + * in_kgdb() has ever been called, as it is always called on a + * watchdog tick. + */ + rdtsc(dum, time); + end_time = time + 2; /* Note: we use the High order bits! */ + i = 1; + if (num_online_cpus() > 1) { + int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; + smp_send_nmi_allbutself(); + + while (i < num_online_cpus() && time != end_time) { + int j; + for (j = 0; j < MAX_NO_CPUS; j++) { + if (waiting_cpus[j].task && + waiting_cpus[j].task != NOCPU && + !cpu_logged_in[j]) { + i++; + cpu_logged_in[j] = 1; + if (remote_debug) { + printk + ("kgdb : cpu %d arrived at kgdb\n", + j); + } + break; + } else if (!waiting_cpus[j].task && + !cpu_online(j)) { + waiting_cpus[j].task = NOCPU; + cpu_logged_in[j] = 1; + waiting_cpus[j].hold = 1; + break; + } + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + + int wait = 100000; + while (wait--) ; + if (!waiting_cpus[j].task && + in_kgdb_here_log[j]) { + printk + ("kgdb : cpu %d stall" + " in in_kgdb\n", + j); + i++; + cpu_logged_in[j] = 1; + waiting_cpus[j].task = + (struct task_struct + *) 1; + } + } + } + + if (in_kgdb_entry_log[smp_processor_id()] > + (me_in_kgdb + 10)) { + break; + } + + rdtsc(dum, time); + } + if (i < num_online_cpus()) { + printk + ("kgdb : time out, proceeding without sync\n"); +#if 0 + printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", + waiting_cpus[0].task != 0, + waiting_cpus[1].task != 0); + printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", + cpu_logged_in[0], cpu_logged_in[1]); + printk + ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", + in_kgdb_here_log[0] != 0, + in_kgdb_here_log[1] != 0); +#endif + entry_state = NO_SYNC; + } else { +#if 0 + int ent = + in_kgdb_entry_log[smp_processor_id()] - + me_in_kgdb; + printk("kgdb : sync after %d entries\n", ent); +#endif + } + } else { + if (remote_debug) { + printk + ("kgdb : %d cpus, but watchdog not active\n" + "proceeding without locking down other cpus\n", + (int)num_online_cpus()); + entry_state = NO_NMI; + } + } + } +#endif + + if (remote_debug) { + unsigned long *lp = (unsigned long *) &linux_regs; + + printk("handle_exception(exceptionVector=%d, " + "signo=%d, err_code=%d, linux_regs=%p)\n", + exceptionVector, signo, err_code, linux_regs); + if (debug_regs) { + print_regs(®s); + printk("Stk: %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[0], lp[1], lp[2], lp[3], + lp[4], lp[5], lp[6], lp[7]); + printk(" %8lx %8lx %8lx %8lx" + " %8lx %8lx %8lx %8lx\n", + lp[8], lp[9], lp[10], lp[11], + lp[12], lp[13], lp[14], lp[15]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[16], lp[17], lp[18], lp[19], + lp[20], lp[21], lp[22], lp[23]); + printk(" %8lx %8lx %8lx %8lx " + "%8lx %8lx %8lx %8lx\n", + lp[24], lp[25], lp[26], lp[27], + lp[28], lp[29], lp[30], lp[31]); + } + } + + /* Disable hardware debugging while we are in kgdb */ + /* Get the debug register status register */ +/* *INDENT-OFF* */ + __asm__("movq %0,%%db7" + : /* no output */ + :"r"(0UL)); + + asm volatile ("movq %%db6, %0\n" + :"=r" (hw_breakpoint_status) + :); + +#if 0 +/* *INDENT-ON* */ + switch (exceptionVector) { + case 0: /* divide error */ + case 1: /* debug exception */ + case 2: /* NMI */ + case 3: /* breakpoint */ + case 4: /* overflow */ + case 5: /* bounds check */ + case 6: /* invalid opcode */ + case 7: /* device not available */ + case 8: /* double fault (errcode) */ + case 10: /* invalid TSS (errcode) */ + case 12: /* stack fault (errcode) */ + case 16: /* floating point error */ + case 17: /* alignment check (errcode) */ + default: /* any undocumented */ + break; + case 11: /* segment not present (errcode) */ + case 13: /* general protection (errcode) */ + case 14: /* page fault (special errcode) */ + case 19: /* cache flush denied */ + if (mem_err_expected) { + /* + * This fault occured because of the + * get_char or set_char routines. These + * two routines use either eax of edx to + * indirectly reference the location in + * memory that they are working with. + * For a page fault, when we return the + * instruction will be retried, so we + * have to make sure that these + * registers point to valid memory. + */ + mem_err = 1; /* set mem error flag */ + mem_err_expected = 0; + mem_err_cnt++; /* helps in debugging */ + /* make valid address */ + regs.eax = (long) &garbage_loc; + /* make valid address */ + regs.edx = (long) &garbage_loc; + if (remote_debug) + printk("Return after memory error: " + "mem_err_cnt=%d\n", mem_err_cnt); + if (debug_regs) + print_regs(®s); + goto exit_kgdb; + } + break; + } +#endif + if (remote_debug) + printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); + + gdb_i386vector = exceptionVector; + gdb_i386errcode = err_code; + kgdb_info.called_from = __builtin_return_address(0); +#ifdef CONFIG_SMP + /* + * OK, we can now communicate, lets tell gdb about the sync. + * but only if we had a problem. + */ + switch (entry_state) { + case NO_NMI: + to_gdb("NMI not active, other cpus not stopped\n"); + break; + case NO_SYNC: + to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); + default:; + } + +#endif +/* + * Set up the gdb function call area. + */ + trap_cpu = smp_processor_id(); + OLD_esp = NEW_esp = (unsigned long) (&linux_regs->rsp); + + IF_SMP(once_again:) + /* reply to host that an exception has occurred */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1 == 1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[signo >> 4]; + remcomOutBuffer[2] = hexchars[signo % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + printk("Remote debug %s\n", + remote_debug ? "on" : "off"); + break; + case 'g': /* return the value of the CPU registers */ + get_gdb_regs(usethread, ®s, gdb_regs); + mem2hex((char *) gdb_regs, + remcomOutBuffer, NUMREGBYTES); + break; + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], + (char *) gdb_regs, NUMREGBYTES); + if (!usethread || usethread == current) { + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E00"); + } + break; + + case 'P':{ /* set the value of a single CPU register - + return OK */ + /* + * For some reason, gdb wants to talk about psudo + * registers (greater than 15). + */ + unsigned long regno; + + ptr = &remcomInBuffer[1]; + regs_to_gdb_regs(gdb_regs, ®s); + if ((!usethread || usethread == current) && + hexToLong(&ptr, ®no) && + *ptr++ == '=' && (regno >= 0)) { + if (regno >= NUMREGS) + break; + hex2mem(ptr, (char *) &gdb_regs[regno], + 8); + gdb_regs_to_regs(gdb_regs, ®s); + strcpy(remcomOutBuffer, "OK"); + break; + } + strcpy(remcomOutBuffer, "E01"); + break; + } + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm': + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr) && + (*(ptr++) == ',') && (hexToLong(&ptr, &length))) { + ptr = 0; + /* + * hex doubles the byte count + */ + if (length > (BUFMAX / 2)) + length = BUFMAX / 2; + if (mem2hex((char *) addr, + remcomOutBuffer, length)) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } + } + + if (ptr) { + strcpy(remcomOutBuffer, "E01"); + debug_error + ("malformed read memory command: %s\n", + remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: + Write LLLL bytes at address AA.AA return OK */ + case 'M': + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr) && + (*(ptr++) == ',') && + (hexToLong(&ptr, &length)) && (*(ptr++) == ':')) { + if (hex2mem(ptr, (char *) addr, length)) { + strcpy(remcomOutBuffer, "E03"); + debug_error("memory fault\n", NULL); + } else { + strcpy(remcomOutBuffer, "OK"); + } + + ptr = 0; + } + if (ptr) { + strcpy(remcomOutBuffer, "E02"); + debug_error + ("malformed write memory command: %s\n", + remcomInBuffer); + } + break; + case 'S': + remcomInBuffer[0] = 's'; + case 'C': + /* Csig;AA..AA where ;AA..AA is optional + * continue with signal + * Since signals are meaning less to us, delete that + * part and then fall into the 'c' code. + */ + ptr = &remcomInBuffer[1]; + length = 2; + while (*ptr && *ptr != ';') { + length++; + ptr++; + } + if (*ptr) { + do { + ptr++; + *(ptr - length++) = *ptr; + } while (*ptr); + } else { + remcomInBuffer[1] = 0; + } + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + /* D detach, reply OK and then continue */ + case 'c': + case 's': + case 'D': + + /* try to read optional parameter, + pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToLong(&ptr, &addr)) { + if (remote_debug) + printk("Changing EIP to 0x%lx\n", addr); + + regs.rip = addr; + } + + newPC = regs.rip; + + /* clear the trace bit */ + regs.eflags &= 0xfffffeff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') + regs.eflags |= 0x100; + + /* detach is a friendly version of continue. Note that + debugging is still enabled (e.g hit control C) + */ + if (remcomInBuffer[0] == 'D') { + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + } + + if (remote_debug) { + printk("Resuming execution\n"); + print_regs(®s); + } + asm volatile ("movq %%db6, %0\n":"=r" (dr6) + :); + if (!(dr6 & 0x4000)) { + for (breakno = 0; breakno < 4; ++breakno) { + if (dr6 & (1 << breakno) && + (breakinfo[breakno].type == 0)) { + /* Set restore flag */ + regs.eflags |= 0x10000; + break; + } + } + } + + if (kgdboe) + netpoll_set_trap(0); + + correct_hw_break(); + asm volatile ("movq %0, %%db6\n"::"r" (0UL)); + goto exit_kgdb; + + /* kill the program */ + case 'k': /* do nothing */ + break; + + /* query */ + case 'q': + nothreads = 0; + switch (remcomInBuffer[1]) { + case 'f': + threadid = 1; + thread_list = 2; + thread_list_start = (usethread ? : current); + case 's': + if (!cmp_str(&remcomInBuffer[2], + "ThreadInfo", 10)) + break; + + remcomOutBuffer[nothreads++] = 'm'; + for (; threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + nothreads += int_to_hex_v( + &remcomOutBuffer[ + nothreads], + threadid); + if (thread_min > threadid) + thread_min = threadid; + remcomOutBuffer[ + nothreads] = ','; + nothreads++; + if (nothreads > BUFMAX - 10) + break; + } + } + if (remcomOutBuffer[nothreads - 1] == 'm') { + remcomOutBuffer[nothreads - 1] = 'l'; + } else { + nothreads--; + } + remcomOutBuffer[nothreads] = 0; + break; + +#ifdef old_thread_list /* Old thread info request */ + case 'L': + /* List threads */ + thread_list = 2; + thread_list_start = (usethread ? : current); + unpack_byte(remcomInBuffer + 3, &maxthreads); + unpack_threadid(remcomInBuffer + 5, &thref); + do { + int buf_thread_limit = + (BUFMAX - 22) / BUF_THREAD_ID_SIZE; + if (maxthreads > buf_thread_limit) { + maxthreads = buf_thread_limit; + } + } while (0); + remcomOutBuffer[0] = 'q'; + remcomOutBuffer[1] = 'M'; + remcomOutBuffer[4] = '0'; + pack_threadid(remcomOutBuffer + 5, &thref); + + /* If start flag set start at 0. */ + if (remcomInBuffer[2] == '1') + threadid = 0; + else + threadid = threadref_to_int(&thref); + for (nothreads = 0; + nothreads < maxthreads && + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + thread = getthread(threadid); + if (thread) { + int_to_threadref(&thref, + threadid); + pack_threadid(remcomOutBuffer + + 21 + + nothreads * 16, + &thref); + nothreads++; + if (thread_min > threadid) + thread_min = threadid; + } + } + + if (threadid == PID_MAX + MAX_NO_CPUS) { + remcomOutBuffer[4] = '1'; + } + pack_hex_byte(remcomOutBuffer + 2, nothreads); + remcomOutBuffer[21 + nothreads * 16] = '\0'; + break; +#endif + case 'C': + /* Current thread id */ + remcomOutBuffer[0] = 'Q'; + remcomOutBuffer[1] = 'C'; + threadid = current->pid; + if (!threadid) { + /* + * idle thread + */ + for (threadid = PID_MAX; + threadid < PID_MAX + MAX_NO_CPUS; + threadid++) { + if (current == + idle_task(threadid - + PID_MAX)) + break; + } + } + int_to_threadref(&thref, threadid); + pack_threadid(remcomOutBuffer + 2, &thref); + remcomOutBuffer[18] = '\0'; + break; + + case 'E': + /* Print exception info */ + printexceptioninfo(exceptionVector, + err_code, remcomOutBuffer); + break; + case 'T': + ptr = &remcomInBuffer[0]; + if (strncmp(ptr, "qThreadExtraInfo,", + strlen("qThreadExtraInfo,")) == 0) { + ptr += strlen("qThreadExtraInfo,"); + hexToLong(&ptr, &tmpid); + p = getthread(tmpid); + print_extra_info(p, lbuf); + mem2hex(lbuf, remcomOutBuffer, + strlen(lbuf)); + } + break; +#if 0 + case 'T':{ + char * nptr; + /* Thread extra info */ + if (!cmp_str(&remcomInBuffer[2], + "hreadExtraInfo,", 15)) { + break; + } + ptr = &remcomInBuffer[17]; + hexToLong(&ptr, &threadid); + thread = getthread(threadid); + nptr = &thread->comm[0]; + length = 0; + ptr = &remcomOutBuffer[0]; + do { + length++; + ptr = pack_hex_byte(ptr, *nptr++); + } while (*nptr && length < 16); + /* + * would like that 16 to be the size of + * task_struct.comm but don't know the + * syntax.. + */ + *ptr = 0; + } +#endif + } + break; + + /* task related */ + case 'H': + switch (remcomInBuffer[1]) { + case 'g': + ptr = &remcomInBuffer[2]; + hexToLong(&ptr, &threadid); + thread = getthread(threadid); + if (!thread) { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + break; + } + /* + * Just in case I forget what this is all about, + * the "thread info" command to gdb causes it + * to ask for a thread list. It then switches + * to each thread and asks for the registers. + * For this (and only this) usage, we want to + * fudge the registers of tasks not on the run + * list (i.e. waiting) to show the routine that + * called schedule. Also, gdb, is a minimalist + * in that if the current thread is the last + * it will not re-read the info when done. + * This means that in this case we must show + * the real registers. So here is how we do it: + * Each entry we keep track of the min + * thread in the list (the last that gdb will) + * get info for. We also keep track of the + * starting thread. + * "thread_list" is cleared when switching back + * to the min thread if it is was current, or + * if it was not current, thread_list is set + * to 1. When the switch to current comes, + * if thread_list is 1, clear it, else do + * nothing. + */ + usethread = thread; + if ((thread_list == 1) && + (thread == thread_list_start)) { + thread_list = 0; + } + if (thread_list && (threadid == thread_min)) { + if (thread == thread_list_start) { + thread_list = 0; + } else { + thread_list = 1; + } + } + /* follow through */ + case 'c': + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + break; + } + break; + + /* Query thread status */ + case 'T': + ptr = &remcomInBuffer[1]; + hexToLong(&ptr, &threadid); + thread = getthread(threadid); + if (thread) { + remcomOutBuffer[0] = 'O'; + remcomOutBuffer[1] = 'K'; + remcomOutBuffer[2] = '\0'; + if (thread_min > threadid) + thread_min = threadid; + } else { + remcomOutBuffer[0] = 'E'; + remcomOutBuffer[1] = '\0'; + } + break; + + case 'Y': /* set up a hardware breakpoint */ + ptr = &remcomInBuffer[1]; + hexToLong(&ptr, &breakno); + ptr++; + hexToLong(&ptr, &breaktype); + ptr++; + hexToLong(&ptr, &length); + ptr++; + hexToLong(&ptr, &addr); + if (set_hw_break(breakno & 0x3, + breaktype & 0x3, + length & 0x3, addr) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + /* Remove hardware breakpoint */ + case 'y': + ptr = &remcomInBuffer[1]; + hexToLong(&ptr, &breakno); + if (remove_hw_break(breakno & 0x3) == 0) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "ERROR"); + } + break; + + case 'r': /* reboot */ + strcpy(remcomOutBuffer, "OK"); + putpacket(remcomOutBuffer); + /*to_gdb("Rebooting\n"); */ + /* triplefault no return from here */ + { + static long no_idt[2]; + __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); + BREAKPOINT; + } + + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1==1) */ + /* + * reached by goto only. + */ + exit_kgdb: + /* + * Here is where we set up to trap a gdb function call. NEW_esp + * will be changed if we are trying to do this. We handle both + * adding and subtracting, thus allowing gdb to put grung on + * the stack which it removes later. + */ + if (NEW_esp != OLD_esp) { + unsigned long *ptr = END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) + ptr -= (OLD_esp - NEW_esp) / sizeof (unsigned long); + *--ptr = linux_regs->eflags; + *--ptr = linux_regs->cs; + *--ptr = linux_regs->rip; + *--ptr = linux_regs->rcx; + *--ptr = linux_regs->rbx; + *--ptr = linux_regs->rax; + linux_regs->rcx = NEW_esp - (sizeof (unsigned long) * 6); + linux_regs->rbx = (unsigned long) END_OF_LOOKASIDE; + if (NEW_esp < OLD_esp) { + linux_regs->rip = (unsigned long) fn_call_stub; + } else { + linux_regs->rip = (unsigned long) fn_rtn_stub; + linux_regs->rax = NEW_esp; + } + linux_regs->eflags &= ~(IF_BIT | TF_BIT); + } +#ifdef CONFIG_SMP + /* + * Release gdb wait locks + * Sanity check time. Must have at least one cpu to run. Also single + * step must not be done if the current cpu is on hold. + */ + if (spinlock_count == 1) { + int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; + int cpu_avail = 0; + int i; + + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!cpu_online(i)) + break; + if (!hold_cpu(i)) { + cpu_avail = 1; + } + } + /* + * Early in the bring up there will be NO cpus on line... + */ + if (!cpu_avail && !cpus_empty(cpu_online_map)) { + to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); + goto once_again; + } + if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { + to_gdb + ("Current cpu must be unblocked to single step\n"); + goto once_again; + } + if (!(ss_hold)) { + int i; + for (i = 0; i < MAX_NO_CPUS; i++) { + if (!hold_cpu(i)) { + spin_unlock(&waitlocks[i]); + } + } + } else { + spin_unlock(&waitlocks[smp_processor_id()]); + } + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + /* + * If this cpu is on hold, this is where we + * do it. Note, the NMI will pull us out of here, + * but will return as the above lock is not held. + * We will stay here till another cpu releases the lock for us. + */ + spin_unlock_wait(waitlocks + smp_processor_id()); + local_irq_restore(flags); + return (1); + } +#if 0 +exit_just_unlock: +#endif +#endif + /* Release kgdb spinlock */ + KGDB_SPIN_UNLOCK(&kgdb_spinlock); + local_irq_restore(flags); + return (1); +} + +#undef regs +static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) +{ + struct die_args *d = ptr; + + if (!kgdb_enabled || (cmd == DIE_DEBUG && user_mode(d->regs))) + return NOTIFY_DONE; + if (cmd == DIE_NMI_IPI) { + if (in_kgdb(d->regs)) + return NOTIFY_BAD; + } else if (kgdb_handle_exception(d->trapnr, d->signr, d->err, d->regs)) + return NOTIFY_BAD; /* skip */ + + return NOTIFY_DONE; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, + .priority = 0, +}; + +void set_debug_traps(void) +{ + static int initialized = 0; + + if (!initialized) { + initialized = 1; + notifier_chain_register(&die_chain, &kgdb_notifier); + } +} + +/* + * Provide the command line "gdb" initial break + */ +int __init kgdb_initial_break(char * str) +{ + if (*str == '\0'){ + breakpoint(); + return 1; + } + return 0; +} +__setup("gdb",kgdb_initial_break); + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ +/* But really, just use the BREAKPOINT macro. We will handle the int stuff + */ + +void breakpoint(void) +{ + + set_debug_traps(); + kgdb_enabled = 1; +#if 0 + /* + * These calls were not enough to allow breakpoint to be + * called before trap_init(). I moved the argument parsing + * after trap_init() and it seems to work. + */ + set_intr_usr_gate(3,&int3); /* disable ints on trap */ + set_intr_gate(1,&debug); + set_intr_gate(14,&page_fault); +#endif + + BREAKPOINT; +} + +#ifdef later +/* + * possibly we should not go thru the traps.c code at all? Someday. + */ +void +do_kgdb_int3(struct pt_regs *regs, long error_code) +{ + kgdb_handle_exception(3, 5, error_code, regs); + return; +} +#endif +#undef regs +#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS +asmlinkage void +bad_sys_call_exit(int stuff) +{ + struct pt_regs *regs = (struct pt_regs *) &stuff; + printk("Sys call %d return with %x preempt_count\n", + (int) regs->orig_eax, preempt_count()); +} +#endif +#ifdef CONFIG_STACK_OVERFLOW_TEST +#include +asmlinkage void +stack_overflow(void) +{ +#ifdef BREAKPOINT + BREAKPOINT; +#else + printk("Kernel stack overflow, looping forever\n"); +#endif + while (1) { + } +} +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) +char gdbconbuf[BUFMAX]; + +static void +kgdb_gdb_message(const char *s, unsigned count) +{ + int i; + int wcount; + char *bufptr; + /* + * This takes care of NMI while spining out chars to gdb + */ + IF_SMP(in_kgdb_console = 1); + gdbconbuf[0] = 'O'; + bufptr = gdbconbuf + 1; + while (count > 0) { + if ((count << 1) > (BUFMAX - 2)) { + wcount = (BUFMAX - 2) >> 1; + } else { + wcount = count; + } + count -= wcount; + for (i = 0; i < wcount; i++) { + bufptr = pack_hex_byte(bufptr, s[i]); + } + *bufptr = '\0'; + s += wcount; + + putpacket(gdbconbuf); + + } + IF_SMP(in_kgdb_console = 0); +} +#endif +#ifdef CONFIG_SMP +static void +to_gdb(const char *s) +{ + int count = 0; + while (s[count] && (count++ < BUFMAX)) ; + kgdb_gdb_message(s, count); +} +#endif +#ifdef CONFIG_KGDB_CONSOLE +#include +#include +#include +#include + +void +kgdb_console_write(struct console *co, const char *s, unsigned count) +{ + + if (gdb_i386vector == -1) { + /* + * We have not yet talked to gdb. What to do... + * lets break, on continue we can do the write. + * But first tell him whats up. Uh, well no can do, + * as this IS the console. Oh well... + * We do need to wait or the messages will be lost. + * Other option would be to tell the above code to + * ignore this breakpoint and do an auto return, + * but that might confuse gdb. Also this happens + * early enough in boot up that we don't have the traps + * set up yet, so... + */ + breakpoint(); + } + kgdb_gdb_message(s, count); +} + +/* + * ------------------------------------------------------------ + * Serial KGDB driver + * ------------------------------------------------------------ + */ + +static struct console kgdbcons = { + name:"kgdb", + write:kgdb_console_write, +#ifdef CONFIG_KGDB_USER_CONSOLE + device:kgdb_console_device, +#endif + flags:CON_PRINTBUFFER | CON_ENABLED, + index:-1, +}; + +/* + * The trick here is that this file gets linked before printk.o + * That means we get to peer at the console info in the command + * line before it does. If we are up, we register, otherwise, + * do nothing. By returning 0, we allow printk to look also. + */ +static int kgdb_console_enabled; + +int __init +kgdb_console_init(char *str) +{ + if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { + register_console(&kgdbcons); + kgdb_console_enabled = 1; + } + return 0; /* let others look at the string */ +} + +__setup("console=", kgdb_console_init); + +#ifdef CONFIG_KGDB_USER_CONSOLE +static kdev_t kgdb_console_device(struct console *c); +/* This stuff sort of works, but it knocks out telnet devices + * we are leaving it here in case we (or you) find time to figure it out + * better.. + */ + +/* + * We need a real char device as well for when the console is opened for user + * space activities. + */ + +static int +kgdb_consdev_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t +kgdb_consdev_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + int size, ret = 0; + static char kbuf[128]; + static DECLARE_MUTEX(sem); + + /* We are not reentrant... */ + if (down_interruptible(&sem)) + return -ERESTARTSYS; + + while (count > 0) { + /* need to copy the data from user space */ + size = count; + if (size > sizeof (kbuf)) + size = sizeof (kbuf); + if (copy_from_user(kbuf, buf, size)) { + ret = -EFAULT; + break;; + } + kgdb_console_write(&kgdbcons, kbuf, size); + count -= size; + ret += size; + buf += size; + } + + up(&sem); + + return ret; +} + +struct file_operations kgdb_consdev_fops = { + open:kgdb_consdev_open, + write:kgdb_consdev_write +}; +static kdev_t +kgdb_console_device(struct console *c) +{ + return MKDEV(TTYAUX_MAJOR, 1); +} + +/* + * This routine gets called from the serial stub in the i386/lib + * This is so it is done late in bring up (just before the console open). + */ +void +kgdb_console_finit(void) +{ + if (kgdb_console_enabled) { + char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); + char *cp = cptr; + while (*cptr && *cptr != '(') + cptr++; + *cptr = 0; + unregister_chrdev(TTYAUX_MAJOR, cp); + register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); + } +} +#endif +#endif +#ifdef CONFIG_KGDB_TS +#include /* time stamp code */ +#include /* in_interrupt */ +#ifdef CONFIG_KGDB_TS_64 +#define DATA_POINTS 64 +#endif +#ifdef CONFIG_KGDB_TS_128 +#define DATA_POINTS 128 +#endif +#ifdef CONFIG_KGDB_TS_256 +#define DATA_POINTS 256 +#endif +#ifdef CONFIG_KGDB_TS_512 +#define DATA_POINTS 512 +#endif +#ifdef CONFIG_KGDB_TS_1024 +#define DATA_POINTS 1024 +#endif +#ifndef DATA_POINTS +#define DATA_POINTS 128 /* must be a power of two */ +#endif +#define INDEX_MASK (DATA_POINTS - 1) +#if (INDEX_MASK & DATA_POINTS) +#error "CONFIG_KGDB_TS_COUNT must be a power of 2" +#endif +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + int data0; + int data1; +}; +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + struct task_struct *task; + long long at_time; + int from_ln; + char *in_src; + void *from; + int *with_shpf; + struct task_struct *t1; + struct task_struct *t2; +}; +struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; + +struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; +int kgdb_and_then_count; + +void +kgdb_tstamp(int line, char *source, int data0, int data1) +{ + static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; + unsigned long flags; + + local_irq_save(flags); + spin_lock(&ts_spin); + rdtscll(kgdb_and_then->at_time); +#ifdef CONFIG_SMP + kgdb_and_then->on_cpu = smp_processor_id(); +#endif + kgdb_and_then->task = current; + kgdb_and_then->from_ln = line; + kgdb_and_then->in_src = source; + kgdb_and_then->from = __builtin_return_address(0); + kgdb_and_then->with_shpf = (int *)(long)(((flags & IF_BIT) >> 9) | + (preempt_count() << 8)); + kgdb_and_then->data0 = data0; + kgdb_and_then->data1 = data1; + kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; + spin_unlock(&ts_spin); + local_irq_restore(flags); +#ifdef CONFIG_PREEMPT + +#endif + return; +} +#endif +typedef int gdb_debug_hook(int exceptionVector, + int signo, int err_code, struct pt_regs *linux_regs); +gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ + +static int kgdb_need_breakpoint[NR_CPUS]; + +void kgdb_schedule_breakpoint(void) +{ + kgdb_need_breakpoint[smp_processor_id()] = 1; +} + +void kgdb_process_breakpoint(void) +{ + /* + * Handle a breakpoint queued from inside network driver code + * to avoid reentrancy issues + */ + if (kgdb_need_breakpoint[smp_processor_id()]) { + kgdb_need_breakpoint[smp_processor_id()] = 0; + kgdb_enabled = 1; + BREAKPOINT; + } +} + --- linux-2.6.8-rc1/arch/x86_64/kernel/ldt.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/kernel/ldt.c 2004-07-13 17:09:13.000000000 -0700 @@ -66,7 +66,7 @@ static int alloc_ldt(mm_context_t *pc, u mask = cpumask_of_cpu(smp_processor_id()); load_LDT(pc); if (!cpus_equal(current->mm->cpu_vm_mask, mask)) - smp_call_function(flush_ldt, 0, 1, 1); + smp_call_function(flush_ldt, NULL, 1, 1); preempt_enable(); #else load_LDT(pc); --- linux-2.6.8-rc1/arch/x86_64/kernel/Makefile 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/kernel/Makefile 2004-07-13 17:09:26.000000000 -0700 @@ -28,6 +28,7 @@ obj-$(CONFIG_SWIOTLB) += swiotlb.o obj-$(CONFIG_SCHED_SMT) += domain.o obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_KGDB) += kgdb_stub.o obj-y += topology.o --- linux-2.6.8-rc1/arch/x86_64/kernel/pci-gart.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/pci-gart.c 2004-07-13 17:09:13.000000000 -0700 @@ -255,7 +255,7 @@ void pci_free_consistent(struct pci_dev #define SET_LEAK(x) if (iommu_leak_tab) \ iommu_leak_tab[x] = __builtin_return_address(0); #define CLEAR_LEAK(x) if (iommu_leak_tab) \ - iommu_leak_tab[x] = 0; + iommu_leak_tab[x] = NULL; /* Debugging aid for drivers that don't free their IOMMU tables */ static void **iommu_leak_tab; --- linux-2.6.8-rc1/arch/x86_64/kernel/process.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/kernel/process.c 2004-07-13 17:09:34.000000000 -0700 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -262,6 +263,7 @@ void exit_thread(void) tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; put_cpu(); } + perfctr_exit_thread(&me->thread); } void flush_thread(void) @@ -365,6 +367,8 @@ int copy_thread(int nr, unsigned long cl asm("movl %%es,%0" : "=m" (p->thread.es)); asm("movl %%ds,%0" : "=m" (p->thread.ds)); + perfctr_copy_thread(&p->thread); + if (unlikely(me->thread.io_bitmap_ptr != NULL)) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); if (!p->thread.io_bitmap_ptr) @@ -411,6 +415,8 @@ struct task_struct *__switch_to(struct t int cpu = smp_processor_id(); struct tss_struct *tss = init_tss + cpu; + perfctr_suspend_thread(prev); + unlazy_fpu(prev_p); /* @@ -514,6 +520,8 @@ struct task_struct *__switch_to(struct t } } + perfctr_resume_thread(next); + return prev_p; } --- linux-2.6.8-rc1/arch/x86_64/kernel/ptrace.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/kernel/ptrace.c 2004-07-13 17:09:30.000000000 -0700 @@ -88,6 +88,9 @@ void ptrace_disable(struct task_struct * { long tmp; +#ifdef CONFIG_IA32_EMULATION + clear_tsk_thread_flag(child, TIF_SINGLESTEP); +#endif tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); } @@ -344,6 +347,9 @@ asmlinkage long sys_ptrace(long request, set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); +#ifdef CONFIG_IA32_EMULATION + clear_tsk_thread_flag(child, TIF_SINGLESTEP); +#endif child->exit_code = data; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET); @@ -395,6 +401,9 @@ asmlinkage long sys_ptrace(long request, ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ break; +#ifdef CONFIG_IA32_EMULATION + clear_tsk_thread_flag(child, TIF_SINGLESTEP); +#endif child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; @@ -416,6 +425,10 @@ asmlinkage long sys_ptrace(long request, } tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); +#ifdef CONFIG_IA32_EMULATION + if (test_tsk_thread_flag(child, TIF_IA32)) + set_tsk_thread_flag(child, TIF_SINGLESTEP); +#endif child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -528,7 +541,10 @@ asmlinkage void syscall_trace_leave(stru if (unlikely(current->audit_context)) audit_syscall_exit(current, regs->rax); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) + if ((test_thread_flag(TIF_SYSCALL_TRACE) +#ifdef CONFIG_IA32_EMULATION + || test_thread_flag(TIF_SINGLESTEP) +#endif + ) && (current->ptrace & PT_PTRACED)) syscall_trace(regs); } --- linux-2.6.8-rc1/arch/x86_64/kernel/signal.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/kernel/signal.c 2004-07-13 17:35:40.000000000 -0700 @@ -92,6 +92,7 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax) { unsigned int err = 0; + unsigned int caller_eflags; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -112,6 +113,7 @@ restore_sigcontext(struct pt_regs *regs, { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); + caller_eflags = regs->eflags; regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_rax = -1; /* disable syscall checks */ } @@ -128,6 +130,22 @@ restore_sigcontext(struct pt_regs *regs, } err |= __get_user(*prax, &sc->rax); + + if (!err && unlikely(caller_eflags & X86_EFLAGS_TF) && + (current->ptrace & (PT_PTRACED|PT_DTRACE)) == (PT_PTRACED|PT_DTRACE)) { + /* + * If ptrace single-stepped into the sigreturn system call, + * then fake a single-step trap before we resume the restored + * context. + */ + siginfo_t info; + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)regs->rip; + force_sig_info(SIGTRAP, &info, current); + } + return err; badframe: --- linux-2.6.8-rc1/arch/x86_64/kernel/smpboot.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/smpboot.c 2004-07-13 17:09:36.000000000 -0700 @@ -576,15 +576,12 @@ static void __init do_boot_cpu (int apic idle = fork_by_hand(); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); - wake_up_forked_process(idle); x86_cpu_to_apicid[cpu] = apicid; - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ + /* Make this the idle thread */ init_idle(idle,cpu); + /* Remove it from the pidhash */ unhash_process(idle); cpu_pda[cpu].pcurrent = idle; --- linux-2.6.8-rc1/arch/x86_64/kernel/smp.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/smp.c 2004-07-13 17:09:26.000000000 -0700 @@ -343,7 +343,7 @@ static void do_flush_tlb_all(void* info) void flush_tlb_all(void) { - on_each_cpu(do_flush_tlb_all, 0, 1, 1); + on_each_cpu(do_flush_tlb_all, NULL, 1, 1); } void smp_kdb_stop(void) @@ -362,6 +362,18 @@ void smp_send_reschedule(int cpu) send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); } +#ifdef CONFIG_KGDB +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} +#endif + /* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. --- linux-2.6.8-rc1/arch/x86_64/kernel/traps.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/arch/x86_64/kernel/traps.c 2004-07-13 17:09:26.000000000 -0700 @@ -45,6 +45,9 @@ #include #include +#ifdef CONFIG_KGDB +#include +#endif extern struct gate_struct idt_table[256]; @@ -115,7 +118,7 @@ unsigned long *in_exception_stack(int cp if (stack >= init_tss[cpu].ist[k] && stack <= end) return (unsigned long *)end; } - return 0; + return NULL; } /* @@ -448,7 +451,7 @@ asmlinkage void do_##name(struct pt_regs info.si_signo = signr; \ info.si_errno = 0; \ info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ + info.si_addr = (void __user *)siaddr; \ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ return; \ do_trap(trapnr, signr, str, regs, error_code, &info); \ @@ -662,7 +665,7 @@ asmlinkage void *do_debug(struct pt_regs if ((regs->cs & 3) == 0) goto clear_dr7; - info.si_addr = (void *)regs->rip; + info.si_addr = (void __user *)regs->rip; force_sig_info(SIGTRAP, &info, tsk); clear_dr7: asm volatile("movq %0,%%db7"::"r"(0UL)); @@ -686,7 +689,7 @@ clear_TF: * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ -void math_error(void *rip) +void math_error(void __user *rip) { struct task_struct * task; siginfo_t info; @@ -743,7 +746,7 @@ void math_error(void *rip) asmlinkage void do_coprocessor_error(struct pt_regs * regs) { conditional_sti(regs); - math_error((void *)regs->rip); + math_error((void __user *)regs->rip); } asmlinkage void bad_intr(void) @@ -751,7 +754,7 @@ asmlinkage void bad_intr(void) printk("bad interrupt"); } -static inline void simd_math_error(void *rip) +static inline void simd_math_error(void __user *rip) { struct task_struct * task; siginfo_t info; @@ -802,7 +805,7 @@ static inline void simd_math_error(void asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs) { conditional_sti(regs); - simd_math_error((void *)regs->rip); + simd_math_error((void __user *)regs->rip); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/arch/x86_64/lib/kgdb_serial.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,490 @@ +/* + * Serial interface GDB stub + * + * Written (hacked together) by David Grothe (dave@gcom.com) + * Modified to allow invokation early in boot see also + * kgdb.h for instructions by George Anzinger(george@mvista.com) + * Modified to handle debugging over ethernet by Robert Walsh + * and wangdi , based on + * code by San Mehat. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_KGDB_USER_CONSOLE +extern void kgdb_console_finit(void); +#endif +#define PRNT_off +#define TEST_EXISTANCE +#ifdef PRNT +#define dbprintk(s) printk s +#else +#define dbprintk(s) +#endif +#define TEST_INTERRUPT_off +#ifdef TEST_INTERRUPT +#define intprintk(s) printk s +#else +#define intprintk(s) +#endif + +#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + +static char gdb_buf[GDB_BUF_SIZE]; +static int gdb_buf_in_inx; +static atomic_t gdb_buf_in_cnt; +static int gdb_buf_out_inx; + +struct async_struct *gdb_async_info; +static int gdb_async_irq; + +#define outb_px(a,b) outb_p(b,a) + +static void program_uart(struct async_struct *info); +static void write_char(struct async_struct *info, int chr); +/* + * Get a byte from the hardware data buffer and return it + */ +static int +read_data_bfr(struct async_struct *info) +{ + char it = inb_p(info->port + UART_LSR); + + if (it & UART_LSR_DR) + return (inb_p(info->port + UART_RX)); + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (it & 0xc) { + program_uart(info); + write_char(info, '-'); + return ('-'); + } + return (-1); + +} /* read_data_bfr */ + +/* + * Get a char if available, return -1 if nothing available. + * Empty the receive buffer first, then look at the interface hardware. + + * Locking here is a bit of a problem. We MUST not lock out communication + * if we are trying to talk to gdb about a kgdb entry. ON the other hand + * we can loose chars in the console pass thru if we don't lock. It is also + * possible that we could hold the lock or be waiting for it when kgdb + * NEEDS to talk. Since kgdb locks down the world, it does not need locks. + * We do, of course have possible issues with interrupting a uart operation, + * but we will just depend on the uart status to help keep that straight. + + */ +static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SMP +extern spinlock_t kgdb_spinlock; +#endif + +static int +read_char(struct async_struct *info) +{ + int chr; + unsigned long flags; + local_irq_save(flags); +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_lock(&uart_interrupt_lock); + } +#endif + if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ + chr = gdb_buf[gdb_buf_out_inx++]; + gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); + atomic_dec(&gdb_buf_in_cnt); + } else { + chr = read_data_bfr(info); + } +#ifdef CONFIG_SMP + if (!spin_is_locked(&kgdb_spinlock)) { + spin_unlock(&uart_interrupt_lock); + } +#endif + local_irq_restore(flags); + return (chr); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +write_char(struct async_struct *info, int chr) +{ + while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; + + outb_p(chr, info->port + UART_TX); + +} /* write_char */ + +/* + * Mostly we don't need a spinlock, but since the console goes + * thru here with interrutps on, well, we need to catch those + * chars. + */ +/* + * This is the receiver interrupt routine for the GDB stub. + * It will receive a limited number of characters of input + * from the gdb host machine and save them up in a buffer. + * + * When the gdb stub routine tty_getDebugChar() is called it + * draws characters out of the buffer until it is empty and + * then reads directly from the serial port. + * + * We do not attempt to write chars from the interrupt routine + * since the stubs do all of that via tty_putDebugChar() which + * writes one byte after waiting for the interface to become + * ready. + * + * The debug stubs like to run with interrupts disabled since, + * after all, they run as a consequence of a breakpoint in + * the kernel. + * + * Perhaps someone who knows more about the tty driver than I + * care to learn can make this work for any low level serial + * driver. + */ +static irqreturn_t +gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct async_struct *info; + unsigned long flags; + + info = gdb_async_info; + if (!info || !info->tty || irq != gdb_async_irq) + return IRQ_NONE; + + local_irq_save(flags); + spin_lock(&uart_interrupt_lock); + do { + int chr = read_data_bfr(info); + intprintk(("Debug char on int: %x hex\n", chr)); + if (chr < 0) + continue; + + if (chr == 3) { /* Ctrl-C means remote interrupt */ + BREAKPOINT; + continue; + } + + if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { + /* buffer overflow tosses early char */ + read_char(info); + } + gdb_buf[gdb_buf_in_inx++] = chr; + gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); + } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); + spin_unlock(&uart_interrupt_lock); + local_irq_restore(flags); + return IRQ_HANDLED; +} /* gdb_interrupt */ + +/* + * Just a NULL routine for testing. + */ +void +gdb_null(void) +{ +} /* gdb_null */ + +/* These structure are filled in with values defined in asm/kgdb_local.h + */ +static struct serial_state state = SB_STATE; +static struct async_struct local_info = SB_INFO; +static int ok_to_enable_ints = 0; +static void kgdb_enable_ints_now(void); + +extern char *kgdb_version; +/* + * Hook an IRQ for KGDB. + * + * This routine is called from tty_putDebugChar, below. + */ +static int ints_disabled = 1; +int +gdb_hook_interrupt(struct async_struct *info, int verb) +{ + struct serial_state *state = info->state; + unsigned long flags; + int port; +#ifdef TEST_EXISTANCE + int scratch, scratch2; +#endif + + /* The above fails if memory managment is not set up yet. + * Rather than fail the set up, just keep track of the fact + * and pick up the interrupt thing later. + */ + gdb_async_info = info; + port = gdb_async_info->port; + gdb_async_irq = state->irq; + if (verb) { + printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", + kgdb_version, + port, + gdb_async_irq, gdb_async_info->state->custom_divisor); + } + local_irq_save(flags); +#ifdef TEST_EXISTANCE + /* Existance test */ + /* Should not need all this, but just in case.... */ + + scratch = inb_p(port + UART_IER); + outb_px(port + UART_IER, 0); + outb_px(0xff, 0x080); + scratch2 = inb_p(port + UART_IER); + outb_px(port + UART_IER, scratch); + if (scratch2) { + printk + ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); + local_irq_restore(flags); + return 1; /* We failed; there's nothing here */ + } + scratch2 = inb_p(port + UART_LCR); + outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ + outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ + outb_px(port + UART_LCR, 0); + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = inb_p(port + UART_IIR) >> 6; + if (scratch == 1) { + printk("gdb_hook_interrupt: Undefined UART type!" + " Not a UART! \n"); + local_irq_restore(flags); + return 1; + } else { + dbprintk(("gdb_hook_interrupt: UART type " + "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); + } + scratch = inb_p(port + UART_MCR); + outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); + outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); + scratch2 = inb_p(port + UART_MSR) & 0xF0; + outb_px(port + UART_MCR, scratch); + if (scratch2 != 0x90) { + printk("gdb_hook_interrupt: " + "Loop back test failed! Not a UART!\n"); + local_irq_restore(flags); + return scratch2 + 1000; /* force 0 to fail */ + } +#endif /* test existance */ + program_uart(info); + local_irq_restore(flags); + + return (0); + +} /* gdb_hook_interrupt */ + +static void +program_uart(struct async_struct *info) +{ + int port = info->port; + + (void) inb_p(port + UART_RX); + outb_px(port + UART_IER, 0); + + (void) inb_p(port + UART_RX); /* serial driver comments say */ + (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ + (void) inb_p(port + UART_MSR); + outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ + outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ + outb_px(port + UART_MCR, info->MCR); + + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ + outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + return; +} + +/* + * tty_getDebugChar + * + * This is a GDB stub routine. It waits for a character from the + * serial interface and then returns it. If there is no serial + * interface connection then it returns a bogus value which will + * almost certainly cause the system to hang. In the + */ +int kgdb_in_isr = 0; +int kgdb_in_lsr = 0; +extern spinlock_t kgdb_spinlock; + +/* Caller takes needed protections */ + +int +tty_getDebugChar(void) +{ + volatile int chr, dum, time, end_time; + + dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + /* + * This trick says if we wait a very long time and get + * no char, return the -1 and let the upper level deal + * with it. + */ + rdtsc(dum, time); + end_time = time + 2; + while (((chr = read_char(gdb_async_info)) == -1) && + (end_time - time) > 0) { + rdtsc(dum, time); + }; + /* + * This covers our butts if some other code messes with + * our uart, hay, it happens :o) + */ + if (chr == -1) + program_uart(gdb_async_info); + + dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); + return (chr); + +} /* tty_getDebugChar */ + +static int count = 3; +static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; + +static int __init +kgdb_enable_ints(void) +{ + set_debug_traps(); + if (kgdboe) { + return 0; + } + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 1); + } + ok_to_enable_ints = 1; + kgdb_enable_ints_now(); +#ifdef CONFIG_KGDB_USER_CONSOLE + kgdb_console_finit(); +#endif + return 0; +} + +#ifdef CONFIG_SERIAL_8250 +void shutdown_for_kgdb(struct async_struct *gdb_async_info); +#endif + +#define kgdb_mem_init_done() (1) + +static void +kgdb_enable_ints_now(void) +{ + if (!spin_trylock(&one_at_atime)) + return; + if (!ints_disabled) + goto exit; + if (kgdb_mem_init_done() && + ints_disabled) { /* don't try till mem init */ +#ifdef CONFIG_SERIAL_8250 + /* + * The ifdef here allows the system to be configured + * without the serial driver. + * Don't make it a module, however, it will steal the port + */ + shutdown_for_kgdb(gdb_async_info); +#endif + ints_disabled = request_irq(gdb_async_info->state->irq, + gdb_interrupt, + IRQ_T(gdb_async_info), + "KGDB-stub", NULL); + intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); + } + if (!ints_disabled) { + intprintk(("KGDB: Sending %d to port %x offset %d\n", + gdb_async_info->IER, + (int) gdb_async_info->port, UART_IER)); + outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); + } + exit: + spin_unlock(&one_at_atime); +} + +/* + * tty_putDebugChar + * + * This is a GDB stub routine. It waits until the interface is ready + * to transmit a char and then sends it. If there is no serial + * interface connection then it simply returns to its caller, having + * pretended to send the char. Caller takes needed protections. + */ +void +tty_putDebugChar(int chr) +{ + dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", + gdb_async_info->port, + chr, + chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); + + if (gdb_async_info == NULL) { + gdb_hook_interrupt(&local_info, 0); + } + + write_char(gdb_async_info, chr); /* this routine will wait */ + count = (chr == '#') ? 0 : count + 1; + if ((count == 2)) { /* try to enable after */ + if (ints_disabled & ok_to_enable_ints) + kgdb_enable_ints_now(); /* try to enable after */ + + /* We do this a lot because, well we really want to get these + * interrupts. The serial driver will clear these bits when it + * initializes the chip. Every thing else it does is ok, + * but this. + */ + if (!ints_disabled) { + outb_px(gdb_async_info->port + UART_IER, + gdb_async_info->IER); + } + } + +} /* tty_putDebugChar */ + +/* + * This does nothing for the serial port, since it doesn't buffer. + */ + +void tty_flushDebugChar(void) +{ +} + +module_init(kgdb_enable_ints); --- linux-2.6.8-rc1/arch/x86_64/lib/Makefile 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/lib/Makefile 2004-07-13 17:09:26.000000000 -0700 @@ -12,3 +12,4 @@ lib-y := csum-partial.o csum-copy.o csum lib-y += memcpy.o memmove.o memset.o copy_user.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_KGDB) += kgdb_serial.o --- linux-2.6.8-rc1/arch/x86_64/mm/fault.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/arch/x86_64/mm/fault.c 2004-07-13 17:09:13.000000000 -0700 @@ -389,7 +389,7 @@ bad_area_nosemaphore: info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ - info.si_addr = (void *)address; + info.si_addr = (void __user *)address; force_sig_info(SIGSEGV, &info, tsk); return; } @@ -463,7 +463,7 @@ do_sigbus: info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; + info.si_addr = (void __user *)address; force_sig_info(SIGBUS, &info, tsk); return; --- linux-2.6.8-rc1/CREDITS 2004-07-11 14:13:26.000000000 -0700 +++ 25/CREDITS 2004-07-13 17:09:33.000000000 -0700 @@ -2534,6 +2534,7 @@ N: Mikael Pettersson E: mikpe@csd.uu.se W: http://www.csd.uu.se/~mikpe/ D: Miscellaneous fixes +D: Performance-monitoring counters driver N: Reed H. Petty E: rhp@draper.net @@ -2703,7 +2704,9 @@ S: Finland N: Luca Risolia E: luca.risolia@studio.unibo.it +P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4 D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips +D: V4L2 driver for SN9C10[12] PC Camera Controllers S: Via Liberta' 41/A S: Osio Sotto, 24046, Bergamo S: Italy --- linux-2.6.8-rc1/crypto/deflate.c 2003-06-14 12:18:35.000000000 -0700 +++ 25/crypto/deflate.c 2004-07-13 17:09:13.000000000 -0700 @@ -39,44 +39,16 @@ #define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL struct deflate_ctx { - int comp_initialized; - int decomp_initialized; struct z_stream_s comp_stream; struct z_stream_s decomp_stream; }; -static inline int deflate_gfp(void) -{ - return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; -} - -static int deflate_init(void *ctx) -{ - return 0; -} - -static void deflate_exit(void *ctx) -{ - struct deflate_ctx *dctx = ctx; - - if (dctx->comp_initialized) - vfree(dctx->comp_stream.workspace); - if (dctx->decomp_initialized) - kfree(dctx->decomp_stream.workspace); -} - -/* - * Lazy initialization to make interface simple without allocating - * un-needed workspaces. Thus can be called in softirq context. - */ static int deflate_comp_init(struct deflate_ctx *ctx) { int ret = 0; struct z_stream_s *stream = &ctx->comp_stream; - stream->workspace = __vmalloc(zlib_deflate_workspacesize(), - deflate_gfp()|__GFP_HIGHMEM, - PAGE_KERNEL); + stream->workspace = vmalloc(zlib_deflate_workspacesize()); if (!stream->workspace ) { ret = -ENOMEM; goto out; @@ -89,7 +61,6 @@ static int deflate_comp_init(struct defl ret = -EINVAL; goto out_free; } - ctx->comp_initialized = 1; out: return ret; out_free: @@ -102,8 +73,7 @@ static int deflate_decomp_init(struct de int ret = 0; struct z_stream_s *stream = &ctx->decomp_stream; - stream->workspace = kmalloc(zlib_inflate_workspacesize(), - deflate_gfp()); + stream->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); if (!stream->workspace ) { ret = -ENOMEM; goto out; @@ -114,7 +84,6 @@ static int deflate_decomp_init(struct de ret = -EINVAL; goto out_free; } - ctx->decomp_initialized = 1; out: return ret; out_free: @@ -122,6 +91,36 @@ out_free: goto out; } +static void deflate_comp_exit(struct deflate_ctx *ctx) +{ + vfree(ctx->comp_stream.workspace); +} + +static void deflate_decomp_exit(struct deflate_ctx *ctx) +{ + kfree(ctx->decomp_stream.workspace); +} + +static int deflate_init(void *ctx) +{ + int ret; + + ret = deflate_comp_init(ctx); + if (ret) + goto out; + ret = deflate_decomp_init(ctx); + if (ret) + deflate_comp_exit(ctx); +out: + return ret; +} + +static void deflate_exit(void *ctx) +{ + deflate_comp_exit(ctx); + deflate_decomp_exit(ctx); +} + static int deflate_compress(void *ctx, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) { @@ -129,12 +128,6 @@ static int deflate_compress(void *ctx, c struct deflate_ctx *dctx = ctx; struct z_stream_s *stream = &dctx->comp_stream; - if (!dctx->comp_initialized) { - ret = deflate_comp_init(dctx); - if (ret) - goto out; - } - ret = zlib_deflateReset(stream); if (ret != Z_OK) { ret = -EINVAL; @@ -165,12 +158,6 @@ static int deflate_decompress(void *ctx, struct deflate_ctx *dctx = ctx; struct z_stream_s *stream = &dctx->decomp_stream; - if (!dctx->decomp_initialized) { - ret = deflate_decomp_init(dctx); - if (ret) - goto out; - } - ret = zlib_inflateReset(stream); if (ret != Z_OK) { ret = -EINVAL; --- linux-2.6.8-rc1/crypto/twofish.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/crypto/twofish.c 2004-07-13 17:09:13.000000000 -0700 @@ -663,7 +663,10 @@ static int twofish_setkey(void *cx, cons /* Check key length. */ if (key_len != 16 && key_len != 24 && key_len != 32) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; /* unsupported key length */ + } /* Compute the first two words of the S vector. The magic numbers are * the entries of the RS matrix, preprocessed through poly_to_exp. The --- linux-2.6.8-rc1/Documentation/cachetlb.txt 2004-06-15 23:29:40.000000000 -0700 +++ 25/Documentation/cachetlb.txt 2004-07-13 17:09:13.000000000 -0700 @@ -132,6 +132,17 @@ changes occur: translations for software managed TLB configurations. The sparc64 port currently does this. +7) void tlb_migrate_finish(struct mm_struct *mm) + + This interface is called at the end of an explicit + process migration. This interface provides a hook + to allow a platform to update TLB or context-specific + information for the address space. + + The ia64 sn2 platform is one example of a platform + that uses this interface. + + Next, we have the cache flushing interfaces. In general, when Linux is changing an existing virtual-->physical mapping to a new value, the sequence will be in one of the following forms: --- linux-2.6.8-rc1/Documentation/cdrom/00-INDEX 2003-06-14 12:18:20.000000000 -0700 +++ 25/Documentation/cdrom/00-INDEX 2004-07-13 17:09:41.000000000 -0700 @@ -22,6 +22,8 @@ mcdx - info on improved Mitsumi CD-ROM driver. optcd - info on the Optics Storage 8000 AT CD-ROM driver +packet-writing.txt + - Info on the CDRW packet writing module sbpcd - info on the SoundBlaster/Panasonic CD-ROM interface driver. sjcd --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/cdrom/packet-writing.txt 2004-07-13 17:09:42.000000000 -0700 @@ -0,0 +1,88 @@ +Getting started quick +--------------------- + +- Select packet support in the block device section and UDF support in + the file system section. + +- Compile and install kernel and modules, reboot. + +- You need the udftools package (pktsetup, mkudffs, cdrwtool). + Download from http://sourceforge.net/projects/linux-udf/ + +- Grab a new CD-RW disc and format it (assuming CD-RW is hdc, substitute + as appropriate): + # cdrwtool -d /dev/hdc -q + +- Make sure that /dev/pktcdvd0 exists (mknod /dev/pktcdvd0 b 97 0) + +- Setup your writer + # pktsetup /dev/pktcdvd0 /dev/hdc + +- Now you can mount /dev/pktcdvd0 and copy files to it. Enjoy! + # mount /dev/pktcdvd0 /cdrom -t udf -o rw,noatime + + +Packet writing for DVD-RW media +------------------------------- + +DVD-RW discs can be written to much like CD-RW discs if they are in +the so called "restricted overwrite" mode. To put a disc in restricted +overwrite mode, run: + + # dvd+rw-format /dev/hdc + +You can then use the disc the same way you would use a CD-RW disc: + + # pktsetup /dev/pktcdvd0 /dev/hdc + # mount /dev/pktcdvd0 /cdrom -t udf -o rw,noatime + + +Packet writing for DVD+RW media +------------------------------- + +According to the DVD+RW specification, a drive supporting DVD+RW discs +shall implement "true random writes with 2KB granularity", which means +that it should be possible to put any filesystem with a block size >= +2KB on such a disc. For example, it should be possible to do: + + # mkudffs /dev/hdc + # mount /dev/hdc /cdrom -t udf -o rw,noatime + +However, some drives don't follow the specification and expect the +host to perform aligned writes at 32KB boundaries. Other drives do +follow the specification, but suffer bad performance problems if the +writes are not 32KB aligned. + +Both problems can be solved by using the pktcdvd driver, which always +generates aligned writes. + + # pktsetup /dev/pktcdvd0 /dev/hdc + # mkudffs /dev/pktcdvd0 + # mount /dev/pktcdvd0 /cdrom -t udf -o rw,noatime + + +Notes +----- + +- CD-RW media can usually not be overwritten more than about 1000 + times, so to avoid unnecessary wear on the media, you should always + use the noatime mount option. + +- Defect management (ie automatic remapping of bad sectors) has not + been implemented yet, so you are likely to get at least some + filesystem corruption if the disc wears out. + +- Since the pktcdvd driver makes the disc appear as a regular block + device, you can put any filesystem you like on the disc. For + example, run: + + # /sbin/mke2fs /dev/pktcdvd0 + + to create an ext2 filesystem on the disc. + + +Links +----- + +See http://fy.chalmers.se/~appro/linux/DVD+RW/ for more information +about DVD writing. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/cpu-freq/cpufreq-nforce2.txt 2004-07-13 17:09:44.000000000 -0700 @@ -0,0 +1,22 @@ + +The cpufreq-nforce2 driver changes the FSB on nVidia nForce2 plattforms. + +This works better than on other plattforms, because the FSB of the CPU +can be controlled independently from the PCI/AGP clock. + +The module has three options: + + fid: multiplier * 10 (for example 8.5 = 85) + min_fsb: minimum FSB + max_fsb: maximum FSB + +If not set, fid is calculated with the current CPU speed and the FSB, +max_fsb is set to the current FSB and min_fsb to current FSB - 50. + +IMPORTANT: The available range is limited up- _and_ downwards! + You should not set max_fsb higher than the FSB at boot- + time. + Also the minimum available FSB can differ, for systems + booting with 200 MHz, 150 should always work. + + --- linux-2.6.8-rc1/Documentation/devices.txt 2004-07-11 14:13:26.000000000 -0700 +++ 25/Documentation/devices.txt 2004-07-13 17:09:36.000000000 -0700 @@ -2719,6 +2719,7 @@ Your cooperation is appreciated. 32 = /dev/ttyDB0 DataBooster serial port 0 ... 39 = /dev/ttyDB7 DataBooster serial port 7 + 40 = /dev/ttySG0 SGI Altix console port 205 char Low-density serial ports (alternate device) 0 = /dev/culu0 Callout device for ttyLU0 @@ -2743,6 +2744,7 @@ Your cooperation is appreciated. 32 = /dev/cudb0 Callout device for ttyDB0 ... 39 = /dev/cudb7 Callout device for ttyDB7 + 40 = /dev/cusg0 Callout device for ttySG0 206 char OnStream SC-x0 tape devices 0 = /dev/osst0 First OnStream SCSI tape, mode 0 --- linux-2.6.8-rc1/Documentation/DMA-API.txt 2004-07-11 14:13:26.000000000 -0700 +++ 25/Documentation/DMA-API.txt 2004-07-13 17:09:21.000000000 -0700 @@ -444,4 +444,83 @@ dma_alloc_noncoherent(), starting at vir continuing on for size. Again, you *must* observe the cache line boundaries when doing this. +int +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int + flags) + + +Declare region of memory to be handed out by dma_alloc_coherent when +it's asked for coherent memory for this device. + +bus_addr is the physical address to which the memory is currently +assigned in the bus responding region (this will be used by the +platform to perform the mapping) + +device_addr is the physical address the device needs to be programmed +with actually to address this memory (this will be handed out as the +dma_addr_t in dma_alloc_coherent()) + +size is the size of the area (must be multiples of PAGE_SIZE). + +flags can be or'd together and are + +DMA_MEMORY_MAP - request that the memory returned from +dma_alloc_coherent() be directly writeable. + +DMA_MEMORY_IO - request that the memory returned from +dma_alloc_coherent() be addressable using read/write/memcpy_toio etc. + +One or both of these flags must be present + +DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by +dma_alloc_coherent of any child devices of this one (for memory residing +on a bridge). + +DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions. +Do not allow dma_alloc_coherent() to fall back to system memory when +it's out of memory in the declared region. + +The return value will be either DMA_MEMORY_MAP or DMA_MEMORY_IO and +must correspond to a passed in flag (i.e. no returning DMA_MEMORY_IO +if only DMA_MEMORY_MAP were passed in) for success or zero for +failure. + +Note, for DMA_MEMORY_IO returns, all subsequent memory returned by +dma_alloc_coherent() may no longer be accessed directly, but instead +must be accessed using the correct bus functions. If your driver +isn't prepared to handle this contingency, it should not specify +DMA_MEMORY_IO in the input flags. + +As a simplification for the platforms, only *one* such region of +memory may be declared per device. + +For reasons of efficiency, most platforms choose to track the declared +region only at the granularity of a page. For smaller allocations, +you should use the dma_pool() API. + +void +dma_release_declared_memory(struct device *dev) + +Remove the memory region previously declared from the system. This +API performs *no* in-use checking for this region and will return +unconditionally having removed all the required structures. It is the +drivers job to ensure that no parts of this memory region are +currently in use. + +void * +dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) + +This is used to occupy specific regions of the declared space +(dma_alloc_coherent() will hand out the first free region it finds). + +device_addr is the *device* address of the region requested + +size is the size (and should be a page sized multiple). + +The return value will be either a pointer to the processor virtual +address of the memory, or an error (via PTR_ERR()) if any part of the +region is occupied. + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/andthen 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,100 @@ + +define set_andthen + set var $thp=0 + set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0] + set var $at_size = (sizeof kgdb_data)/(sizeof *$thp) + set var $at_oc=kgdb_and_then_count + set var $at_cc=$at_oc +end + +define andthen_next + set var $at_cc=$arg0 +end + +define andthen + andthen_set_edge + if ($at_cc >= $at_oc) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc + output *($thp+($at_cc++ % $at_size )) + printf "\n" + end +end +define andthen_set_edge + set var $at_oc=kgdb_and_then_count + set var $at_low = $at_oc - $at_size + if ($at_low < 0 ) + set var $at_low = 0 + end + if (( $at_cc > $at_oc) || ($at_cc < $at_low)) + printf "Count outside of window, setting count to " + if ($at_cc >= $at_oc) + set var $at_cc = $at_oc + else + set var $at_cc = $at_low + end + printf "%d\n",$at_cc + end +end + +define beforethat + andthen_set_edge + if ($at_cc <= $at_low) + printf "Outside window. Window size is %d\n",($at_oc-$at_low) + else + printf "%d: ",$at_cc-1 + output *($thp+(--$at_cc % $at_size )) + printf "\n" + end +end + +document andthen_next + andthen_next + . sets the number of the event to display next. If this event + . is not in the event pool, either andthen or beforethat will + . correct it to the nearest event pool edge. The event pool + . ends at the last event recorded and begins + . prior to that. If beforethat is used next, it will display + . event -1. +. + andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + + +document andthen + andthen +. displays the next event in the list. sets up to display +. the oldest saved event first. +. (optional) count of the event to display. +. note the number of events saved is specified at configure time. +. if events are saved between calls to andthen the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document set_andthen + set_andthen +. sets up to use the and commands. +. if you have defined your own struct, use the above and +. then enter the following: +. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0] +. where is the name of your structure. +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end + +document beforethat + beforethat +. displays the next prior event in the list. sets up to +. display the last occuring event first. +. +. note the number of events saved is specified at configure time. +. if events are saved between calls to beforethat the index will change +. but the displayed event will be the next one (unless the event buffer +. is overrun). +. +. andthen commands are: set_andthen, andthen_next, andthen and beforethat +end --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/debug-nmi.txt 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,37 @@ +Subject: Debugging with NMI +Date: Mon, 12 Jul 1999 11:28:31 -0500 +From: David Grothe +Organization: Gcom, Inc +To: David Grothe + +Kernel hackers: + +Maybe this is old hat, but it is new to me -- + +On an ISA bus machine, if you short out the A1 and B1 pins of an ISA +slot you will generate an NMI to the CPU. This interrupts even a +machine that is hung in a loop with interrupts disabled. Used in +conjunction with kgdb < +ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can +gain debugger control of a machine that is hung in the kernel! Even +without kgdb the kernel will print a stack trace so you can find out +where it was hung. + +The A1/B1 pins are directly opposite one another and the farthest pins +towards the bracket end of the ISA bus socket. You can stick a paper +clip or multi-meter probe between them to short them out. + +I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the +board consists of two rows of wire wrap pins. So I wired a push button +between the A1/B1 pins and now have an ISA board that I can stick into +any ISA bus slot for debugger entry. + +Microsoft has a circuit diagram of a PCI card at +http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to +build one you will have to mail them and ask for the PAL equations. +Nobody makes one comercially. + +[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if +your machine catches fire, it is your problem, not mine.] + +-- Dave (the kgdb guy) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdb-globals.txt 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,71 @@ +Sender: akale@veritas.com +Date: Fri, 23 Jun 2000 19:26:35 +0530 +From: "Amit S. Kale" +Organization: Veritas Software (India) +To: Dave Grothe , linux-kernel@vger.rutgers.edu +CC: David Milburn , + "Edouard G. Parmelan" , + ezannoni@cygnus.com, Keith Owens +Subject: Re: Module debugging using kgdb + +Dave Grothe wrote: +> +> Amit: +> +> There is a 2.4.0 version of kgdb on our ftp site: +> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb +> and loadmodule.sh there. +> +> Have a look at the README file and see if I go it right. If not, send +> me some corrections and I will update it. +> +> Does your version of gdb solve the global variable problem? + +Yes. +Thanks to Elena Zanoni, gdb (developement version) can now calculate +correctly addresses of dynamically loaded object files. I have not been +following gdb developement for sometime and am not sure when symbol +address calculation fix is going to appear in a gdb stable version. + +Elena, any idea when the fix will make it to a prebuilt gdb from a +redhat release? + +For the time being I have built a gdb developement version. It can be +used for module debugging with loadmodule.sh script. + +The problem with calculating of module addresses with previous versions +of gdb was as follows: +gdb did not use base address of a section while calculating address of +a symbol in the section in an object file loaded via 'add-symbol-file'. +It used address of .text segment instead. Due to this addresses of +symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly. + +Above mentioned fix allow gdb to use base address of a segment while +calculating address of a symbol in it. It adds a parameter '-s' to +'add-symbol-file' command for specifying base address of a segment. + +loadmodule.sh script works as follows. + +1. Copy a module file to target machine. +2. Load the module on the target machine using insmod with -m parameter. +insmod produces a module load map which contains base addresses of all +sections in the module and addresses of symbols in the module file. +3. Find all sections and their base addresses in the module from +the module map. +4. Generate a script that loads the module file. The script uses +'add-symbol-file' and specifies address of text segment followed by +addresses of all segments in the module. + +Here is an example gdb script produced by loadmodule.sh script. + +add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5 +-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38 +-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838 + +With this command gdb can calculate addresses of symbols in ANY segment +in a module file. + +Regards. +-- +Amit Kale +Veritas Software ( http://www.veritas.com ) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,14 @@ +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 +target remote /dev/ttyS0 +define si +stepi +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip +end +define ni +nexti +printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx +printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp +x/i $eip --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit.hw 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,117 @@ + +#Using ia-32 hardware breakpoints. +# +#4 hardware breakpoints are available in ia-32 processors. These breakpoints +#do not need code modification. They are set using debug registers. +# +#Each hardware breakpoint can be of one of the +#three types: execution, write, access. +#1. An Execution breakpoint is triggered when code at the breakpoint address is +#executed. +#2. A write breakpoint ( aka watchpoints ) is triggered when memory location +#at the breakpoint address is written. +#3. An access breakpoint is triggered when memory location at the breakpoint +#address is either read or written. +# +#As hardware breakpoints are available in limited number, use software +#breakpoints ( br command in gdb ) instead of execution hardware breakpoints. +# +#Length of an access or a write breakpoint defines length of the datatype to +#be watched. Length is 1 for char, 2 short , 3 int. +# +#For placing execution, write and access breakpoints, use commands +#hwebrk, hwwbrk, hwabrk +#To remove a breakpoint use hwrmbrk command. +# +#These commands take following types of arguments. For arguments associated +#with each command, use help command. +#1. breakpointno: 0 to 3 +#2. length: 1 to 3 +#3. address: Memory location in hex ( without 0x ) e.g c015e9bc +# +#Use the command exinfo to find which hardware breakpoint occured. + +#hwebrk breakpointno address +define hwebrk + maintenance packet Y$arg0,0,0,$arg1 +end +document hwebrk + hwebrk
+ Places a hardware execution breakpoint + = 0 - 3 +
= Hex digits without leading "0x". +end + +#hwwbrk breakpointno length address +define hwwbrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwwbrk + hwwbrk
+ Places a hardware write breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwabrk breakpointno length address +define hwabrk + maintenance packet Y$arg0,1,$arg1,$arg2 +end +document hwabrk + hwabrk
+ Places a hardware access breakpoint + = 0 - 3 + = 1 (1 byte), 2 (2 byte), 3 (4 byte) +
= Hex digits without leading "0x". +end + +#hwrmbrk breakpointno +define hwrmbrk + maintenance packet y$arg0 +end +document hwrmbrk + hwrmbrk + = 0 - 3 + Removes a hardware breakpoint +end + +define reboot + maintenance packet r +end +#exinfo +define exinfo + maintenance packet qE +end +document exinfo + exinfo + Gives information about a breakpoint. +end +define get_th + p $th=(struct thread_info *)((int)$esp & ~8191) +end +document get_th + get_tu + Gets and prints the current thread_info pointer, Defines th to be it. +end +define get_cu + p $cu=((struct thread_info *)((int)$esp & ~8191))->task +end +document get_cu + get_cu + Gets and print the "current" value. Defines $cu to be it. +end +define int_off + set var $flags=$eflags + set $eflags=$eflags&~0x200 + end +define int_on + set var $eflags|=$flags&0x200 + end +document int_off + saves the current interrupt state and clears the processor interrupt + flag. Use int_on to restore the saved flag. +end +document int_on + Restores the interrupt flag saved by int_off. +end --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/gdbinit-modules 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,146 @@ +# +# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub. +# +# This don't work for Linux-2.0 or older. +# +# Author Edouard G. Parmelan +# +# +# Fri Apr 30 20:33:29 CEST 1999 +# First public release. +# +# Major cleanup after experiment Linux-2.0 kernel without success. +# Symbols of a module are not in the correct order, I can't explain +# why :( +# +# Fri Mar 19 15:41:40 CET 1999 +# Initial version. +# +# Thu Jan 6 16:29:03 CST 2000 +# A little fixing by Dave Grothe +# +# Mon Jun 19 09:33:13 CDT 2000 +# Alignment changes from Edouard Parmelan +# +# The basic idea is to find where insmod load the module and inform +# GDB to load the symbol table of the module with the GDB command +# ``add-symbol-file
''. +# +# The Linux kernel holds the list of all loaded modules in module_list, +# this list end with &kernel_module (exactly with module->next == NULL, +# but the last module is not a real module). +# +# Insmod allocates the struct module before the object file. Since +# Linux-2.1, this structure contain his size. The real address of +# the object file is then (char*)module + module->size_of_struct. +# +# You can use three user functions ``mod-list'', ``mod-print-symbols'' +# and ``add-module-symbols''. +# +# mod-list list all loaded modules with the format: +# +# +# As soon as you have found the address of your module, you can +# print its exported symbols (mod-print-symbols) or inform GDB to add +# symbols from your module file (mod-add-symbols). +# +# The argument that you give to mod-print-symbols or mod-add-symbols +# is the from the mod-list command. +# +# When using the mod-add-symbols command you must also give the full +# pathname of the modules object code file. +# +# The command mod-add-lis is an example of how to make this easier. +# You can edit this macro to contain the path name of your own +# favorite module and then use it as a shorthand to load it. You +# still need the module-address, however. +# +# The internal function ``mod-validate'' set the GDB variable $mod +# as a ``struct module*'' if the kernel known the module otherwise +# $mod is set to NULL. This ensure to not add symbols for a wrong +# address. +# +# Have a nice hacking day ! +# +# +define mod-list + set $mod = (struct module*)module_list + # the last module is the kernel, ignore it + while $mod != &kernel_module + printf "%p\t%s\n", (long)$mod, ($mod)->name + set $mod = $mod->next + end +end +document mod-list +List all modules in the form: +Use the as the argument for the other +mod-commands: mod-print-symbols, mod-add-symbols. +end + +define mod-validate + set $mod = (struct module*)module_list + while ($mod != $arg0) && ($mod != &kernel_module) + set $mod = $mod->next + end + if $mod == &kernel_module + set $mod = 0 + printf "%p is not a module\n", $arg0 + end +end +document mod-validate +mod-validate +Internal user-command used to validate the module parameter. +If is a real loaded module, set $mod to it otherwise set $mod to 0. +end + + +define mod-print-symbols + mod-validate $arg0 + if $mod != 0 + set $i = 0 + while $i < $mod->nsyms + set $sym = $mod->syms[$i] + printf "%p\t%s\n", $sym->value, $sym->name + set $i = $i + 1 + end + end +end +document mod-print-symbols +mod-print-symbols +Print all exported symbols of the module. see mod-list +end + + +define mod-add-symbols-align + mod-validate $arg0 + if $mod != 0 + set $mod_base = ($mod->size_of_struct + (long)$mod) + if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0) + set $mod_base = ($mod_base | ($arg2 - 1)) + 1 + end + add-symbol-file $arg1 $mod_base + end +end +document mod-add-symbols-align +mod-add-symbols-align +Load the symbols table of the module from the object file where +first section aligment is . +To retreive alignment, use `objdump -h '. +end + +define mod-add-symbols + mod-add-symbols-align $arg0 $arg1 sizeof(long) +end +document mod-add-symbols +mod-add-symbols +Load the symbols table of the module from the object file. +Default alignment is 4. See mod-add-symbols-align. +end + +define mod-add-lis + mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16 +end +document mod-add-lis +mod-add-lis +Does mod-add-symbols /usr/src/LiS/streams.o +end --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdbeth.txt 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,92 @@ +KGDB over ethernet +================== + +Authors +------- + +Robert Walsh (2.6 port) +wangdi (2.6 port) +Matt Mackall (netpoll api) +San Mehat (original 2.4 code) + + +Introduction +------------ + +KGDB supports debugging over ethernet (kgdboe) via polling of a given +network interface. Most cards should be supported automatically. +Debugging facilities are available as soon as the network driver and +kgdboe have initialized. Unfortunately, this is too late in the boot +process for debugging some issues, but works quite well for many +others. This should not interfere with normal network usage and +doesn't require a dedicated NIC. + +Terminology +----------- + +This document uses the following terms: + + TARGET: the machine being debugged. + HOST: the machine running gdb. + + +Usage +----- + +You need to use the following command-line option on the TARGET kernel: + + kgdboe=[tgt-port]@/[dev],[host-port]@/[host-macaddr] + + where + tgt-port source for UDP packets (defaults to 6443) + tgt-ip source IP to use (interface address) + dev network interface (eth0) + host-port HOST UDP port (6442) (not really used) + host-ip IP address for HOST machine + host-macaddr ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff) + + examples: + + kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D + this machine is 192.168.0.1 on eth1 + remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D + listen for gdb packets on port 7000 + send unsolicited gdb packets to port 7001 + + kgdboe=@192.168.0.1/,@192.168.0.2/ + this machine is 192.168.0.1 on default interface eth0 + remote machine is 192.168.0.2, use default broadcast MAC address + listen for gdb packets on default port 6443 + send unsolicited gdb packets to port 6442 + +Only packets originating from the configured HOST IP address will be +accepted by the debugger. + +On the HOST side, run gdb as normal and use a remote UDP host as the +target: + + % gdb ./vmlinux + GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) + Copyright 2003 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux-gnu"... + (gdb) target remote udp:HOSTNAME:6443 + +You can now continue as if you were debugging over a serial line. + +Limitations +----------- + +The current release of this code is exclusive of using kgdb on a +serial interface, so you must boot without the kgdboe option to use +serial debugging. Trying to debug the network driver while using it +will prove interesting. + +Bug reports +----------- + +Send bug reports to Robert Walsh and Matt +Mackall . --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/kgdb.txt 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,775 @@ +Last edit: <20030806.1637.12> +This file has information specific to the i386 kgdb option. Other +platforms with the kgdb option may behave in a similar fashion. + +New features: +============ +20030806.1557.37 +This version was made against the 2.6.0-test2 kernel. We have made the +following changes: + +- The getthread() code in the stub calls find_task_by_pid(). It fails + if we are early in the bring up such that the pid arrays have yet to + be allocated. We have added a line to kernel/pid.c to make + "kgdb_pid_init_done" true once the arrays are allocated. This way the + getthread() code knows not to call. This is only used by the thread + debugging stuff and threads will not yet exist at this point in the + boot. + +- For some reason, gdb was not asking for a new thread list when the + "info thread" command was given. We changed to the newer version of + the thread info command and gdb now seems to ask when needed. Result, + we now get all threads in the thread list. + +- We now respond to the ThreadExtraInfo request from gdb with the thread + name from task_struct .comm. This then appears in the thread list. + Thoughts on additional options for this are welcome. Things such as + "has BKL" and "Preempted" come to mind. I think we could have a flag + word that could enable different bits of info here. + +- We now honor, sort of, the C and S commands. These are continue and + single set after delivering a signal. We ignore the signal and do the + requested action. This only happens when we told gdb that a signal + was the reason for entry, which is only done on memory faults. The + result is that you can now continue into the Oops. + +- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb, + but it is more exact on what language to use. + +- We added two dwarf2 include files and a bit of code at the end of + entry.S. This does not yet work, so it is disabled. Still we want to + keep track of the code and "maybe" someone out there can fix it. + +- Randy Dunlap sent some fix ups for this file which are now merged. + +- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a + compiler warning if CONFIG_KGDB is off (now who would do that :). + +- Andrew Morton sent a fix for the serial driver which is now merged. + +- Andrew also sent a change to the stub around the cpu managment code + which is also merged. + +- Andrew also sent a patch to make "f" as well as "g" work as SysRq + commands to enter kgdb, merged. + +- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a + "who" field to the spinlock data struct. This is filled with + "current" when ever the spinlock suceeds. Useful if you want to know + who has the lock. + +_ And last, but not least, we fixed the "get_cu" macro to properly get + the current value of "current". + +New features: +============ +20030505.1827.27 +We are starting to align with the sourceforge version, at least in +commands. To this end, the boot command string to start kgdb at +boot time has been changed from "kgdb" to "gdb". + +Andrew Morton sent a couple of patches which are now included as follows: +1.) We now return a flag to the interrupt handler. +2.) We no longer use smp_num_cpus (a conflict with the lock meter). +3.) And from William Lee Irwin III code to make + sure high-mem is set up before we attempt to register our interrupt + handler. +We now include asm/kgdb.h from config.h so you will most likely never +have to include it. It also 'NULLS' the kgdb macros you might have in +your code when CONFIG_KGDB is not defined. This allows you to just +turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such. +This include is conditioned on the machine being an x86 so as to not +mess with other archs. + +20020801.1129.03 +This is currently the version for the 2.4.18 (and beyond?) kernel. + +We have several new "features" beginning with this version: + +1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more + waiting and it will pull that guy out of an IRQ off spin lock :) + +2.) We doctored up the code that tells where a task is waiting and + included it so that the "info thread" command will show a bit more + than "schedule()". Try it... + +3.) Added the ability to call a function from gdb. All the standard gdb + issues apply, i.e. if you hit a breakpoint in the function, you are + not allowed to call another (gdb limitation, not kgdb). To help + this capability we added a memory allocation function. Gdb does not + return this memory (it is used for strings that you pass to that function + you are calling from gdb) so we fixed up a way to allow you to + manually return the memory (see below). + +4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the + interrupt flag to now also include the preemption count and the + "in_interrupt" info. The flag is now called "with_pif" to indicate + the order, preempt_count, in_interrupt, flag. The preempt_count is + shifted left by 4 bits so you can read the count in hex by dropping + the low order digit. In_interrupt is in bit 1, and the flag is in + bit 0. + +5.) The command: "p kgdb_info" is now expanded and prints something + like: +(gdb) p kgdb_info +$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259, + errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1, + cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0, + regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}} + + Things to note here: a.) used_malloc is the amount of memory that + has been malloc'ed to do calls from gdb. You can reclaim this + memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.) + cpus_waiting is now "sized" by the number of CPUs you enter at + configure time in the kgdb configure section. This is NOT used + anywhere else in the system, but it is "nice" here. c.) The task's + "pid" is now in the structure. This is the pid you will need to use + to decode to the thread id to get gdb to look at that thread. + Remember that the "info thread" command prints a list of threads + wherein it numbers each thread with its reference number followed + by the thread's pid. Note that the per-CPU idle threads actually + have pids of 0 (yes, there is more than one pid 0 in an SMP system). + To avoid confusion, kgdb numbers these threads with numbers beyond + the MAX_PID. That is why you see 32768 and above. + +6.) A subtle change, we now provide the complete register set for tasks + that are active on the other CPUs. This allows better trace back on + those tasks. + + And, let's mention what we could not fix. Back-trace from all but the + thread that we trapped will, most likely, have a bogus entry in it. + The problem is that gdb does not recognize the entry code for + functions that use "current" near (at all?) the entry. The compiler + is putting the "current" decode as the first two instructions of the + function where gdb expects to find %ebp changing code. Back trace + also has trouble with interrupt frames. I am talking with Daniel + Jacobowitz about some way to fix this, but don't hold your breath. + +20011220.0050.35 +Major enhancement with this version is the ability to hold one or more +CPUs in an SMP system while allowing the others to continue. Also, by +default only the current CPU is enabled on single-step commands (please +note that gdb issues single-step commands at times other than when you +use the si command). + +Another change is to collect some useful information in +a global structure called "kgdb_info". You should be able to just: + +p kgdb_info + +although I have seen cases where the first time this is done gdb just +prints the first member but prints the whole structure if you then enter +CR (carriage return or enter). This also works: + +p *&kgdb_info + +Here is a sample: +(gdb) p kgdb_info +$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0, + vector = 3, print_debug_info = 0} + +"Called_from" is the return address from the current entry into kgdb. +Sometimes it is useful to know why you are in kgdb, for example, was +it an NMI or a real breakpoint? The simple way to interrogate this +return address is: + +l *0xc010732c + +which will print the surrounding few lines of source code. + +"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the +kgdb_ts entries). + +"errcode" and "vector" are other entry parameters which may be helpful on +some traps. + +"print_debug_info" is the internal debugging kgdb print enable flag. Yes, +you can modify it. + +In SMP systems kgdb_info also includes the "cpus_waiting" structure and +"hold_on_step": + +(gdb) p kgdb_info +$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0, + vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{ + task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0, + regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, + hold = 0, regs = 0x0}}} + +"Cpus_waiting" has an entry for each CPU other than the current one that +has been stopped. Each entry contains the task_struct address for that +CPU, the address of the regs for that task and a hold flag. All these +have the proper typing so that, for example: + +p *kgdb_info.cpus_waiting[1].regs + +will print the registers for CPU 1. + +"Hold_on_sstep" is a new feature with this version and comes up set or +true. What this means is that whenever kgdb is asked to single-step all +other CPUs are held (i.e. not allowed to execute). The flag applies to +all but the current CPU and, again, can be changed: + +p kgdb_info.hold_on_sstep=0 + +restores the old behavior of letting all CPUs run during single-stepping. + +Likewise, each CPU has a "hold" flag, which if set, locks that CPU out +of execution. Note that this has some risk in cases where the CPUs need +to communicate with each other. If kgdb finds no CPU available on exit, +it will push a message thru gdb and stay in kgdb. Note that it is legal +to hold the current CPU as long as at least one CPU can execute. + +20010621.1117.09 +This version implements an event queue. Events are signaled by calling +a function in the kgdb stub and may be examined from gdb. See EVENTS +below for details. This version also tightens up the interrupt and SMP +handling to not allow interrupts on the way to kgdb from a breakpoint +trap. It is fine to allow these interrupts for user code, but not +system debugging. + +Version +======= + +This version of the kgdb package was developed and tested on +kernel version 2.4.16. It will not install on any earlier kernels. +It is possible that it will continue to work on later versions +of 2.4 and then versions of 2.5 (I hope). + + +Debugging Setup +=============== + +Designate one machine as the "development" machine. This is the +machine on which you run your compiles and which has your source +code for the kernel. Designate a second machine as the "target" +machine. This is the machine that will run your experimental +kernel. + +The two machines will be connected together via a serial line out +one or the other of the COM ports of the PC. You will need the +appropriate modem eliminator (null modem) cable(s) for this. + +Decide on which tty port you want the machines to communicate, then +connect them up back-to-back using the null modem cable. COM1 is +/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection +with the two machines prior to trying to debug a kernel. Once you +have it working, on the TARGET machine, enter: + +setserial /dev/ttyS0 (or what ever tty you are using) + +and record the port address and the IRQ number. + +On the DEVELOPMENT machine you need to apply the patch for the kgdb +hooks. You have probably already done that if you are reading this +file. + +On your DEVELOPMENT machine, go to your kernel source directory and do +"make Xconfig" where X is one of "x", "menu", or "". If you are +configuring in the standard serial driver, it must not be a module. +Either yes or no is ok, but making the serial driver a module means it +will initialize after kgdb has set up the UART interrupt code and may +cause a failure of the control-C option discussed below. The configure +question for the serial driver is under the "Character devices" heading +and is: + +"Standard/generic (8250/16550 and compatible UARTs) serial support" + +Go down to the kernel debugging menu item and open it up. Enable the +kernel kgdb stub code by selecting that item. You can also choose to +turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler +to put more debug info (like local symbols) in the object file. On the +i386 -g and -ggdb are the same so this option just reduces to "O1". The +-O1 reduces the optimization level. This may be helpful in some cases, +be aware, however, that this may also mask the problem you are looking +for. + +The baud rate. Default is 115200. What ever you choose be sure that +the host machine is set to the same speed. I recommend the default. + +The port. This is the I/O address of the serial UART that you should +have gotten using setserial as described above. The standard COM1 port +(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ +3. + +The port IRQ (see above). + +Stack overflow test. This option makes a minor change in the trap, +system call and interrupt code to detect stack overflow and transfer +control to kgdb if it happens. (Some platforms have this in the +baseline code, but the i386 does not.) + +You can also configure the system to recognize the boot option +"console=kgdb" which if given will cause all console output during +booting to be put thru gdb as well as other consoles. This option +requires that gdb and kgdb be connected prior to sending console output +so, if they are not, a breakpoint is executed to force the connection. +This will happen before any kernel output (it is going thru gdb, right), +and will stall the boot until the connection is made. + +You can also configure in a patch to SysRq to enable the kGdb SysRq. +This request generates a breakpoint. Since the serial port IRQ line is +set up after any serial drivers, it is possible that this command will +work when the control-C will not. + +Save and exit the Xconfig program. Then do "make clean" , "make dep" +and "make bzImage" (or whatever target you want to make). This gets the +kernel compiled with the "-g" option set -- necessary for debugging. + +You have just built the kernel on your DEVELOPMENT machine that you +intend to run on your TARGET machine. + +To install this new kernel, use the following installation procedure. +Remember, you are on the DEVELOPMENT machine patching the kernel source +for the kernel that you intend to run on the TARGET machine. + +Copy this kernel to your target machine using your usual procedures. I +usually arrange to copy development: +/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine +via a LAN based NFS access. That is, I run the cp command on the target +and copy from the development machine via the LAN. Run Lilo (see "man +lilo" for details on how to set this up) on the new kernel on the target +machine so that it will boot! Then boot the kernel on the target +machine. + +On the DEVELOPMENT machine, create a file called .gdbinit in the +directory /usr/src/linux. An example .gdbinit file looks like this: + +shell echo -e "\003" >/dev/ttyS0 +set remotebaud 38400 (or what ever speed you have chosen) +target remote /dev/ttyS0 + + +Change the "echo" and "target" definition so that it specifies the tty +port that you intend to use. Change the "remotebaud" definition to +match the data rate that you are going to use for the com line. + +You are now ready to try it out. + +Boot your target machine with "kgdb" in the boot command i.e. something +like: + +lilo> test kgdb + +or if you also want console output thru gdb: + +lilo> test kgdb console=kgdb + +You should see the lilo message saying it has loaded the kernel and then +all output stops. The kgdb stub is trying to connect with gdb. Start +gdb something like this: + + +On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux". +When gdb gets the symbols loaded it will read your .gdbinit file and, if +everything is working correctly, you should see gdb print out a few +lines indicating that a breakpoint has been taken. It will actually +show a line of code in the target kernel inside the kgdb activation +code. + +The gdb interaction should look something like this: + + linux-dev:/usr/src/linux# gdb vmlinux + GDB is free software and you are welcome to distribute copies of it + under certain conditions; type "show copying" to see the conditions. + There is absolutely no warranty for GDB; type "show warranty" for details. + GDB 4.15.1 (i486-slackware-linux), + Copyright 1995 Free Software Foundation, Inc... + breakpoint () at i386-stub.c:750 + 750 } + (gdb) + +You can now use whatever gdb commands you like to set breakpoints. +Enter "continue" to start your target machine executing again. At this +point the target system will run at full speed until it encounters +your breakpoint or gets a segment violation in the kernel, or whatever. + +If you have the kgdb console enabled when you continue, gdb will print +out all the console messages. + +The above example caused a breakpoint relatively early in the boot +process. For the i386 kgdb it is possible to code a break instruction +as the first C-language point in init/main.c, i.e. as the first instruction +in start_kernel(). This could be done as follows: + +#include + breakpoint(); + +This breakpoint() is really a function that sets up the breakpoint and +single-step hardware trap cells and then executes a breakpoint. Any +early hard coded breakpoint will need to use this function. Once the +trap cells are set up they need not be set again, but doing it again +does not hurt anything, so you don't need to be concerned about which +breakpoint is hit first. Once the trap cells are set up (and the kernel +sets them up in due course even if breakpoint() is never called) the +macro: + +BREAKPOINT; + +will generate an inline breakpoint. This may be more useful as it stops +the processor at the instruction instead of in a function a step removed +from the location of interest. In either case must be +included to define both breakpoint() and BREAKPOINT. + +Triggering kgdbstub at other times +================================== + +Often you don't need to enter the debugger until much later in the boot +or even after the machine has been running for some time. Once the +kernel is booted and interrupts are on, you can force the system to +enter the debugger by sending a control-C to the debug port. This is +what the first line of the recommended .gdbinit file does. This allows +you to start gdb any time after the system is up as well as when the +system is already at a breakpoint. (In the case where the system is +already at a breakpoint the control-C is not needed, however, it will +be ignored by the target so no harm is done. Also note the the echo +command assumes that the port speed is already set. This will be true +once gdb has connected, but it is best to set the port speed before you +run gdb.) + +Another simple way to do this is to put the following file in you ~/bin +directory: + +#!/bin/bash +echo -e "\003" > /dev/ttyS0 + +Here, the ttyS0 should be replaced with what ever port you are using. +The "\003" is control-C. Once you are connected with gdb, you can enter +control-C at the command prompt. + +An alternative way to get control to the debugger is to enable the kGdb +SysRq command. Then you would enter Alt-SysRq-g (all three keys at the +same time, but push them down in the order given). To refresh your +memory of the available SysRq commands try Alt-SysRq-=. Actually any +undefined command could replace the "=", but I like to KNOW that what I +am pushing will never be defined. + +Debugging hints +=============== + +You can break into the target machine at any time from the development +machine by typing ^C (see above paragraph). If the target machine has +interrupts enabled this will stop it in the kernel and enter the +debugger. + +There is unfortunately no way of breaking into the kernel if it is +in a loop with interrupts disabled, so if this happens to you then +you need to place exploratory breakpoints or printk's into the kernel +to find out where it is looping. The exploratory breakpoints can be +entered either thru gdb or hard coded into the source. This is very +handy if you do something like: + +if () BREAKPOINT; + + +There is a copy of an e-mail in the Documentation/i386/kgdb/ directory +(debug-nmi.txt) which describes how to create an NMI on an ISA bus +machine using a paper clip. I have a sophisticated version of this made +by wiring a push button switch into a PC104/ISA bus adapter card. The +adapter card nicely furnishes wire wrap pins for all the ISA bus +signals. + +When you are done debugging the kernel on the target machine it is a +good idea to leave it in a running state. This makes reboots faster, +bypassing the fsck. So do a gdb "continue" as the last gdb command if +this is possible. To terminate gdb itself on the development machine +and leave the target machine running, first clear all breakpoints and +continue, then type ^Z to suspend gdb and then kill it with "kill %1" or +something similar. + +If gdbstub Does Not Work +======================== + +If it doesn't work, you will have to troubleshoot it. Do the easy +things first like double checking your cabling and data rates. You +might try some non-kernel based programs to see if the back-to-back +connection works properly. Just something simple like cat /etc/hosts +>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you +if you can send data from one machine to the other. Make sure it works +in both directions. There is no point in tearing out your hair in the +kernel if the line doesn't work. + +All of the real action takes place in the file +/usr/src/linux/arch/i386/kernel/kgdb_stub.c. That is the code on the target +machine that interacts with gdb on the development machine. In gdb you can +turn on a debug switch with the following command: + + set remotedebug + +This will print out the protocol messages that gdb is exchanging with +the target machine. + +Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is +the code that talks to the serial port on the target side. There might +be a problem there. In particular there is a section of this code that +tests the UART which will tell you what UART you have if you define +"PRNT" (just remove "_off" from the #define PRNT_off). To view this +report you will need to boot the system without any beakpoints. This +allows the kernel to run to the point where it calls kgdb to set up +interrupts. At this time kgdb will test the UART and print out the type +it finds. (You need to wait so that the printks are actually being +printed. Early in the boot they are cached, waiting for the console to +be enabled. Also, if kgdb is entered thru a breakpoint it is possible +to cause a dead lock by calling printk when the console is locked. The +stub thus avoids doing printks from breakpoints, especially in the +serial code.) At this time, if the UART fails to do the expected thing, +kgdb will print out (using printk) information on what failed. (These +messages will be buried in all the other boot up messages. Look for +lines that start with "gdb_hook_interrupt:". You may want to use dmesg +once the system is up to view the log. If this fails or if you still +don't connect, review your answers for the port address. Use: + +setserial /dev/ttyS0 + +to get the current port and IRQ information. This command will also +tell you what the system found for the UART type. The stub recognizes +the following UART types: + +16450, 16550, and 16550A + +If you are really desperate you can use printk debugging in the +kgdbstub code in the target kernel until you get it working. In particular, +there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c +named "remote_debug". Compile your kernel with this set to 1, rather +than 0 and the debug stub will print out lots of stuff as it does +what it does. Likewise there are debug printks in the kgdb_serial.c +code that can be turned on with simple changes in the macro defines. + + +Debugging Loadable Modules +========================== + +This technique comes courtesy of Edouard Parmelan + + +When you run gdb, enter the command + +source gdbinit-modules + +This will read in a file of gdb macros that was installed in your +kernel source directory when kgdb was installed. This file implements +the following commands: + +mod-list + Lists the loaded modules in the form + +mod-print-symbols + Prints all the symbols in the indicated module. + +mod-add-symbols + Loads the symbols from the object file and associates them + with the indicated module. + +After you have loaded the module that you want to debug, use the command +mod-list to find the of your module. Then use that +address in the mod-add-symbols command to load your module's symbols. +From that point onward you can debug your module as if it were a part +of the kernel. + +The file gdbinit-modules also contains a command named mod-add-lis as +an example of how to construct a command of your own to load your +favorite module. The idea is to "can" the pathname of the module +in the command so you don't have to type so much. + +Threads +======= + +Each process in a target machine is seen as a gdb thread. gdb thread +related commands (info threads, thread n) can be used. + +ia-32 hardware breakpoints +========================== + +kgdb stub contains support for hardware breakpoints using debugging features +of ia-32(x86) processors. These breakpoints do not need code modification. +They use debugging registers. 4 hardware breakpoints are available in ia-32 +processors. + +Each hardware breakpoint can be of one of the following three types. + +1. Execution breakpoint - An Execution breakpoint is triggered when code + at the breakpoint address is executed. + + As limited number of hardware breakpoints are available, it is + advisable to use software breakpoints ( break command ) instead + of execution hardware breakpoints, unless modification of code + is to be avoided. + +2. Write breakpoint - A write breakpoint is triggered when memory + location at the breakpoint address is written. + + A write or can be placed for data of variable length. Length of + a write breakpoint indicates length of the datatype to be + watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for + 4 byte data. + +3. Access breakpoint - An access breakpoint is triggered when memory + location at the breakpoint address is either read or written. + + Access breakpoints also have lengths similar to write breakpoints. + +IO breakpoints in ia-32 are not supported. + +Since gdb stub at present does not use the protocol used by gdb for hardware +breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros +for hardware breakpoints are described below. + +hwebrk - Places an execution breakpoint + hwebrk breakpointno address +hwwbrk - Places a write breakpoint + hwwbrk breakpointno length address +hwabrk - Places an access breakpoint + hwabrk breakpointno length address +hwrmbrk - Removes a breakpoint + hwrmbrk breakpointno +exinfo - Tells whether a software or hardware breakpoint has occurred. + Prints number of the hardware breakpoint if a hardware breakpoint has + occurred. + +Arguments required by these commands are as follows +breakpointno - 0 to 3 +length - 1 to 3 +address - Memory location in hex digits ( without 0x ) e.g c015e9bc + +SMP support +========== + +When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb +client, all the processors are forced to enter the debugger. Current +thread corresponds to the thread running on the processor where +breakpoint occurred. Threads running on other processor(s) appear +similar to other non-running threads in the 'info threads' output. +Within the kgdb stub there is a structure "waiting_cpus" in which kgdb +records the values of "current" and "regs" for each CPU other than the +one that hit the breakpoint. "current" is a pointer to the task +structure for the task that CPU is running, while "regs" points to the +saved registers for the task. This structure can be examined with the +gdb "p" command. + +ia-32 hardware debugging registers on all processors are set to same +values. Hence any hardware breakpoints may occur on any processor. + +gdb troubleshooting +=================== + +1. gdb hangs +Kill it. restart gdb. Connect to target machine. + +2. gdb cannot connect to target machine (after killing a gdb and +restarting another) If the target machine was not inside debugger when +you killed gdb, gdb cannot connect because the target machine won't +respond. In this case echo "Ctrl+C"(ASCII 3) to the serial line. +e.g. echo -e "\003" > /dev/ttyS1 +This forces that target machine into the debugger, after which you +can connect. + +3. gdb cannot connect even after echoing Ctrl+C into serial line +Try changing serial line settings min to 1 and time to 0 +e.g. stty min 1 time 0 < /dev/ttyS1 +Try echoing again + +Check serial line speed and set it to correct value if required +e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1 + +EVENTS +====== + +Ever want to know the order of things happening? Which CPU did what and +when? How did the spinlock get the way it is? Then events are for +you. Events are defined by calls to an event collection interface and +saved for later examination. In this case, kgdb events are saved by a +very fast bit of code in kgdb which is fully SMP and interrupt protected +and they are examined by using gdb to display them. Kgdb keeps only +the last N events, where N must be a power of two and is defined at +configure time. + + +Events are signaled to kgdb by calling: + +kgdb_ts(data0,data1) + +For each call kgdb records each call in an array along with other info. +Here is the array definition: + +struct kgdb_and_then_struct { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + int data0; + int data1; +}; + +For SMP machines the CPU is recorded, for all machines the TSC is +recorded (gets a time stamp) as well as the line number and source file +the call was made from. The address of the (from), the "if" (interrupt +flag) and the two data items are also recorded. The macro kgdb_ts casts +the types to int, so you can put any 32-bit values here. There is a +configure option to select the number of events you want to keep. A +nice number might be 128, but you can keep up to 1024 if you want. The +number must be a power of two. An "andthen" macro library is provided +for gdb to help you look at these events. It is also possible to define +a different structure for the event storage and cast the data to this +structure. For example the following structure is defined in kgdb: + +struct kgdb_and_then_struct2 { +#ifdef CONFIG_SMP + int on_cpu; +#endif + long long at_time; + int from_ln; + char * in_src; + void *from; + int with_if; + struct task_struct *t1; + struct task_struct *t2; +}; + +If you use this for display, the data elements will be displayed as +pointers to task_struct entries. You may want to define your own +structure to use in casting. You should only change the last two items +and you must keep the structure size the same. Kgdb will handle these +as 32-bit ints, but within that constraint you can define a structure to +cast to any 32-bit quantity. This need only be available to gdb and is +only used for casting in the display code. + +Final Items +=========== + +I picked up this code from Amit S. Kale and enhanced it. + +If you make some really cool modification to this stuff, or if you +fix a bug, please let me know. + +George Anzinger + + +Amit S. Kale + + +(First kgdb by David Grothe ) + +(modified by Tigran Aivazian ) + Putting gdbstub into the kernel config menu. + +(modified by Scott Foehner ) + Hooks for entering gdbstub at boot time. + +(modified by Amit S. Kale ) + Threads, ia-32 hw debugging, mp support, console support, + nmi watchdog handling. + +(modified by George Anzinger ) + Extended threads to include the idle threads. + Enhancements to allow breakpoint() at first C code. + Use of module_init() and __setup() to automate the configure. + Enhanced the cpu "collection" code to work in early bring-up. + Added ability to call functions from gdb + Print info thread stuff without going back to schedule() + Now collect the "other" cpus with an IPI/ NMI. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/i386/kgdb/loadmodule.sh 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,78 @@ +#/bin/sh +# This script loads a module on a target machine and generates a gdb script. +# source generated gdb script to load the module file at appropriate addresses +# in gdb. +# +# Usage: +# Loading the module on target machine and generating gdb script) +# [foo]$ loadmodule.sh +# +# Loading the module file into gdb +# (gdb) source +# +# Modify following variables according to your setup. +# TESTMACHINE - Name of the target machine +# GDBSCRIPTS - The directory where a gdb script will be generated +# +# Author: Amit S. Kale (akale@veritas.com). +# +# If you run into problems, please check files pointed to by following +# variables. +# ERRFILE - /tmp/.errs contains stderr output of insmod +# MAPFILE - /tmp/.map contains stdout output of insmod +# GDBSCRIPT - $GDBSCRIPTS/load gdb script. + +TESTMACHINE=foo +GDBSCRIPTS=/home/bar + +if [ $# -lt 1 ] ; then { + echo Usage: $0 modulefile + exit +} ; fi + +MODULEFILE=$1 +MODULEFILEBASENAME=`basename $1` + +if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { + MODULEFILE=`pwd`/$MODULEFILE +} fi + +ERRFILE=/tmp/$MODULEFILEBASENAME.errs +MAPFILE=/tmp/$MODULEFILEBASENAME.map +GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME + +function findaddr() { + local ADDR=0x$(echo "$SEGMENTS" | \ + grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ + sed 's/[ ]*[^ ]*$//') + echo $ADDR +} + +function checkerrs() { + if [ "`cat $ERRFILE`" != "" ] ; then { + cat $ERRFILE + exit + } fi +} + +#load the module +echo Copying $MODULEFILE to $TESTMACHINE +rcp $MODULEFILE root@${TESTMACHINE}: + +echo Loading module $MODULEFILE +rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ + > $MAPFILE 2> $ERRFILE +checkerrs + +SEGMENTS=`head -n 11 $MAPFILE | tail -n 10` +TEXTADDR=$(findaddr "\\.text[^.]") +LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" +SEGADDRS=`echo "$SEGMENTS" | awk '//{ + if ($1 != ".text" && $1 != ".this" && + $1 != ".kstrtab" && $1 != ".kmodtab") { + print " -s " $1 " 0x" $3 " " + } +}'` +LOADSTRING="$LOADSTRING $SEGADDRS" +echo Generating script $GDBSCRIPT +echo $LOADSTRING > $GDBSCRIPT --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/ia64/kgdb.txt 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,9 @@ +IA64 kgdb requires a patch to gdb/remote.c. The proposed patch will eventually be in gdb but +until then, within gdb do "show remote" and look for "Support for remote protocol `p' (fetch-register) packet is auto-detected, currently unknown." Should this line not appear, then you must +obtain the patch, apply it and build gdb. + +CONFIG_KGDB_EARLY enables one with serial kgdb support to debug the kernel starting at the +end of the routine setup_arch. A boot option of "kgdb=1" will result in a kernel breakpoint +and requires gdb to continue from the breakpoint. + +For further information consult the i386 kgdb documentation. --- linux-2.6.8-rc1/Documentation/input/joystick-parport.txt 2004-04-03 20:39:10.000000000 -0800 +++ 25/Documentation/input/joystick-parport.txt 2004-07-13 17:09:22.000000000 -0700 @@ -335,6 +335,7 @@ controller (compatible with DirectPadPro * Analog PSX Pad (red mode) * Analog PSX Pad (green mode) * PSX Rumble Pad + * PSX DDR Pad 2.4 Sega ~~~~~~~~ @@ -452,14 +453,22 @@ uses the following kernel/module command 5 | Multisystem 2-button joystick 6 | N64 pad 7 | Sony PSX controller + 8 | Sony PSX DDR controller - The exact type of the PSX controller type is autoprobed, so you must have -your controller plugged in before initializing. + The exact type of the PSX controller type is autoprobed when used so +hot swapping should work (but is not recomended). Should you want to use more than one of parallel ports at once, you can use gamecon.map2 and gamecon.map3 as additional command line parameters for two more parallel ports. + There are two options specific to PSX driver portion. gamecon.psx_delay sets +the command delay when talking to the controllers. The default of 25 should +work but you can try lowering it for better performace. If your pads don't +respond try raising it untill they work. Setting the type to 8 allows the +driver to be used with Dance Dance Revolution or similar games. Arrow keys are +registered as key presses instead of X and Y axes. + 3.2 db9.c ~~~~~~~~~ Apart from making an interface, there is nothing difficult on using the --- linux-2.6.8-rc1/Documentation/kernel-parameters.txt 2004-07-11 14:13:26.000000000 -0700 +++ 25/Documentation/kernel-parameters.txt 2004-07-13 17:35:08.000000000 -0700 @@ -574,6 +574,20 @@ running once the system is up. so, the driver will manage that printer. See also header of drivers/char/lp.c. + lpj=n [KNL] + Sets loops_per_jiffy to given constant, thus avoiding + time-consuming boot-time autodetection (up to 250 ms per + CPU). 0 enables autodetection (default). To determine + the correct value for your kernel, boot with normal + autodetection and see what value is printed. Note that + on SMP systems the preset will be applied to all CPUs, + which is likely to cause problems if your CPUs need + significantly divergent settings. An incorrect value + will cause delays in the kernel to be wrong, leading to + unpredictable I/O errors and other breakage. Although + unlikely, in the extreme case this might damage your + hardware. + ltpc= [NET] Format: ,, @@ -650,6 +664,12 @@ running once the system is up. mga= [HW,DRM] + mousedev.tap_time= + [MOUSE] Maximum time between finger touching and + leaving touchpad surface for touch to be considered + a tap and be reported as a left button click (for + touchpads working in absolute mode only). + Format: mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices reporting absolute coordinates, such as tablets mousedev.yres= [MOUSE] Vertical screen resolution, used for devices @@ -887,7 +907,10 @@ running once the system is up. Ranges are in pairs (memory base and size). profile= [KNL] Enable kernel profiling via /proc/profile - (param: profile step/bucket size as a power of 2) + { schedule | } + (param: schedule - profile schedule points} + (param: profile step/bucket size as a power of 2 for + statistical time based profiling) prompt_ramdisk= [RAM] List of RAM disks to prompt for floppy disk before loading. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/must-fix.txt 2004-07-13 17:09:27.000000000 -0700 @@ -0,0 +1,249 @@ + +Must-fix bugs +============= + +drivers/char/ +~~~~~~~~~~~~~ + +o TTY locking is broken. + + o see FIXME in do_tty_hangup(). This causes ppp BUGs in local_bh_enable() + + o Other problems: aviro, dipankar, Alan have details. + + o somebody will have to document the tty driver and ldisc API + +drivers/tty +~~~~~~~~~~~ + +o viro: tty_driver refcounting, tty/misc/upper levels of sound still not + completely fixed. + +drivers/block/ +~~~~~~~~~~~~~~ + +o loop.c: Concurrent write access on block devices might cause a deadlock + of the complete system. See: + http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w== + http://bugzilla.kernel.org/show_bug.cgi?id=1198 + Thread of possible fix: + http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html + + (Fruhwirth Clemens) + +o ideraid hasn't been ported to 2.5 at all yet. + + We need to understand whether the proposed BIO split code will suffice + for this. + +drivers/input/ +~~~~~~~~~~~~~~ + +o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0 + currently on these remaining in my/Linus' tree.) + +o viro: large absence of locking. + +o viro: parport is nearly as bad as that and there the code is more hairy. + IMO parport is more of "figure out what API changes are needed for its + users, get them done ASAP, then fix generic layer at leisure" + + +drivers/misc/ +~~~~~~~~~~~~~ + +o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM + tree. (touchscreen, audio, gpio, type device.) + + These need to be moved out of drivers/misc/ and into real places + +o viro: actually, misc.c has a good chance to die. With cdev-cidr that's + trivial. + +drivers/net/ +~~~~~~~~~~~~ + +drivers/net/irda/ +~~~~~~~~~~~~~~~~~ + + (Jean Tourrilhes) + +o irport need to be converted to sir-kthread + +o dongle drivers need to be converted to sir-dev (in progress) + +o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress) + + +drivers/pci/ +~~~~~~~~~~~~ + +o alan: Some cardbus crashes the system + + (bugzilla, please?) + +drivers/pcmcia/ +~~~~~~~~~~~~~~~ + +o alan: This is a locking disaster. + + (rmk, brodo: in progress) + +drivers/pld/ +~~~~~~~~~~~~ + +o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld) + + (rmk: will work out what to do here. maybe drivers/arm/) + +drivers/video/ +~~~~~~~~~~~~~~ + +o Lots of drivers don't compile, others do but don't work. + +drivers/scsi/ +~~~~~~~~~~~~~ + +o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping + +o Make inia100, cpqfc, pci2000 and dc390t compile + +o Convert + + wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93 + + 53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000 + pci2220i dc390t + + To new error handling + + It also might be possible to shift the 53c7xx based drivers over to + 53c700 which does the new EH stuff, but I don't have the hardware to check + such a shift. + + For the non-compiling stuff, I've probably missed a few that just aren't + compilable on my platforms, so any updates would be welcome. Also, are + some of our non-compiling or unconverted drivers obsolete? + +fs/ +~~~ + +o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr. + In progress. + +o viro: there is some generic stuff for namei/namespace/super, but that's a + slow-merge and can go in 2.6 just fine + + +kernel/sched.c +~~~~~~~~~~~~~~ + +o Starvation, general interactivity need close monitoring. + + +kernel/ +~~~~~~~ + +o Alan: 32bit uid support is *still* broken for process accounting. + + Create a 32bit uid, turn accounting on. Shock horror it doesn't work + because the field is 16bit. We need an acct structure flag day for 2.6 + IMHO + + (alan has patch) + +o viro: core sysctl code is racy. And its interaction wiuth sysfs + + +lib/kobject.c +~~~~~~~~~~~~~ + +o kobject refcounting (comments from Al Viro): + + _anything_ can grab a temporary reference to kobject. IOW, if kobject is + embedded into something that could be freed - it _MUST_ have a destructor + and that destructor _MUST_ be the destructor for containing object. + + Any violation of the above (and we already have a bunch of those) is a + user-triggerable memory corruption. + + We can tolerate it for a while in 2.5 (e.g. during work on susbsystem we + can decide to switch to that way of handling objects and have subsystem + vulnerable for a while), but all such windows must be closed before 2.6 + and during 2.6 we can't open them at all. + +o All block drivers which control multiple gendisks with a single + request_queue are broken, due to one-to-one assumptions in the request + queue sysfs hookup. + +mm/ +~~~ + +o GFP_DMA32 (or something like that). Lots of ideas. jejb, zaitcev, + willy, arjan, wli. + + Specifically, 64-bit systems need to be able to enforce 32-bit addressing + limits for device metadata like network cards' ring buffers and SCSI + command descriptors. + +o access_process_vm() doesn't flush right. We probably need new flushing + primitives to do this (davem?) + + +modules +~~~~~~~ + + (Rusty) + +net/ +~~~~ + + (davem) + +o UDP apps can in theory deadlock, because the ip_append_data path can end + up sleeping while the socket lock is held. + + It is OK to sleep with the socket held held, normally. But in this case + the sleep happens while waiting for socket memory/space to become + available, if another context needs to take the socket lock to free up the + space we could hang. + + I sent a rough patch on how to fix this to Alexey, and he is analyzing + the situation. I expect a final fix from him next week or so. + +o Semantics for IPSEC during operations such as TCP connect suck currently. + + When we first try to connect to a destination, we may need to ask the + IPSEC key management daemon to resolve the IPSEC routes for us. For the + purposes of what the kernel needs to do, you can think of it like ARP. We + can't send the packet out properly until we resolve the path. + + What happens now for IPSEC is basically this: + + O_NONBLOCK: returns -EAGAIN over and over until route is resolved + + !O_NONBLOCK: Sleeps until route is resolved + + These semantics are total crap. The solution, which Alexey is working + on, is to allow incomplete routes to exist. These "incomplete" routes + merely put the packet onto a "resolution queue", and once the key manager + does it's thing we finish the output of the packet. This is precisely how + ARP works. + + I don't know when Alexey will be done with this. + +net/*/netfilter/ +~~~~~~~~~~~~~~~~ + + (Rusty) + +sound/ +~~~~~~ + +global +~~~~~~ + +o A couple of hundred real looking bugzilla bugs + +o viro: cdev rework. Mostly done. + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/perfctr/low-level-api.txt 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,216 @@ +$Id: low-level-api.txt,v 1.1 2004/07/02 18:57:05 mikpe Exp $ + +PERFCTR LOW-LEVEL DRIVERS API +============================= + +This document describes the common low-level API. +See low-level-$ARCH.txt for architecture-specific documentation. + +General Model +============= +The model is that of a processor with: +- A non-programmable clock-like counter, the "TSC". + The TSC frequency is assumed to be constant, but it is not + assumed to be identical to the core frequency. + The TSC may be absent. +- A set of programmable counters, the "perfctrs" or "pmcs". + Control data may be per-counter, global, or both. + The counters are not assumed to be interchangeable. + + A normal counter that simply counts events is referred to + as an "accumulation-mode" or "a-mode" counter. Its total + count is computed by adding the counts for the individual + periods during which the counter is active. Two per-counter + state variables are used for this: "sum", which is the + total count up to but not including the current period, + and "start", which records the value of the hardware counter + at the start of the current period. At the end of a period, + the hardware counter's value is read again, and the increment + relative the start value is added to the sum. This strategy + is used because it avoids a number of hardware problems. + + A counter that has been programmed to generate an interrupt + on overflow is referred to as an "interrupt-mode" or "i-mode" + counter. I-mode counters are initialised to specific values, + and after overflowing are reset to their (re)start values. + The total event count is available just as for a-mode counters. + + The set of counters may be empty, in which case only the + TSC (which must be present) can be sampled. + +Contents of +================================= + +"struct perfctr_sum_ctrs" +------------------------- +struct perfctr_sum_ctrs { + unsigned long long tsc; + unsigned long long pmc[..]; /* one per counter */ +}; + +Architecture-specific container for counter values. +Used in the kernel/user API, but not by the low-level drivers. + +"struct perfctr_cpu_control" +---------------------------- +This struct includes at least the following fields: + + unsigned int tsc_on; + unsigned int nractrs; /* # of a-mode counters */ + unsigned int nrictrs; /* # of i-mode counters */ + unsigned int pmc_map[..]; /* one per counter: virt-to-phys mapping */ + unsigned int evntsel[..]; /* one per counter: hw control data */ + int ireset[..]; /* one per counter: i-mode (re)start value */ + +Architecture-specific container for control data. +Used both in the kernel/user API and by the low-level drivers +(embedded in "struct perfctr_cpu_state"). + +"tsc_on" is non-zero if the TSC should be sampled. + +"nractrs" is the number of a-mode counters, corresponding to +elements 0..nractrs-1 in the per-counter arrays. + +"nrictrs" is the number of i-mode counters, corresponding to +elements nractrs..nractrs+nrictrs-1 in the per-counter arrays. + +"nractrs+nrictrs" is the total number of counters to program +and sample. A-mode and i-mode counters are separated in order +to allow quick enumeration of either set, which is needed in +some low-level driver operations. + +"pmc_map[]" maps each counter to its corresponding hardware counter +identification. No two counters may map to the same hardware counter. +This mapping is present because the hardware may have asymmetric +counters or other addressing quirks, which means that a counter's index +may not suffice to address its hardware counter. + +"evntsel[]" contains the per-counter control data. Architecture-specific +global control data, if any, is placed in architecture-specific fields. + +"ireset[]" contains the (re)start values for the i-mode counters. +Only indices nractrs..nractrs+nrictrs-1 are used. + +"struct perfctr_cpu_state" +-------------------------- +This struct includes at least the following fields: + + unsigned int cstatus; + unsigned int tsc_start; + unsigned long long tsc_sum; + struct { + unsigned int map; + unsigned int start; + unsigned long long sum; + } pmc[..]; /* one per counter; the size is not part of the user ABI */ +#ifdef __KERNEL__ + struct perfctr_cpu_control control; +#endif + +This type records the state and control data for a collection +of counters. It is used by many low-level operations, and may +be exported to user-space via mmap(). + +"cstatus" is a re-encoding of control.tsc_on/nractrs/nrictrs, +used because it reduces overheads in key low-level operations. +Operations on cstatus values include: +- unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs, unsigned int nrictrs); + Construct a cstatus value. +- unsigned int perfctr_cstatus_enabled(unsigned int cstatus); + Check if any part (tsc_on, nractrs, nrictrs) of the cstatus is non-zero. +- int perfctr_cstatus_has_tsc(unsigned int cstatus); + Check if the tsc_on part of the cstatus is non-zero. +- unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus); + Retrieve nractrs+nrictrs from the cstatus. +- unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus); + Check if the nrictrs part of cstatus is non-zero. + +"tsc_start" and "tsc_sum" record the state of the TSC. + +"pmc[]" contains the per-counter state, in the "start" and "sum" +fields. The "map" field contains the corresponding hardware counter +identification, from the counter's entry in "control.pmc_map[]"; +it is copied into pmc[] to reduce overheads in key low-level operations. + +"control" contains the control data which determines the +behaviour of the counters. + +User-space overflow signal handler items +---------------------------------------- +After a counter has overflowed, a user-space signal handler may +be invoked with a "struct siginfo" identifying the source of the +signal and the set of overflown counters. + +#define SI_PMC_OVF .. + +Value to be stored in "si.si_code". + +#define si_pmc_ovf_mask .. + +Field in which to store a bit-mask of the overflown counters. + +Kernel-internal API +------------------- + +/* Driver init/exit. + perfctr_cpu_init() performs hardware detection and may fail. */ +extern int perfctr_cpu_init(void); +extern void perfctr_cpu_exit(void); + +/* CPU type name. Set if perfctr_cpu_init() was successful. */ +extern char *perfctr_cpu_name; + +/* Hardware reservation. A high-level driver must reserve the + hardware before it may use it, and release it afterwards. + "service" is a unique string identifying the high-level driver. + perfctr_cpu_reserve() returns NULL on success; if another + high-level driver has reserved the hardware, then that + driver's "service" string is returned. */ +extern const char *perfctr_cpu_reserve(const char *service); +extern void perfctr_cpu_release(const char *service); + +/* PRE: state has no running interrupt-mode counters. + Check that the new control data is valid. + Update the low-level driver's private control data. + is_global should be zero for per-process counters and non-zero + for global-mode counters. + Returns a negative error code if the control data is invalid. */ +extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global); + +/* Stop i-mode counters. Update sums and start values. + Read a-mode counters. Subtract from start and accumulate into sums. + Must be called with preemption disabled. */ +extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state); + +/* Reset i-mode counters to their start values. + Write control registers. + Read a-mode counters and update their start values. + Must be called with preemption disabled. */ +extern void perfctr_cpu_resume(struct perfctr_cpu_state *state); + +/* Perform an efficient combined suspend/resume operation. + Must be called with preemption disabled. */ +extern void perfctr_cpu_sample(struct perfctr_cpu_state *state); + +/* The type of a perfctr overflow interrupt handler. + It will be called in IRQ context, with preemption disabled. */ +typedef void (*perfctr_ihandler_t)(unsigned long pc); + +/* Install a perfctr overflow interrupt handler. + Should be called after perfctr_cpu_reserve() but before + any counter state has been activated. */ +extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t); + +/* PRE: The state has been suspended and sampled by perfctr_cpu_suspend(). + Should be called from the high-level driver's perfctr_ihandler_t, + and preemption must not have been enabled. + Identify which counters have overflown, reset their start values + from ireset[], and perform any necessary hardware cleanup. + Returns a bit-mask of the overflown counters. */ +extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*); + +/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to + bypass internal caching and force a reload of the i-mode pmcs. + This ensures that perfctr_cpu_identify_overflow()'s state changes + are propagated to the hardware. */ +extern void perfctr_cpu_ireload(struct perfctr_cpu_state*); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/perfctr/low-level-ppc32.txt 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,164 @@ +$Id: low-level-ppc32.txt,v 1.1 2004/07/02 18:57:05 mikpe Exp $ + +PERFCTRS PPC32 LOW-LEVEL API +============================ + +See low-level-api.txt for the common low-level API. +This document only describes ppc32-specific behaviour. +For detailed hardware control register layouts, see +the manufacturers' documentation. + +Supported processors +==================== +- PowerPC 604, 604e, 604ev. +- PowerPC 750/740, 750CX, 750FX, 750GX. +- PowerPC 7400, 7410, 7451/7441, 7457/7447. +- Any generic PowerPC with a timebase register. + +Contents of +================================= + +"struct perfctr_sum_ctrs" +------------------------- +struct perfctr_sum_ctrs { + unsigned long long tsc; + unsigned long long pmc[8]; +}; + +The pmc[] array has room for 8 counters. + +"struct perfctr_cpu_control" +---------------------------- +struct perfctr_cpu_control { + unsigned int tsc_on; + unsigned int nractrs; /* # of a-mode counters */ + unsigned int nrictrs; /* # of i-mode counters */ + unsigned int pmc_map[8]; + unsigned int evntsel[8]; /* one per counter, even on P5 */ + int ireset[8]; /* [0,0x7fffffff], for i-mode counters */ + struct { + unsigned int mmcr0; /* sans PMC{1,2}SEL */ + unsigned int mmcr2; /* only THRESHMULT */ + /* IABR/DABR/BAMR not supported */ + } ppc; + unsigned int _reserved1; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +The per-counter arrays have room for 8 elements. + +ireset[] values must be non-negative, since overflow occurs on +the non-negative-to-negative transition. + +The ppc sub-struct contains PowerPC-specific control data: +- mmcr0: global control data for the MMCR0 SPR; the event + selectors for PMC1 and PMC2 are in evntsel[], not in mmcr0 +- mmcr2: global control data for the MMCR2 SPR; only the + THRESHMULT field can be specified + +"struct perfctr_cpu_state" +-------------------------- +struct perfctr_cpu_state { + unsigned int cstatus; + struct { /* k1 is opaque in the user ABI */ + unsigned int id; + int isuspend_cpu; + } k1; + /* The two tsc fields must be inlined. Placing them in a + sub-struct causes unwanted internal padding on x86-64. */ + unsigned int tsc_start; + unsigned long long tsc_sum; + struct { + unsigned int map; + unsigned int start; + unsigned long long sum; + } pmc[8]; /* the size is not part of the user ABI */ +#ifdef __KERNEL__ + unsigned int ppc_mmcr[3]; + struct perfctr_cpu_control control; +#endif +}; + +The k1 sub-struct is used by the low-level driver for +caching purposes. "id" identifies the control data, and +"isuspend_cpu" identifies the CPU on which the i-mode +counters were last suspended. + +The pmc[] array has room for 8 elements. + +ppc_mmcr[] is computed from control by the low-level driver, +and provides the data for the MMCR0, MMCR1, and MMCR2 SPRs. + +User-space overflow signal handler items +---------------------------------------- +#ifdef __KERNEL__ +#define SI_PMC_OVF (__SI_FAULT|'P') +#else +#define SI_PMC_OVF ('P') +#endif +#define si_pmc_ovf_mask _sifields._pad[0] + +Kernel-internal API +------------------- + +In perfctr_cpu_update_control(), the is_global parameter +is ignored. (It is only relevant for x86.) + +CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK is never defined. +(It is only relevant for x86.) + +Overflow interrupt handling is not yet implemented. + +Processor-specific Notes +======================== + +General +------- +pmc_map[] contains a counter number, an integer between 0 and 5. +It never contains an SPR number. + +Basic operation (the strategy for a-mode counters, caching +control register contents, recording "suspend CPU" for i-mode +counters) is the same as in the x86 driver. + +PowerPC 604/750/74xx +-------------------- +These processors use similar hardware layouts, differing +mainly in the number of counter and control registers. +The set of available events differ greatly, but that only +affects users, not the low-level driver itself. + +The hardware has 2 (604), 4 (604e/750/7400/7410), or 6 +(745x) counters (PMC1 to PMC6), and 1 (604), 2 (604e/750), +or 3 (74xx) control registers (MMCR0 to MMCR2). + +MMCR0 contains global control bits, and the event selection +fields for PMC1 and PMC2. MMCR1 contains event selection fields +for PMC3-PMC6. MMCR2 contains the THRESHMULT flag, which +specifies how MMCR0[THRESHOLD] should be scaled. + +In control.ppc.mmcr0, the PMC1SEL and PMC2SEL fields (0x00001FFF) +are reserved. The PMXE flag (0x04000000) may only be set when +the driver supports overflow interrupts. + +If FCECE or TRIGGER is set in MMCR0 on a 74xx processor, then +MMCR0 can change asynchronously. The driver handles this, at +the cost of some additional work in perfctr_cpu_suspend(). +Not setting these flags avoids that overhead. + +In control.ppc.mmcr2, only the THRESHMULT flag (0x80000000) +may be set, and only on 74xx processors. + +The SIA (sampled instruction address) register is not used. +The SDA (sampled data address) register is 604/604e-only, +and is not used. The BAMR (breakpoint address mask) register +is not used, but it is cleared by the driver. + +Generic PowerPC with timebase +----------------------------- +The driver supports any PowerPC as long as it has a timebase +register, and the TB frequency is available via Open Firmware. +In this case, the only valid usage mode is with tsc_on == 1 +and nractrs == nrictrs == 0 in the control data. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/perfctr/low-level-x86.txt 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,360 @@ +$Id: low-level-x86.txt,v 1.1 2004/07/02 18:57:05 mikpe Exp $ + +PERFCTRS X86 LOW-LEVEL API +========================== + +See low-level-api.txt for the common low-level API. +This document only describes x86-specific behaviour. +For detailed hardware control register layouts, see +the manufacturers' documentation. + +Contents +======== +- Supported processors +- Contents of +- Processor-specific Notes +- Implementation Notes + +Supported processors +==================== +- Intel P5, P5MMX, P6, P4. +- AMD K7, K8. (P6 clones, with some changes) +- Cyrix 6x86MX, MII, and III. (good P5 clones) +- Centaur WinChip C6, 2, and 3. (bad P5 clones) +- VIA C3. (bad P6 clone) +- Any generic x86 with a TSC. + +Contents of +================================ + +"struct perfctr_sum_ctrs" +------------------------- +struct perfctr_sum_ctrs { + unsigned long long tsc; + unsigned long long pmc[18]; +}; + +The pmc[] array has room for 18 counters. + +"struct perfctr_cpu_control" +---------------------------- +struct perfctr_cpu_control { + unsigned int tsc_on; + unsigned int nractrs; /* # of a-mode counters */ + unsigned int nrictrs; /* # of i-mode counters */ + unsigned int pmc_map[18]; + unsigned int evntsel[18]; /* one per counter, even on P5 */ + struct { + unsigned int escr[18]; + unsigned int pebs_enable; /* for replay tagging */ + unsigned int pebs_matrix_vert; /* for replay tagging */ + } p4; + int ireset[18]; /* < 0, for i-mode counters */ + unsigned int _reserved1; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +The per-counter arrays have room for 18 elements. + +ireset[] values must be negative, since overflow occurs on +the negative-to-non-negative transition. + +The p4 sub-struct contains P4-specific control data: +- escr[]: the control data to write to the ESCR register + associatied with the counter +- pebs_enable: the control data to write to the PEBS_ENABLE MSR +- pebs_matrix_vert: the control data to write to the + PEBS_MATRIX_VERT MSR + +"struct perfctr_cpu_state" +-------------------------- +struct perfctr_cpu_state { + unsigned int cstatus; + struct { /* k1 is opaque in the user ABI */ + unsigned int id; + int isuspend_cpu; + } k1; + /* The two tsc fields must be inlined. Placing them in a + sub-struct causes unwanted internal padding on x86-64. */ + unsigned int tsc_start; + unsigned long long tsc_sum; + struct { + unsigned int map; + unsigned int start; + unsigned long long sum; + } pmc[18]; /* the size is not part of the user ABI */ +#ifdef __KERNEL__ + struct perfctr_cpu_control control; + unsigned int p4_escr_map[18]; +#endif +}; + +The k1 sub-struct is used by the low-level driver for +caching purposes. "id" identifies the control data, and +"isuspend_cpu" identifies the CPU on which the i-mode +counters were last suspended. + +The pmc[] array has room for 18 elements. + +p4_escr_map[] is computed from control by the low-level driver, +and provides the MSR number for the counter's associated ESCR. + +User-space overflow signal handler items +---------------------------------------- +#ifdef __KERNEL__ +#define SI_PMC_OVF (__SI_FAULT|'P') +#else +#define SI_PMC_OVF ('P') +#endif +#define si_pmc_ovf_mask _sifields._pad[0] + +Kernel-internal API +------------------- + +In perfctr_cpu_update_control(), the is_global parameter controls +whether monitoring the other thread (T1) on HT P4s is permitted +or not. On other processors the parameter is ignored. + +SMP kernels define CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK and +"extern cpumask_t perfctr_cpus_forbidden_mask;". +On HT P4s, resource conflicts can occur because both threads +(T0 and T1) in a processor share the same perfctr registers. +To prevent conflicts, only thread 0 in each processor is allowed +to access the counters. perfctr_cpus_forbidden_mask contains the +smp_processor_id()s of each processor's thread 1, and it is the +responsibility of the high-level driver to ensure that it never +accesses the perfctr state from a forbidden thread. + +Overflow interrupt handling requires local APIC support in the kernel. + +Processor-specific Notes +======================== + +General +------- +pmc_map[] contains a counter number, as used by the RDPMC instruction. +It never contains an MSR number. + +Counters are 32, 40, or 48 bits wide. The driver always only +reads the low 32 bits. This avoids performance issues, and +errata on some processors. + +Writing to counters or their control registers tends to be +very expensive. This is why a-mode counters only use read +operations on the counter registers. Caching of control +register contents is done to avoid writing them. "Suspend CPU" +is recorded for i-mode counters to avoid writing the counter +registers when the counters are resumed (their control +registers must be written at both suspend and resume, however). + +Some processors are unable to stop the counters (Centaur/VIA), +and some are unable to reinitialise them to arbitrary values (P6). +Storing the counters' total counts in the hardware counters +would break as soon as context-switches occur. This is another +reason why the accumulate-differences method for maintaining the +counter values is used. + +Intel P5 +-------- +The hardware stores both counters' control data in a single +control register, the CESR MSR. The evntsel values are +limited to 16 bits each, and are combined by the low-level +driver to form the value for the CESR. Apart from that, +the evntsel values are direct images of the CESR. + +Bits 0xFE00 in an evntsel value are reserved. +At least one evntsel CPL bit (0x00C0) must be set. + +For Cyrix' P5 clones, evntsel bits 0xFA00 are reserved. + +For Centaur's P5 clones, evntsel bits 0xFF00 are reserved. +It has no CPL bits to set. The TSC is broken and cannot be used. + +Intel P6 +-------- +The evntsel values are mapped directly onto the counters' +EVNTSEL control registers. + +The global enable bit (22) in EVNTSEL0 must be set. That bit is +reserved in EVNTSEL1. + +Bits 21 and 19 (0x00280000) in each evntsel are reserved. + +For an i-mode counter, bit 20 (0x00100000) of its evntsel must be +set. For a-mode counters, that bit must not be set. + +Hardware quirk: Counters are 40 bits wide, but writing to a +counter only writes the low 32 bits: remaining bits are +sign-extended from bit 31. + +AMD K7/K8 +--------- +Similar to Intel P6. The main difference is that each evntsel has +its own enable bit, which must be set. + +VIA C3 +------ +Superficially similar to Intel P6, but only PERFCTR1/EVNTSEL1 +are programmable. pmc_map[0] must be 1, if nractrs == 1. + +Bits 0xFFFFFE00 in the evntsel are reserved. There are no auxiliary +control bits to set. + +Generic +------- +Only permits TSC sampling, with tsc_on == 1 and nractrs == nrictrs == 0 +in the control data. + +Intel P4 +-------- +For each counter, its evntsel[] value is mapped onto its CCCR +control register, and its p4.escr[] value is mapped onto its +associated ESCR control register. + +The ESCR register number is computed from the hardware counter +number (from pmc_map[]) and the ESCR SELECT field in the CCCR, +and is cached in p4_escr_map[]. + +pmc_map[] contains the value to pass to RDPMC when reading the +counter. It is strongly recommended to set bit 31 (fast rdpmc). + +In each evntsel/CCCR value: +- the OVF, OVF_PMI_T1 and hardware-reserved bits (0xB80007FF) + are reserved and must not be set +- bit 11 (EXTENDED_CASCADE) is only permitted on P4 models >= 2, + and for counters 12 and 15-17 +- bits 16 and 17 (ACTIVE_THREAD) must both be set on non-HT processors +- at least one of bits 12 (ENABLE), 30 (CASCADE), or 11 (EXTENDED_CASCADE) + must be set +- bit 26 (OVF_PMI_T0) must be clear for a-mode counters, and set + for i-mode counters; if bit 25 (FORCE_OVF) also is set, then + the corresponding ireset[] value must be exactly -1 + +In each p4.escr[] value: +- bit 32 is reserved and must not be set +- the CPL_T1 field (bits 0 and 1) must be zero except on HT processors + when global-mode counters are used +- IQ_ESCR0 and IQ_ESCR1 can only be used on P4 models <= 2 + +PEBS is not supported, but the replay tagging bits in PEBS_ENABLE +and PEBS_MATRIX_VERT may be used. + +If p4.pebs_enable is zero, then p4.pebs_matrix_vert must also be zero. + +If p4.pebs_enable is non-zero: +- only bits 24, 10, 9, 2, 1, and 0 may be set; note that in contrast + to Intel's documentation, bit 25 (ENABLE_PEBS_MY_THR) is not needed + and must not be set +- bit 24 (UOP_TAG) must be set +- at least one of bits 10, 9, 2, 1, or 0 must be set +- in p4.pebs_matrix_vert, all bits except 1 and 0 must be clear, + and at least one of bits 1 and 0 must be set + +Implementation Notes +==================== + +Caching +------- +Each 'struct perfctr_cpu_state' contains two cache-related fields: +- 'id': a unique identifier for the control data contents +- 'isuspend_cpu': the identity of the CPU on which a state containing + interrupt-mode counters was last suspended + +To this the driver adds a per-CPU cache, recording: +- the 'id' of the control data currently in that CPU +- the current contents of each control register + +When perfctr_cpu_update_control() has validated the new control data, +it also updates the id field. + +The driver's internal 'write_control' function, called from the +perfctr_cpu_resume() API function, first checks if the state's id +matches that of the CPU's cache, and if so, returns. Otherwise +it checks each control register in the state and updates those +that do not match the cache. Finally, it writes the state's id +to the cache. Tests on various x86 processor types have shown that +MSR writes are very expensive: the purpose of these cache checks +is to avoid MSR writes whenever possible. + +Unlike accumulation-mode counters, interrupt-mode counters must be +physically stopped when suspended, primilarly to avoid overflow +interrupts in contexts not expecting them, and secondarily to avoid +increments to the counters themselves (see below). + +When suspending interrupt-mode counters, the driver: +- records the CPU identity in the per-CPU cache +- stops each interrupt-mode counter by disabling its control register +- lets the cache and state id values remain the same + +Later, when resuming interrupt-mode counters, the driver: +- if the state and cache id values match: + * the cache id is cleared, to force a reload of the control + registers stopped at suspend (see below) + * if the state's "suspend" CPU identity matches the current CPU, + the counter registers are still valid, and the procedure returns +- if the procedure did not return above, it then loops over each + interrupt-mode counter: + * the counter's control register is physically disabled, unless + the cache indicates that it already is disabled; this is necessary + to prevent premature events and overflow interrupts if the CPU's + registers previously belonged to some other state + * then the counter register itself is restored +After this interrupt-mode specific resume code is complete, the +driver continues by calling 'write_control' as described above. +The state and cache ids will not match, forcing write_control to +reload the disabled interrupt-mode control registers. + +Call-site Backpatching +---------------------- +The x86 family of processors is quite diverse in how their +performance counters work and are accessed. There are three +main designs (P5, P6, and P4) with several variations. +To handle this the processor type detection and initialisation +code sets up a number of function pointers to point to the +correct procedures for the actual CPU type. + +Calls via function pointers are more expensive than direct calls, +so the driver actually performs direct calls to wrappers that +backpatch the original call sites to instead call the actual +CPU-specific functions in the future. + +Unsynchronised code backpatching in SMP systems doesn't work +on Intel P6 processors due to an erratum, so the driver performs +a "finalise backpatching" step after the CPU-specific function +pointers have been set up. This step invokes the API procedures +on a temporary state object, set up to force every backpatchable +call site to be invoked and adjusted. + +Several low-level API procedures are called in the context-switch +path by the per-process perfctrs kernel extension, which motivates +the efforts to reduce runtime overheads as much as possible. + +Overflow Interrupts +------------------- +The x86 hardware enables overflow interrupts via the local +APIC's LVTPC entry, which is only present in P6/K7/K8/P4. + +The low-level driver supports overflow interrupts as follows: +- It reserves a local APIC vector, 0xee, as LOCAL_PERFCTR_VECTOR. +- It adds a local APIC exception handler to entry.S, which + invokes the driver's smp_perfctr_interrupt() procedure. +- It adds code to i8259.c to bind the LOCAL_PERFCTR_VECTOR + interrupt gate to the exception handler in entry.S. +- During processor type detection, it records whether the + processor supports the local APIC, and sets up function pointers + for the suspend and resume operations on interrupt-mode counters. +- When the low-level driver is activated, it enables overflow + interrupts by writing LOCAL_PERFCTR_VECTOR to each CPU's APIC_LVTPC. +- Overflow interrupts now end up in smp_perfctr_interrupt(), which + ACKs the interrupt and invokes the interrupt handler installed + by the high-level service/driver. +- When the low-level driver is deactivated, it disables overflow + interrupts by masking APIC_LVTPC in each CPU. It then releases + the local APIC back to the NMI watchdog. + +At compile-time, the low-level driver indicates overflow interrupt +support by enabling CONFIG_PERFCTR_INTERRUPT_SUPPORT. If the feature +is also available at runtime, it sets the PERFCTR_FEATURE_PCINT flag +in the perfctr_info object. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/perfctr/overview.txt 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,129 @@ +$Id: perfctr-documentation-update.patch,v 1.1 2004/07/12 05:41:57 akpm Exp $ + +AN OVERVIEW OF PERFCTR +====================== +The perfctr package adds support to the Linux kernel for using +the performance-monitoring counters found in many processors. + +Perfctr is internally organised in three layers: + +- The low-level drivers, one for each supported architecture. + Currently there are two, one for 32 and 64-bit x86 processors, + and one for 32-bit PowerPC processors. + + low-level-api.txt documents the model of the performance counters + used in this package, and the internal API to the low-level drivers. + + low-level-{x86,ppc}.txt provide documentation specific for those + architectures and their low-level drivers. + +- The high-level services. + There is currently one, a kernel extension adding support for + virtualised per-process performance counters. + See virtual.txt for documentation on this kernel extension. + + [There used to be a second high-level service, a simple driver + to control and access all performance counters in all processors. + This driver is currently removed, pending an acceptable new API.] + +- The top-level, which performs initialisation and implements + common procedures and system calls. + +Rationale +--------- +The perfctr package solves three problems: + +- Hardware invariably restricts programming of the performance + counter registers to kernel-level code, and sometimes also + restricts reading the counters to kernel-level code. + + Perfctr adds APIs allowing user-space code access the counters. + In the case of the per-process counters kernel extension, + even non-privileged processes are allowed access. + +- Hardware often limits the precision of the hardware counters, + making them unsuitable for storing total event counts. + + The counts are instead maintained as 64-bit values in software, + with the hardware counters used to derive increments over given + time periods. + +- In a non-modified kernel, the thread state does not include the + performance monitoring counters, and the context switch code + does not save and restore them. In this situation the counters + are system-wide, making them unreliable and inaccurate when used + for monitoring specific processes or specific segments of code. + + The per-process counters kernel extension treats the counter state as + part of the thread state, solving the reliability and accuracy problems. + +Non-goals +--------- +Providing high-level interfaces that abstract and hide the +underlying hardware is a non-goal. Such abstractions can +and should be implemented in user-space, for several reasons: + +- The complexity and variability of the hardware means that + any abstraction would be inaccurate. There would be both + loss of functionality, and presence of functionality which + isn't supportable on any given processor. User-space tools + and libraries can implement this, on top of the processor- + specific interfaces provided by the kernel. + +- The implementation of such an abstraction would be large + and complex. (Consider ESCR register assignment on P4.) + Performing complex actions in user-space simplifies the + kernel, allowing it to concentrate on validating control + data, managing processes, and driving the hardware. + (C.f. the role of compilers.) + +- The abstraction is purely a user-convenience thing. The + kernel-level components have no need for it. + +Common System Calls +=================== +This lists those system calls that are not tied to +a specific high-level service/driver. + +Querying CPU and Driver Information +----------------------------------- +int err = sys_perfctr_info(struct perfctr_info *info, + struct perfctr_cpu_mask *cpus, + struct perfctr_cpu_mask *forbidden); + +This operation retrieves information from the kernel about +the processors in the system. + +If non-NULL, '*info' will be updated with information about the +capabilities of the processor and the low-level driver. + +If non-NULL, '*cpus' will be updated with a bitmask listing the +set of processors in the system. The size of this bitmask is not +statically known, so the protocol is: + +1. User-space initialises cpus->nrwords to the number of elements + allocated for cpus->mask[]. +2. The kernel reads cpus->nrwords, and then writes the required + number of words to cpus->nrwords. +3. If the required number of words is less than the original value + of cpus->nrwords, then an EOVERFLOW error is signalled. +4. Otherwise, the kernel converts its internal cpumask_t value + to the external format and writes that to cpus->mask[]. + +If non-NULL, '*forbidden' will be updated with a bitmask listing +the set of processors in the system on which users must not try +to use performance counters. This is currently only relevant for +hyper-threaded Pentium 4/Xeon systems. The protocol is the same +as for '*cpus'. + +Notes: +- The internal representation of a cpumask_t is as an array of + unsigned long. This representation is unsuitable for user-space, + because it is not binary-compatible between 32 and 64-bit + variants of a big-endian processor. The 'struct perfctr_cpu_mask' + type uses an array of unsigned 32-bit integers. +- The protocol for retrieving a 'struct perfctr_cpu_mask' was + designed to allow user-space to quickly determine the correct + size of the 'mask[]' array. Other system calls use weaker protocols, + which force user-space to guess increasingly larger values in a + loop, until finally an acceptable value was guessed. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/perfctr/virtual.txt 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,355 @@ +$Id: perfctr-documentation-update.patch,v 1.1 2004/07/12 05:41:57 akpm Exp $ + +VIRTUAL PER-PROCESS PERFORMANCE COUNTERS +======================================== +This document describes the virtualised per-process performance +counters kernel extension. See "General Model" in low-level-api.txt +for the model of the processor's performance counters. + +Contents +======== +- Summary +- Design & Implementation Notes + * State + * Thread Management Hooks + * Synchronisation Rules + * The Pseudo File System +- API For User-Space + * Opening/Creating the State + * Updating the Control + * Unlinking the State + * Reading the State + * Resuming After Handling Overflow Signal + * Reading the Counter Values +- Limitations / TODO List + +Summary +======= +The virtualised per-process performance counters facility +(virtual perfctrs) is a kernel extension which extends the +thread state to record perfctr settings and values, and augments +the context-switch code to save perfctr values at suspends and +restore them at resumes. This "virtualises" the performance +counters in much the same way as the kernel already virtualises +general-purpose and floating-point registers. + +Virtual perfctrs also adds an API allowing non-privileged +user-space processes to set up and access their perfctrs. + +As this facility is primarily intended to support developers +of user-space code, both virtualisation and allowing access +from non-privileged code are essential features. + +Design & Implementation Notes +============================= + +State +----- +The state of a thread's perfctrs is packaged up in an object of +type 'struct vperfctr'. It consists of CPU-dependent state, a +sampling timer, and some auxiliary administrative data. This is +an independent object, with its own lifetime and access rules. + +The state object is attached to the thread via a pointer in its +thread_struct. While attached, the object records the identity +of its owner thread: this is used for user-space API accesses +from threads other than the owner. + +The state is separate from the thread_struct for several resons: +- It's potentially large, hence it's allocated only when needed. +- It can outlive its owner thread. The state can be opened as + a pseudo file: as long as that file is live, so is the object. +- It can be mapped, via mmap() on the pseudo file's descriptor. + To facilitate this, a full page is allocated and reserved. + +Thread Management Hooks +----------------------- +Virtual perfctrs hooks into several thread management events: + +- exit_thread(): Calls perfctr_exit_thread() to stop the counters + and detach the thread's vperfctr object. + +- copy_thread(): Calls perfctr_copy_thread() to initialise + the child's vperfctr pointer. Currently the settings are + not inherited from parent to child, so the pointer is set + to NULL in the child's thread_struct. + +- switch_to(): + * Calls perfctr_suspend_thread() on the previous thread, to + suspend its counters. + * Calls perfctr_resume_thread() on the next thread, to resume + its counters. Also resets the sampling timer (see below). + +- update_process_times(): Calls perfctr_sample_thread(), which + decrements the sampling timer and samples the counters if the + timer reaches zero. + + Sampling is normally only done at switch_to(), but if too much + time passes before the next switch_to(), a hardware counter may + increment by more than its range (usually 2^32). If this occurs, + the difference from its start value will be incorrect, causing + its updated sum to also be incorrect. The sampling timer is used + to prevent this problem, which has been observed on SMP machines, + and on high clock frequency UP machines. + +- set_cpus_allowed(): Calls perfctr_set_cpus_allowed() to detect + attempts to migrate the thread to a "forbidden" CPU, in which + case a flag in the vperfctr object is set. perfctr_resume_thread() + checks this flag, and if set, marks the counters as stopped and + sends a SIGILL to the thread. + + The notion of forbidden CPUs is a workaround for a design flaw + in hyper-threaded Pentium 4s and Xeons. See low-level-x86.txt + for details. + +To reduce overheads, these hooks are implemented as inline functions +that check if the thread is using perfctrs before calling the code +that implements the behaviour. The hooks also reduce to no-ops if +CONFIG_PERFCTR_VIRTUAL is disabled. + +Synchronisation Rules +--------------------- +There are four types of accesses to a thread's perfctr state: + +1. Thread management events (see above) done by the thread itself. + Suspend, resume, and sample are lock-less. + +2. API operations done by the thread itself. + These are lock-less, except when an individual operation + has specific synchronisation needs. For instance, preemption + is often disabled to prevent accesses due to context switches. + +3. API operations done by a different thread ("monitor thread"). + The owner thread must be suspended for the duration of the operation. + This is ensured by requiring that the monitor thread is ptrace()ing + the owner thread, and that the owner thread is in TASK_STOPPED state. + +4. set_cpus_allowed(). + The kernel does not lock the target during set_cpus_allowed(), + so it can execute concurrently with the owner thread or with + some monitor thread. In particular, the state may be deallocated. + + To solve this problem, both perfctr_set_cpus_allowed() and the + operations that can change the owner thread's perfctr pointer + (creat, unlink, exit) perform a task_lock() on the owner thread + before accessing the perfctr pointer. + + When concurrent set_cpus_allowed() isn't a problem (because the + architecture doesn't have a notion of forbidden CPUs), atomicity + of updates to the thread's perfctr pointer is ensured by disabling + preemption. + +The Pseudo File System +---------------------- +The perfctr state is accessed from user-space via a file descriptor. + +The main reason for this is to enable mmap() on the file descriptor, +which gives read-only access to the state. + +The file descriptor is a handle to the perfctr state object. This +allows a very simple implementation of the user-space 'perfex' +program, which runs another program with given perfctr settings +and reports their final values. Without this handle, monitoring +applications like perfex would have to be implemented like debuggers +in order to catch the target thread's exit and retrieve the counter +values before the exit completes and the state disappears. + +The file for a perfctr state object belongs to the vperfctrs pseudo +file system. Files in this file system support only a few operations: +- mmap() +- release() decrements the perfctr object's reference count and + deallocates the object when no references remain +- the listing of a thread's open file descriptors identifies + perfctr state file descriptors as belonging to "vperfctrfs" +The implementation is based on the code for pipefs. + +In previous versions of the perfctr package, the file descriptors +for perfctr state objects also supported the API's ioctl() method. + +API For User-Space +================== + +Opening/Creating the State +-------------------------- +int fd = sys_vperfctr_open(int tid, int creat); + +'tid' must be the id of a thread, or 0 which is interpreted as an +alias for the current thread. + +This operation returns an open file descriptor which is a handle +on the thread's perfctr state object. + +If 'creat' is non-zero and the object did not exist, then it is +created and attached to the thread. The newly created state object +is inactive, with all control fields disabled and all counters +having the value zero. If 'creat' is non-zero and the object +already existed, then an EEXIST error is signalled. + +If 'tid' does not denote the current thread, then it must denote a +thread that is stopped and under ptrace control by the current thread. + +Notes: +- The access rule in the non-self case is the same as for the + ptrace() system call. It ensures that no other thread, including + the target thread itself, can access or change the target thread's + perfctr state during the operation. +- An open file descriptor for a perfctr state object counts as a + reference to that object; even if detached from its thread the + object will not be deallocated until the last reference is gone. +- The file descriptor can be passed to mmap(), for low-overhead + counter sampling. See "READING THE COUNTER VALUES" for details. +- The file descriptor can be passed to another thread. Accesses + from threads other than the owner are permitted as long as they + posses the file descriptor and use ptrace() for synchronisation. + +Updating the Control +-------------------- +int err = sys_vperfctr_control(int fd, const struct vperfctr_control *control); + +'fd' must be the return value from a call to sys_vperfctr_open(), +The perfctr object must still be attached to its owner thread. + +This operation stops and samples any currently running counters in +the thread, and then updates the control settings. If the resulting +state has any enabled counters, then the counters are restarted. + +Before restarting, the counter sums are reset to zero. However, +if a counter's bit is set in the control object's 'preserve' +bitmask field, then that counter's sum is not reset. The TSC's +sum is only reset if the TSC is disabled in the new state. + +If any of the programmable counters are enabled, then the thread's +CPU affinity mask is adjusted to exclude the set of forbidden CPUs. + +If the control data activates any interrupt-mode counters, then +a signal (specified by the 'si_signo' control field) will be sent +to the owner thread after an overflow interrupt. The documentation +for sys_vperfctr_iresume() describes this mechanism. + +If 'fd' does not denote the current thread, then it must denote a +thread that is stopped and under ptrace control by the current thread. +The perfctr state object denoted by 'fd' must still be attached +to its owner thread. + +Notes: +- It is strongly recommended to memset() the vperfctr_control object + to all-bits-zero before setting the fields of interest. +- Stopping the counters is done by invoking the control operation + with a control object that activates neither the TSC nor any PMCs. + +Unlinking the State +------------------- +int err = sys_vperfctr_unlink(int fd); + +'fd' must be the return value from a call to sys_vperfctr_open(). + +This operation stops and samples the thread's counters, and then +detaches the perfctr state object from the thread. If the object +already had been detached, then no action is performed. + +If 'fd' does not denote the current thread, then it must denote a +thread that is stopped and under ptrace control by the current thread. + +Reading the State +----------------- +int err = sys_vperfctr_read(int fd, struct perfctr_sum_ctrs *sum, + struct vperfctr_control *control); + +'fd' must be the return value from a call to sys_vperfctr_open(). + +This operation copies data from the perfctr state object to +user-space. If 'sum' is non-NULL, then the counter sums are +written to it. If 'control' is non-NULL, then the control data +is written to it. + +If the perfctr state object is attached to the current thread, +then the counters are sampled and updated first. + +If 'fd' does not denote the current thread, then it must denote a +thread that is stopped and under ptrace control by the current thread. + +Notes: +- An alternate and faster way to retrieve the counter sums is described + below. This system call can be used if the hardware does not permit + user-space reads of the counters. + +Resuming After Handling Overflow Signal +--------------------------------------- +int err = sys_vperfctr_iresume(int fd); + +'fd' must be the return value from a call to sys_vperfctr_open(). +The perfctr object must still be attached to its owner thread. + +When an interrupt-mode counter has overflowed, the counters +are sampled and suspended (TSC remains active). Then a signal, +as specified by the 'si_signo' control field, is sent to the +owner thread: the associated 'struct siginfo' has 'si_code' +equal to 'SI_PMC_OVF', and 'si_pmc_ovf_mask' equal to the set +of overflown counters. + +The counters are suspended to avoid generating new performance +counter events during the execution of the signal handler, but +the previous settings are saved. Calling sys_vperfctr_iresume() +restores the previous settings and resumes the counters. Doing +this is optional. + +If 'fd' does not denote the current thread, then it must denote a +thread that is stopped and under ptrace control by the current thread. + +Reading the Counter Values +-------------------------- +The value of a counter is computed from three components: + + value = sum + (now - start); + +Two of these (sum and start) reside in the kernel's state object, +and the third (now) is the contents of the hardware counter. +To perform this computation in user-space requires access to +the state object. This is achieved by passing the file descriptor +from sys_vperfctr_open() to mmap(): + + volatile const struct vperfctr_state *kstate; + kstate = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); + +Reading the three components is a non-atomic operation. If the +thread is scheduled during the operation, the three values will +not be consistent and the wrong result will be computed. +To detect this situation, user-space should check the kernel +state's TSC start value before and after the operation, and +retry the operation in case of a mismatch. + +The algorithm for retrieving the value of counter 'i' is: + + tsc0 = kstate->cpu_state.tsc_start; + for(;;) { + rdpmcl(kstate->cpu_state.pmc[i].map, now); + start = kstate->cpu_state.pmc[i].start; + sum = kstate->cpu_state.pmc[i].sum; + tsc1 = kstate->cpu_state.tsc_start; + if (likely(tsc1 == tsc0)) + break; + tsc0 = tsc1; + } + return sum + (now - start); + +The algorithm for retrieving the value of the TSC is similar, +as is the algorithm for retrieving the values of all counters. + +Notes: +- Since the state's TSC time-stamps are used, the algorithm requires + that user-space enables TSC sampling. +- The algorithm requires that the hardware allows user-space reads + of the counter registers. If this property isn't statically known + for the architecture, user-space should retrieve the kernel's + 'struct perfctr_info' object and check that the PERFCTR_FEATURE_RDPMC + flag is set. + +Limitations / TODO List +======================= +- Perfctr settings are not inherited from parent to child at fork(). + The issue is not fork() but propagating final counts from children + to parents, and allowing user-space to distinguish "self" counts + from "children" counts. + An implementation of this feature is being planned. +- Buffering of overflow samples is not implemented. So far, not a + single user has requested it. --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/powerpc/mpc52xx.txt 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,48 @@ +Linux 2.6.x on MPC52xx family +----------------------------- + +For the latest info, go to http://www.246tNt.com/mpc52xx/state.txt + +To compile/use : + + - U-Boot: + # tftpboot 200000 uImage + => tftpboot 400000 pRamdisk + => bootm 200000 400000 + + - DBug: + # dn -i zImage.initrd.lite5200 + + +Some remarks : + - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 + is not supported, and I'm not sure anyone is interesting in working on it + so. I didn't took 5xxx because there's apparently a lot of 5xxx that have + nothing to do with the MPC5200. I also included the 'MPC' for the same + reason. + - Of course, I inspired myself from the 2.4 port. If you think I forgot to + mention you/your company in the copyright of some code, I'll correct it + ASAP. + - The codes wants the MBAR to be set at 0xf0000000 by the bootloader. It's + mapped 1:1 with the MMU. If for whatever reason, you want to change this, + beware that some code depends on the 0xf0000000 address and other depends + on the 1:1 mapping. + - Most of the code assumes that port multiplexing, frequency selection, ... + has already been done. IMHO this should be done as early as possible, in + the bootloader. If for whatever reason you can't do it there, do it in the + platform setup code (if U-Boot) or in the arch/ppc/boot/simple/... (if + DBug) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/should-fix.txt 2004-07-13 17:09:27.000000000 -0700 @@ -0,0 +1,422 @@ +Not-ready features and speedups +=============================== + +Legend: + +PRI1: We're totally lame if this doesn't get in +PRI2: Would be nice +PRI3: Not very important + +drivers/block/ +~~~~~~~~~~~~~~ + +drivers/char/rtc/ +~~~~~~~~~~~~~~~~~ + +o rmk, trini: add support for alarms to the existing generic rtc driver. + + PRI2 + +console drivers +~~~~~~~~~~~~~~~ + (Pavel Machek ) + +o There are few must-fix bugs in cursor handling. + +o Play with gpm selection for a while and your cursor gets corrupted with + random dots. Ouch. + +device mapper +~~~~~~~~~~~~~ + +o ioctl interface cleanup patch is ready (redo the structure layouts) + + PRI1 + +o A port of the 2.4 snapshot and mirror targets is in progress + + PRI1 + +o the fs interface to dm needs to be redone. gregkh was going to work on + this. viro is interested in seeing work thus-far. + + PRI2 + +drivers/net/wireless/ +~~~~~~~~~~~~~~~~~~~~~ + + (Jean Tourrilhes ) + +o get HostAP driver in the kernel. No consolidation of the 802.11 + management across driver can happen until this one is in (which is probably + 2.7.X material). I think Jouni is mostly ready but didn't find time for + it. + + PRI2 + +o get more wireless drivers into the kernel. The most "integrable" drivers + at this point seem the NWN driver, Pavel's Spectrum driver. + + PRI1 + +drivers/usb/gadget/ +~~~~~~~~~~~~~~~~~~~ + +o rmk: SA11xx USB client/gadget code (David B has been doing some work on + this, and keeps trying to prod me, but unfortunately I haven't had the time + to look at his work, sorry David.) + + PRI3 + +fs/ +~~~ + +o ext3 and ext2 block allocators have serious failure modes - interleaved + allocations. (Reservation patch in -mm). + + PRI3 + +o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling + patches. They make reiserfs a lot safer. + + Ordered: PRI2 + data journalled: PRI3 + +o viro: convert more filesystems to use lib/parser.c for options. + + PRI2 + +o aio: fs IO isn't async at present. suparna has restart patches, they're + in -mm. Need to get Ben to review/comment. + + PRI1. + +o drepper: various filesystems use ->pid wrongly + + PRI1 + +kernel/ +~~~~~~~ + +o rusty: Zippel's Reference count simplification. Tricky code, but cuts + about 120 lines from module.c. Patch exists, needs stressing. + + PRI3 + +o rusty: Fix module-failed-init races by starting module "disabled". Patch + exists, requires some subsystems (ie. add_partition) to explicitly say + "make module live now". Without patch we are no worse off than 2.4 etc. + + PRI1 + +o kexec. Seems to work, was in -mm. + + PRI3 + +o rmk: lib/inflate.c must not use static variables (causes these to be + referenced via GOTOFF relocations in PIC decompressor. We have a PIC + decompressor to avoid having to hard code a per platform zImage link + address into the makefiles.) + + PRI2 + + +mm/ +~~~ + + +net/ +~~~~ + + (davem) + +o Real serious use of IPSEC is hampered by lack of MPLS support. MPLS is a + switching technology that works by switching based upon fixed length labels + prepended to packets. Many people use this and IPSEC to implement VPNs + over public networks, it is also used for things like traffic engineering. + + A good reference site is: + + http://www.mplsrc.com/ + + Anyways, an existing (crappy) implementation exists. I've almost + completed a rewrite, I should have something in the tree next week. + + PRI1 + +o Sometimes we generate IP fragments when it truly isn't necessary. + + The way IP fragmentation is specified, each fragment must be modulo 8 + bytes in length. So suppose the device has an MTU that is not 0 modulo 8, + ethernet even classifies in this way. 1500 == (8 * 187) + 4 + + Our IP fragmenting engine can fragment on packets that are sized within + the last modulo 8 bytes of the MTU. This happens in obscure cases, but it + does happen. + + I've proposed a fix to Alexey, whereby very late in the output path we + check the packet, if we fragmented but the data length would fit into the + MTU we unfragment the packet. + + This is low priority, because technically it creates suboptimal behavior + rather than mis-operation. + + PRI1 + +net/*/netfilter/ +~~~~~~~~~~~~~~~~ + +o Lots of misc. cleanups, which are happening slowly. + + PRI2 + +power management +~~~~~~~~~~~~~~~~ + +o Pat and Pavel disagree over swsusp. Need to sort that out. + + PRI2 + +o Frame buffer, AGP, DRI restore. + + PRI2 + +o XFree86 hooks + + PRI2 + +o IDE suspend/resume without races (Ben is looking at this a little) + + PRI2 + +o Pat: There are already CPU device structures; MTRRs should be a + dynamically registered interface of CPUs, which implies there needs + to be some other glue to know that there are MTRRs that need to be + saved/restored. + + PRI1 + +global +~~~~~~ + +o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit + means extra work on nfsd/raid/etc. + +o We need a kernel side API for reporting error events to userspace (could + be async to 2.6 itself) + + (Prototype core based on netlink exists) + + PRI2 + +o Kai: Introduce a sane, easy and standard way to build external modules + - make clean and make modules_install are both broken + + PRI2 + +drivers +~~~~~~~ + +o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do + multiheader right and so on + + PRI1 + +drivers/acpi/ +~~~~~~~~~~~~~ + +o alan: VIA APIC stuff is one bit of this, there are also some other + reports that were caused by ACPI not setting level v edge trigger some + times + + PRI1 + +o mochel: it seems the acpi irq routing code could use a serious rewrite. + + grover: The problem is the ACPI irq routing code is trying to piggyback + on the existing MPS-specific data structures, and it's generally a hack. + So yes mochel is right, but it is also purging MPS-ities from common code + as well. I've done some preliminary work in this area and it doesn't seem + to break anything (yet) but a rewrite in this area imho should not be + rushed out the door. And, I think the above bugs can be fixed w/o the + rewrite. + + PRI2 + +o mochel: ACPI suspend doesn't work. Important, not cricital. Pat is + working it. + + PRI2 + +drivers/block/ +~~~~~~~~~~~~~~ + + +drivers/char/ +~~~~~~~~~~~~~ + + +drivers/ide/ +~~~~~~~~~~~~ + + (Alan) + +o IDE races, PIO problems, simplex, hotplug, taskfile. + + PRI2 + + +drivers/isdn/ +~~~~~~~~~~~~~ + + (Kai, rmk) + +o locking fixes, cleanups, adaption to recent APIs etc + + PRI2 + +o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent + 3-set patch for serial stuff) + + Alternatively, we could re-introduce the fallback to driver ioctl parsing + for these if not enough drivers get updated. + + PRI3 + +drivers/net/ +~~~~~~~~~~~~ + +o davej: Either Wireless network drivers or PCMCIA broke somewhen. A + configuration that worked fine under 2.4 doesn't receive any packets. Need + to look into this more to make sure I don't have any misconfiguration that + just 'happened to work' under 2.4 + + PRI1 + +drivers/scsi/ +~~~~~~~~~~~~~ + +o jejb: qlogic - + + o Merge the feral driver. It covers all qlogic chips: 1020 all the way + up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5 + + o qla2xxx: only for FC chips. Has significant build issues. hch + promises to send me a "must fix" list for this. + http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5 + + PRI2 + +o hch, Mike Anderson, Badari Pulavarty: scsi locking issues + + o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd + with very unclear locking, many of them probably want to become + atomic_t's or bitmaps (for the 1bit bitfields). + + o there's lots of volatile abuse in the scsi code that needs to be + thought about. + + o there's some global variables incremented without any locks + + PRI2 + +sound/ +~~~~~~ + + (rmk) + +o ALSA-fication of drivers, forward port 2.4 bugfixes + (Killing off OSS is 2.7 material) + +PRI2 + +arch/i386/ +~~~~~~~~~~ + +o davej: PAT support (for mtrr exhaustion w/ AGP) + + PRI2 + +o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan + Hollis) + + alan: ECC - I have some test bits from Dan's stuff - they need no kernel + core changes for most platforms. That means we can treat it as a random + driver merge. + + PRI3 + + +arch/x86_64/ +~~~~~~~~~~~~ + + (Andi) + +o need to coredump 64bit vsyscall code with dwarf2 + + PRI2 + +o move 64bit signal trampolines into vsyscall code and add dwarf2 for it. + (in progress) + + PRI1 + +o describe kernel assembly with dwarf2 annotations for kgdb + + PRI3 + +arch/alpha/ +~~~~~~~~~~~ + +o rth: Ptrace writes are broken. This means we can't (reliably) set + breakpoints or modify variables from gdb. + + PRI1 + +arch/arm/ +~~~~~~~~~ + +o rmk: missing raw keyboard translation tables for all ARM machines. + Haven't even looked into this at all. This could be messy since there + isn't an ARM architecture standard. I'm presently hoping that it won't be + an issue. If it does, I guess we'll see drivers/char/keyboard.c explode. + + PRI2 + +arch/others/ +~~~~~~~~~~~~ + +o SH needs resyncing, as do some other ports. SH64 needs merging. + No impact on mainstream platforms hopefully. + + PRI2 + +arch/s390/ +~~~~~~~~~ + + +drivers/s390/ +~~~~~~~~~~~~~ + +o The 3270 console driver needs to be replaced with a working one + (prototype is there, needs to be finished). + + PRI2 + +o Minor interface changes are pending in cio/ when the z990 machines are + out. + + PRI2 + +o a block device driver for ramdisks shared among virtual machines + + PRI3 + +o driver for crypto hardware + + PRI3 + +o 'claw' network device driver + + PRI3 + --- linux-2.6.8-rc1/Documentation/sound/alsa/ALSA-Configuration.txt 2004-06-15 23:29:40.000000000 -0700 +++ 25/Documentation/sound/alsa/ALSA-Configuration.txt 2004-07-13 17:09:19.000000000 -0700 @@ -516,6 +516,13 @@ Module parameters Module for ForteMedia FM801 based PCI soundcards. + tea575x_tuner - Enable TEA575x tuner + - 1 = MediaForte 256-PCS + - 2 = MediaForte 256-PCPR + - 3 = MediaForte 64-PCR + - High 16-bits are video (radio) device number + 1 + - example: 0x10002 (MediaForte 256-PCPR, device 1) + Module supports up to 8 cards and autoprobe. Module snd-gusclassic @@ -613,7 +620,7 @@ Module parameters model - Use the given board model, one of the following: delta1010, dio2496, delta66, delta44, audiophile, delta410, delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d, - dmx6fire, dsp24, dsp24_71, ez8 + dmx6fire, dsp24, dsp24_value, dsp24_71, ez8 omni - Omni I/O support for MidiMan M-Audio Delta44/66 cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever) in msec resolution, default value is 500 (0.5 sec) @@ -631,7 +638,8 @@ Module parameters * TerraTec Aureon Sky-5.1, Space-7.1 model - Use the given board model, one of the following: - revo71, amp2000, prodigy71, aureon51, aureon71 + revo71, amp2000, prodigy71, aureon51, aureon71, + k8x800 Module supports up to 8 cards and autoprobe. --- linux-2.6.8-rc1/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 2004-06-15 23:29:40.000000000 -0700 +++ 25/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 2004-07-13 17:09:19.000000000 -0700 @@ -18,8 +18,8 @@ - Mar. 6, 2004 - 0.3.1 + June 29, 2004 + 0.3.2 @@ -411,10 +411,6 @@ // "PCI Resource Managements" }; - // this should be go into - // (see "Management of Cards and Components") - #define mychip_t_magic 0xa15a4501 - // chip-specific destructor // (see "PCI Resource Managements") static int snd_mychip_free(mychip_t *chip) @@ -426,8 +422,7 @@ // (see "Management of Cards and Components") static int snd_mychip_dev_free(snd_device_t *device) { - mychip_t *chip = snd_magic_cast(mychip_t, - device->device_data, return -ENXIO); + mychip_t *chip = device->device_data; return snd_mychip_free(chip); } @@ -448,8 +443,8 @@ // check PCI availability here // (see "PCI Resource Managements") - // allocate a chip-specific data with magic-alloc - chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); + // allocate a chip-specific data with zero filled + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -906,13 +901,6 @@ - You might have objections against such a typedef, but this - typedef is necessary if you use a magic-cast - (explained later). - - - In general, there are two ways to allocate the chip record. @@ -943,9 +931,8 @@ - With this method, you don't have to allocate twice. But you - cannot use magic-cast for this record pointer, - instead. + With this method, you don't have to allocate twice. + The record is released together with the card instance. @@ -956,7 +943,7 @@ After allocating a card instance via snd_card_new() (with NULL on the 4th arg), call - snd_magic_kcalloc(). + kcalloc(). @@ -965,13 +952,10 @@ mychip_t *chip; card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); ..... - chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); ]]> - - Once when the record is allocated via snd_magic stuff, you - can use magic-cast for the void pointer. @@ -1003,21 +987,6 @@ - Also, you need to define a magic-value for mychip_t. - - - - - - - (the detail will be described in the - - next subsection). - - - Next, initialize the fields, and register this chip record as a low-level device with a specified ops, @@ -1045,8 +1014,7 @@ device_data, - return -ENXIO); + mychip_t *chip = device->device_data; return snd_mychip_free(chip); } ]]> @@ -1057,127 +1025,6 @@ -
- Not a magic but a logic - - Now, you might have a question: What is the advantage of the - second method? Obviously, it looks far more complicated. - - As I wrote many times, the second method allows a - magic-cast for mychip_t. If you - have a void pointer (such as - pcm->private_data), the pointer type - is unknown at the compile time, and you cannot know even if a - wrong pointer type is passed. The compiler would accept - it. The magic-cast checks the pointer type at the runtime (and - whether it's a null pointer, too). Hence, the cast will be - much safer and good for debugging. - - - - As you have already seen, allocation with a magic-header can - be done via snd_magic_kmalloc() or - snd_magic_kcalloc(). - - - - - - - - The difference of these two functions is whether the area is - zero-cleared (kcalloc) or not - (kmalloc). - - - - The first argument of the allocator is the type of the - record. The magic-constant has to be defined for this type - beforehand. In this case, we'll need to define - mychip_t_magic, for example, as already - seen, - - - - - - - - The value is arbitrary but should be unique. - This is usually defined in - <include/sndmagic.h> or - <include/amagic.h> for alsa-driver tree, - but you may define it locally in the code at the early - development stage, since changing - sndmagic.h will lead to the recompilation - of the whole driver codes. - - - - The second argument is the extra-data length. It is usually - zero. The third argument is the flags to be passed to kernel - memory allocator, GFP_XXX. Normally, - GFP_KERNEL is passed. - - - - For casting a pointer, use - snd_magic_cast() macro: - - - - - - - - where source_pointer is the pointer to - be casted (e.g. pcm->private_data), and - action is the action to do if the cast - fails (e.g. return -EINVAL). - - - - For releasing the magic-allocated data, you need to call - snd_magic_kfree() function instead of - kfree(). - - - - - - - - - - If you call kfree() for the - magic-allocated value, it will lead to memory leaks. - When the ALSA drivers are compiled with - CONFIG_SND_DEBUG_MEMORY kernel config (or - configured with ), the - non-matching free will be checked and you'll see warning - messages. - - - - If you are 100% sure that your code is bug-free, you can - compile the driver without - CONFIG_SND_DEBUG_MEMORY kernel config, - so that the magic-allocator and the magic-cast will be - replaced to the normal kmalloc and cast. - -
- -
Registration and Release @@ -1257,7 +1104,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); // release the data - snd_magic_kfree(chip); + kfree(chip); return 0; } @@ -1283,7 +1130,7 @@ return -ENXIO; } - chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -1436,7 +1283,7 @@ need to initialize this number as -1 before actual allocation, since irq 0 is valid. The port address and its resource pointer can be initialized as null by - snd_magic_kcalloc() automatically, so you + kcalloc() automatically, so you don't have to take care of resetting them. @@ -1517,16 +1364,13 @@ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); + mychip_t *chip = dev_id; .... return IRQ_HANDLED; } ]]> - - Again the magic-cast is used here to get the correct pointer - from the second argument. @@ -1583,19 +1427,14 @@ - The chip instance is freed via - snd_magic_kfree(). Please use this function - for the object allocated by - snd_magic_kmalloc(). If you free it with - kfree(), it won't work properly and will - result in the memory leak. Also, again, remember that you cannot + Again, remember that you cannot set __devexit prefix for this destructor. @@ -1857,9 +1696,6 @@ #include .... - #define chip_t mychip_t - .... - /* hardware definition */ static snd_pcm_hardware_t snd_mychip_playback_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -2224,8 +2060,7 @@ private_data, return); + mychip_t *chip = snd_pcm_chip(pcm); // free your own data kfree(chip->my_private_pcm_data); // do what you like else... @@ -2653,8 +2488,11 @@ struct _snd_pcm_runtime { done in the open callback. - Since it's a void pointer, you should use magic-kmalloc and - magic-cast for such an object. + Don't mix this with pcm->private_data. + The pcm->private_data usually points the + chip instance assigned statically at the creation of PCM, while the + runtime->private_data points a dynamic + data created at the PCM open callback. @@ -2663,7 +2501,7 @@ struct _snd_pcm_runtime { { my_pcm_data_t *data; .... - data = snd_magic_kmalloc(my_pcm_data_t, 0, GFP_KERNEL); + data = kmalloc(sizeof(*data), GFP_KERNEL); substream->runtime->private_data = data; .... } @@ -2710,8 +2548,6 @@ struct _snd_pcm_runtime { - - - It's expanded with a magic-cast, so the cast-error is - automatically checked. You should define chip_t at - the beginning of the code, since this will be referred in many - places of pcm and control interfaces. + The macro reads substream->private_data, + which is a copy of pcm->private_data. + You can override the former if you need to assign different data + records per PCM substream. For example, cmi8330 driver assigns + different private_data for playback and capture directions, + because it uses two different codecs (SB- and AD-compatible) for + different directions.
@@ -2803,7 +2640,7 @@ struct _snd_pcm_runtime { static int snd_xxx_close(snd_pcm_substream_t *substream) { .... - snd_magic_kfree(substream->runtime->private_data); + kfree(substream->runtime->private_data); .... } ]]> @@ -3176,7 +3013,7 @@ struct _snd_pcm_runtime { static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); + mychip_t *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { @@ -3220,7 +3057,7 @@ struct _snd_pcm_runtime { static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); + mychip_t *chip = dev_id; spin_lock(&chip->lock); .... if (pcm_irq_invoked(chip)) { @@ -3988,8 +3825,7 @@ struct _snd_pcm_runtime { static unsigned short snd_mychip_ac97_read(ac97_t *ac97, unsigned short reg) { - mychip_t *chip = snd_magic_cast(mychip_t, - ac97->private_data, return 0); + mychip_t *chip = ac97->private_data; .... // read a register value here from the codec return the_register_value; @@ -3998,8 +3834,7 @@ struct _snd_pcm_runtime { static void snd_mychip_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - mychip_t *chip = snd_magic_cast(mychip_t, - ac97->private_data, return 0); + mychip_t *chip = ac97->private_data; .... // write the given register value to the codec } @@ -4096,8 +3931,7 @@ struct _snd_pcm_runtime { static unsigned short snd_mychip_ac97_read(ac97_t *ac97, unsigned short reg) { - mychip_t *chip = snd_magic_cast(mychip_t, - ac97->private_data, return 0); + mychip_t *chip = ac97->private_data; .... return the_register_value; } @@ -4375,7 +4209,7 @@ struct _snd_pcm_runtime { private_data, ); + mpu = rmidi->private_data; ]]> @@ -4546,16 +4380,15 @@ struct _snd_pcm_runtime { You can then pass any pointer value to the - private_data. Again, it should be a - magic-allocated record, so that the cast can be checked more - safely. If you assign a private data, you should define the + private_data. + If you assign a private data, you should define the destructor, too. The destructor function is set to private_free field. private_data = p; hw->private_free = mydata_free; ]]> @@ -4569,9 +4402,8 @@ struct _snd_pcm_runtime { private_data, return); - snd_magic_kfree(p); + mydata_t *p = hw->private_data; + kfree(p); } ]]> @@ -5097,8 +4929,7 @@ struct _snd_pcm_runtime { static void my_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - chip_t *cm = snd_magic_cast(mychip_t, - entry->private_data, return); + chip_t *chip = entry->private_data; snd_iprintf(buffer, "This is my chip!\n"); snd_iprintf(buffer, "Port = %ld\n", chip->port); @@ -5266,8 +5097,7 @@ struct _snd_pcm_runtime { static int mychip_suspend(snd_card_t *card, unsigned int state) { // (1) - mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data, - return -ENXIO); + mychip_t *chip = card->pm_private_data; // (2) snd_pcm_suspend_all(chip->pcm); // (3) @@ -5309,8 +5139,7 @@ struct _snd_pcm_runtime { static void mychip_resume(mychip_t *chip) { // (1) - mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data, - return -ENXIO); + mychip_t *chip = card->pm_private_data; // (2) pci_enable_device(chip->pci); // (3) @@ -5427,19 +5256,7 @@ struct _snd_pcm_runtime { The module parameters must be declared with the standard module_param()(), module_param_array()() and - MODULE_PARM_DESC() macros. The ALSA provides - an additional macro, MODULE_PARM_SYNTAX(), - for describing its syntax. The strings will be written to - /lib/modules/XXX/modules.generic_string - file. - - - - For convenience, the typical string arguments given to - MODULE_PARM_SYNTAX() are defined in - <sound/initval.h>, such as - SNDRV_ID_DESC or - SNDRV_ENABLED. + MODULE_PARM_DESC() macros. @@ -5453,13 +5270,10 @@ struct _snd_pcm_runtime { static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); - MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); - MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); - MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); ]]> @@ -5478,9 +5292,8 @@ struct _snd_pcm_runtime { --- linux-2.6.8-rc1/Documentation/usb/error-codes.txt 2004-04-03 20:39:10.000000000 -0800 +++ 25/Documentation/usb/error-codes.txt 2004-07-13 17:09:24.000000000 -0700 @@ -47,6 +47,8 @@ USB-specific: -ESHUTDOWN The host controller has been disabled due to some problem that could not be worked around. +-EPERM Submission failed because urb->reject was set. + ************************************************************************** * Error codes returned by in urb->status * --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/Documentation/usb/sn9c102.txt 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,276 @@ + + SN9C10[12] PC Camera Controllers + Driver for Linux + ================================ + + - Documentation - + + +Index +===== +1. Copyright +2. License +3. Overview +4. Module dependencies +5. Module loading +6. Module parameters +7. Device control through "sysfs" +8. Supported devices +9. How to add support for new image sensors +10. Note for V4L2 developers +11. Contact information +12. Credits + + +1. Copyright +============ +Copyright (C) 2004 by Luca Risolia + +SONiX is a trademark of SONiX Technology Company Limited, inc. +This driver is not sponsored or developed by SONiX. + + +2. License +========== +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + +3. Overview +=========== +This driver attempts to support the video streaming capabilities of the devices +mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers. + +- It's worth to note that SONiX has never collaborated with me during the +development of this project, despite of several requests for enough detailed +specifications of the register tables, compression engine and video data format +of the above chips - + +Up to 64 cameras can be handled at the same time. They can be connected and +disconnected from the host many times without turning off the computer, if +your system supports the hotplug facility. + +The driver relies on the Video4Linux2 and USB core modules. It has been +designed to run properly on SMP systems as well. + +The latest version of the SN9C10[12] driver can be found at the following URL: +http://go.lamarinapunto.com/ + + +4. Module dependencies +====================== +For it to work properly, the driver needs kernel support for Video4Linux and +USB. + +The following options of the kernel configuration file must be enabled and +corresponding modules must be compiled: + + # Multimedia devices + # + CONFIG_VIDEO_DEV=m + + # USB support + # + CONFIG_USB=m + +In addition, depending on the hardware being used, the modules below are +necessary: + + # USB Host Controller Drivers + # + CONFIG_USB_EHCI_HCD=m + CONFIG_USB_UHCI_HCD=m + CONFIG_USB_OHCI_HCD=m + +And finally: + + # USB Multimedia devices + # + CONFIG_USB_SN9C102=m + + +5. Module loading +================= +To use the driver, it is necessary to load the "sn9c102" module into memory +after every other module required: "videodev", "usbcore" and, depending on +the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd". + +Loading can be done as shown below: + + [root@localhost home]# modprobe usbcore + [root@localhost home]# modprobe sn9c102 + +At this point the devices should be recognized. You can invoke "dmesg" to +analyze kernel messages and verify that the loading process has gone well: + + [user@localhost home]$ dmesg + + +6. Module parameters +==================== +Module parameters are listed below: +------------------------------------------------------------------------------- +Name: video_nr +Type: int array (min = 0, max = 32) +Syntax: <-1|n[,...]> +Description: Specify V4L2 minor mode number: + -1 = use next available + n = use minor number n + You can specify up to 32 cameras this way. + For example: + video_nr=-1,2,-1 would assign minor number 2 to the second + recognized camera and use auto for the first one and for every + other camera. +Default: -1 +------------------------------------------------------------------------------- +Name: debug +Type: int +Syntax: +Description: Debugging information level, from 0 to 3: + 0 = none (use carefully) + 1 = critical errors + 2 = significant informations + 3 = more verbose messages + Level 3 is useful for testing only, when just one device + is used. +Default: 2 +------------------------------------------------------------------------------- + + +7. Device control through "sysfs" +================================= +It is possible to read and write both the SN9C10[12] and the image sensor +registers by using the "sysfs" filesystem interface. + +Every time a supported device is recognized, read-only files named "redblue" +and "green" are created in the /sys/class/video4linux/videoX directory. You can +set the red, blue and green channel's gain by writing the desired value to +them. The value may range from 0 to 15 for each channel; this means that +"redblue" accepts 8-bit values, where the low 4 bits are reserved for red and +the others for blue. + +There are other four entries in the directory above for each registered camera: +"reg", "val", "i2c_reg" and "i2c_val". The first two files control the +SN9C10[12] bridge, while the other two control the sensor chip. "reg" and +"i2c_reg" hold the values of the current register index where the following +reading/writing operations are addressed at through "val" and "i2c_val". Their +use is not intended for end-users, unless you know what you are doing. Note +that "i2c_reg" and "i2c_val" won't be created if the sensor does not actually +support the standard I2C protocol. Also, remember that you must be logged in as +root before writing to them. + +As an example, suppose we were to want to read the value contained in the +register number 1 of the sensor register table - which usually is the product +identifier - of the camera registered as "/dev/video0": + + [root@localhost #] cd /sys/class/video4linux/video0 + [root@localhost #] echo 1 > i2c_reg + [root@localhost #] cat i2c_val + +Now let's set the green gain's register of the SN9C10[12] chip to 2: + + [root@localhost #] echo 0x11 > reg + [root@localhost #] echo 2 > val + +Note that the SN9C10[12] always returns 0 when some of its registers are read. +To avoid race conditions, all the I/O accesses to the files are serialized. + + +8. Supported devices +==================== +- I won't mention any of the names of the companies as well as their products +here. They have never collaborated with me, so no advertising - + +From the point of view of a driver, what unambiguously identify a device are +its vendor and product USB identifiers. Below is a list of known identifiers of +devices mounting the SN9C10[12] PC camera controllers: + +Vendor ID Product ID +--------- ---------- +0xc45 0x6001 +0xc45 0x6005 +0xc45 0x6009 +0xc45 0x600d +0xc45 0x6024 +0xc45 0x6025 +0xc45 0x6028 +0xc45 0x6029 +0xc45 0x602a +0xc45 0x602c +0xc45 0x8001 + +The list above does NOT imply that all those devices work with this driver: up +until now only the ones that mount the following image sensors are supported. +Kernel messages will always tell you whether this is the case: + +Model Manufacturer +----- ------------ +PAS106B PixArt Imaging Inc. +TAS5110C1B Taiwan Advanced Sensor Corporation +TAS5130D1B Taiwan Advanced Sensor Corporation + +If you think your camera is based on the above hardware and is not actually +listed in the above table, you may try to add the specific USB VendorID and +ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h"; +then compile, load the module again and look at the kernel output. +If this works, please send an email to me reporting the kernel messages, so +that I will add a new entry in the list of supported devices. + +Donations of new models for further testing and support would be much +appreciated. I won't add official support for hardware that I don't actually +have. + + +9. How to add support for new image sensors +=========================================== +It should be easy to write code for new sensors by using the small API that I +have created for this purpose, which is present in "sn9c102_sensor.h" +(documentation is included there). As an example, have a look at the code in +"sn9c102_pas106b.c", which uses the mentioned interface. + +At the moment, not yet supported image sensors are: PAS202B (VGA), +HV7131[D|E1] (VGA), MI03 (VGA), OV7620 (VGA). + + +10. Note for V4L2 developers +============================ +This driver follows the V4L2 API specifications. In particular, it enforces two +rules: + +1) Exactly one I/O method, either "mmap" or "read", is associated with each +file descriptor. Once it is selected, the application must close and reopen the +device to switch to the other I/O method. + +2) Previously mapped buffer memory must always be unmapped before calling any +of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. In case, +the same number of buffers as before will be allocated again to match the size +of the new video frames, so you have to map them again before any I/O attempts. + + +11. Contact information +======================= +I may be contacted by e-mail at . + +I can accept GPG/PGP encrypted e-mail. My GPG key ID is 'FCE635A4'. +My public 1024-bit key should be available at any keyserver; the fingerprint +is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'. + + +12. Credits +=========== +I would thank the following persons: + +- Stefano Mozzi, who donated 45 EU; +- Luca Capello for the donation of a webcam; +- Mizuno Takafumi for the donation of a webcam. --- linux-2.6.8-rc1/Documentation/usb/w9968cf.txt 2004-02-03 20:42:34.000000000 -0800 +++ 25/Documentation/usb/w9968cf.txt 2004-07-13 17:09:24.000000000 -0700 @@ -23,6 +23,9 @@ Index ============ Copyright (C) 2002-2004 by Luca Risolia +Winbond is a trademark of Winbond Electronics Corporation. +This driver is not sponsored or developed by Winbond. + 2. License ========== @@ -44,8 +47,8 @@ Foundation, Inc., 675 Mass Ave, Cambridg 3. Overview =========== This driver supports the video streaming capabilities of the devices mounting -Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they -are being commanded by USB. OV681 based cameras should be supported as well. +Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips. OV681 +based cameras should be supported as well. The driver is divided into two modules: the basic one, "w9968cf", is needed for the supported devices to work; the second one, "w9968cf-vpp", is an optional @@ -58,7 +61,8 @@ Please keep in mind that official kernel performance purposes. However it is always recommended to download and install the latest and complete release of the driver, replacing the existing one, if present: it will be still even possible not to load the "w9968cf-vpp" module at -all, if you ever want to. +all, if you ever want to. Another important missing feature of the version in +the official Linux 2.4 kernels is the writeable /proc filesystem interface. The latest and full-featured version of the W996[87]CF driver can be found at: http://go.lamarinapunto.com/ . Please refer to the documentation included in @@ -68,38 +72,37 @@ Up to 32 cameras can be handled at the s disconnected from the host many times without turning off the computer, if your system supports the hotplug facility. -To change the default settings for each camera, many paramaters can be passed +To change the default settings for each camera, many parameters can be passed through command line when the module is loaded into memory. -The driver relies on the Video4Linux, USB and I2C core modules of the official -Linux kernels. It has been designed to run properly on SMP systems as well. -At the moment, an additional module, "ovcamchip", is mandatory; it provides -support for some OmniVision CMOS sensors connected to the W996[87]CF chips. - -The "ovcamchip" module is part of the OV511 driver, version 2.27, which can be -downloaded from internet: -http://alpha.dyndns.org/ov511/ -To know how to compile it, read the documentation included in the OV511 -package. +The driver relies on the Video4Linux, USB and I2C core modules. It has been +designed to run properly on SMP systems as well. An additional module, +"ovcamchip", is mandatory; it provides support for some OmniVision image +sensors connected to the W996[87]CF chips; if found in the system, the module +will be automatically loaded by default (provided that the kernel has been +compiled with the automatic module loading option). 4. Supported devices ==================== At the moment, known W996[87]CF and OV681 based devices are: -- Aroma Digi Pen ADG-5000 Refurbished -- AVerTV USB -- Creative Labs Video Blaster WebCam Go -- Creative Labs Video Blaster WebCam Go Plus -- Die Lebon LDC-D35A Digital Kamera -- Ezonics EZ-802 EZMega Cam -- OPCOM Digi Pen VGA Dual Mode Pen Camera +- Aroma Digi Pen VGA Dual Mode ADG-5000 (unknown image sensor) +- AVerMedia AVerTV USB (SAA7111A, Philips FI1216Mk2 tuner, PT2313L audio chip) +- Creative Labs Video Blaster WebCam Go (OmniVision OV7610 sensor) +- Creative Labs Video Blaster WebCam Go Plus (OmniVision OV7620 sensor) +- Lebon LDC-035A (unknown image sensor) +- Ezonics EZ-802 EZMega Cam (OmniVision OV8610C sensor) +- OmniVision OV8610-EDE (OmniVision OV8610 sensor) +- OPCOM Digi Pen VGA Dual Mode Pen Camera (unknown image sensor) +- Pretec Digi Pen-II (OmniVision OV7620 sensor) +- Pretec DigiPen-480 (OmniVision OV8610 sensor) If you know any other W996[87]CF or OV681 based cameras, please contact me. The list above does NOT imply that all those devices work with this driver: up -until now only webcams that have a CMOS sensor supported by the "ovcamchip" +until now only webcams that have an image sensor supported by the "ovcamchip" module work. -For a list of supported CMOS sensors, please visit the author's homepage on +For a list of supported image sensors, please visit the author's homepage on this module: http://alpha.dyndns.org/ov511/ Possible external microcontrollers of those webcams are not supported: this @@ -112,8 +115,10 @@ additional testing and full support, wou 5. Module dependencies ====================== -For it to work properly, the driver needs kernel support for Video4Linux, -USB and I2C, and a third-party module for the CMOS sensor. +For it to work properly, the driver needs kernel support for Video4Linux, USB +and I2C, and the "ovcamchip" module for the image sensor. Make sure you are not +actually using any external "ovcamchip" module, given that the W996[87]CF +driver depends on the version of the module present in the official kernels. The following options of the kernel configuration file must be enabled and corresponding modules must be compiled: @@ -128,6 +133,10 @@ corresponding modules must be compiled: The I2C core module can be compiled statically in the kernel as well. + # OmniVision Camera Chip support + # + CONFIG_VIDEO_OVCAMCHIP=m + # USB support # CONFIG_USB=m @@ -141,19 +150,12 @@ below is necessary: CONFIG_USB_UHCI_HCD=m CONFIG_USB_OHCI_HCD=m -Also, make sure "Enforce bandwidth allocation" is NOT enabled. - And finally: # USB Multimedia devices # CONFIG_USB_W9968CF=m -The last module we need is "ovcamchip.o". To obtain it, you have to download -the OV511 package, version 2.27 - don't use other versions - and compile it -according to its documentation. -The package is available at http://alpha.dyndns.org/ov511/ . - 6. Module loading ================= @@ -164,11 +166,10 @@ Loading can be done this way, from root: [root@localhost home]# modprobe usbcore [root@localhost home]# modprobe i2c-core - [root@localhost ov511-x.xx]# insmod ./ovcamchip.ko [root@localhost home]# modprobe w9968cf -At this point the devices should be recognized: "dmesg" can be used to analyze -kernel messages: +At this point the pertinent devices should be recognized: "dmesg" can be used +to analyze kernel messages: [user@localhost home]$ dmesg @@ -180,9 +181,22 @@ explanation about them and which syntax [root@locahost home]# modinfo w9968cf -7. Module paramaters +7. Module parameters ==================== -Module paramaters are listed below: +Module parameters are listed below: +------------------------------------------------------------------------------- +Name: ovmod_load +Type: bool +Syntax: <0|1> +Description: Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled. + If enabled, 'insmod' searches for the required 'ovcamchip' + module in the system, according to its configuration, and + loads that module automatically. This action is performed as + once soon as the 'w9968cf' module is loaded into memory. +Default: 1 +Note: The kernel must be compiled with the CONFIG_KMOD option + enabled for the 'ovcamchip' module to be loaded and for + this parameter to be present. ------------------------------------------------------------------------------- Name: vppmod_load Type: bool @@ -191,10 +205,14 @@ Description: Automatic 'w9968cf-vpp' If enabled, every time an application attempts to open a camera, 'insmod' searches for the video post-processing module in the system and loads it automatically (if present). - The 'w9968cf-vpp' module adds extra image manipulation + The optional 'w9968cf-vpp' module adds extra image manipulation capabilities to the 'w9968cf' module,like software up-scaling, - colour conversions and video decoding. + colour conversions and video decompression for very high frame + rates. Default: 1 +Note: The kernel must be compiled with the CONFIG_KMOD option + enabled for the 'w9968cf-vpp' module to be loaded and for + this parameter to be present. ------------------------------------------------------------------------------- Name: simcams Type: int @@ -237,7 +255,7 @@ Syntax: <0|1[,...]> Description: Hardware double buffering: 0 disabled, 1 enabled. It should be enabled if you want smooth video output: if you obtain out of sync. video, disable it, or try to - decrease the 'clockdiv' module paramater value. + decrease the 'clockdiv' module parameter value. Default: 1 for every device. ------------------------------------------------------------------------------- Name: clamping @@ -252,7 +270,7 @@ Syntax: <0|1|2[,...]> Description: Video filter type. 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter. The filter is used to reduce noise and aliasing artifacts - produced by the CCD or CMOS sensor. + produced by the CCD or CMOS image sensor. Default: 0 for every device. ------------------------------------------------------------------------------- Name: largeview @@ -269,7 +287,7 @@ Description: Software scaling (for no Disable it if you have a slow CPU or you don't have enough memory. Default: 0 for every device. -Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 0. +Note: If 'w9968cf-vpp' is not present, this parameter is set to 0. ------------------------------------------------------------------------------- Name: decompression Type: int array (min = 0, max = 32) @@ -284,8 +302,8 @@ Description: Software video decompres YUV420P/YUV420 in any resolutions where width and height are multiples of 16. Default: 2 for every device. -Note: If 'w9968cf-vpp' is not loaded, forcing decompression is not - allowed; in this case this paramater is set to 2. +Note: If 'w9968cf-vpp' is not present, forcing decompression is not + allowed; in this case this parameter is set to 2. ------------------------------------------------------------------------------- Name: force_palette Type: int array (min = 0, max = 32) @@ -304,9 +322,9 @@ Description: Force picture palette. 3 = RGB565 16 bpp - Software conversion from UYVY 4 = RGB24 24 bpp - Software conversion from UYVY 5 = RGB32 32 bpp - Software conversion from UYVY - When not 0, this paramater will override 'decompression'. + When not 0, this parameter will override 'decompression'. Default: 0 for every device. Initial palette is 9 (UYVY). -Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 9. +Note: If 'w9968cf-vpp' is not present, this parameter is set to 9. ------------------------------------------------------------------------------- Name: force_rgb Type: bool array (min = 0, max = 32) @@ -320,14 +338,14 @@ Default: 0 for every device. Name: autobright Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> -Description: CMOS sensor automatically changes brightness: +Description: Image sensor automatically changes brightness: 0 = no, 1 = yes Default: 0 for every device. ------------------------------------------------------------------------------- Name: autoexp Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> -Description: CMOS sensor automatically changes exposure: +Description: Image sensor automatically changes exposure: 0 = no, 1 = yes Default: 1 for every device. ------------------------------------------------------------------------------- @@ -354,7 +372,7 @@ Syntax: <-1|n[,...]> Description: Force pixel clock divisor to a specific value (for experts): n may vary from 0 to 127. -1 for automatic value. - See also the 'double_buffer' module paramater. + See also the 'double_buffer' module parameter. Default: -1 for every device. ------------------------------------------------------------------------------- Name: backlight @@ -374,7 +392,7 @@ Default: 0 for every device. Name: monochrome Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> -Description: The CMOS sensor is monochrome: +Description: The image sensor is monochrome: 0 = no, 1 = yes Default: 0 for every device. ------------------------------------------------------------------------------- @@ -420,7 +438,7 @@ Description: Debugging information le 4 = warnings 5 = called functions 6 = function internals - Level 5 and 6 are useful for testing only, when just one + Level 5 and 6 are useful for testing only, when only one device is used. Default: 2 ------------------------------------------------------------------------------- @@ -449,7 +467,7 @@ The development would not have proceed m the source code of other drivers and without the help of several persons; in particular: -- the I2C interface to kernel and high-level CMOS sensor control routines have +- the I2C interface to kernel and high-level image sensor control routines have been taken from the OV511 driver by Mark McClelland; - memory management code has been copied from the bttv driver by Ralph Metzler, --- linux-2.6.8-rc1/drivers/acpi/dispatcher/dsmethod.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dsmethod.c 2004-07-13 17:09:17.000000000 -0700 @@ -145,8 +145,9 @@ acpi_ds_parse_method ( return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, op, node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -267,8 +268,9 @@ acpi_ds_call_control_method ( { acpi_status status; struct acpi_namespace_node *method_node; - union acpi_operand_object *obj_desc; struct acpi_walk_state *next_walk_state; + union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; u32 i; @@ -309,7 +311,6 @@ acpi_ds_call_control_method ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* Create and init a Root Node */ op = acpi_ps_create_scope_op (); @@ -320,7 +321,7 @@ acpi_ds_call_control_method ( status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - NULL, NULL, 1); + NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (next_walk_state); goto cleanup; @@ -348,9 +349,12 @@ acpi_ds_call_control_method ( */ this_walk_state->operands [this_walk_state->num_operands] = NULL; + info.parameters = &this_walk_state->operands[0]; + info.parameter_type = ACPI_PARAM_ARGS; + status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, - &this_walk_state->operands[0], NULL, 3); + &info, 3); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -382,7 +386,7 @@ acpi_ds_call_control_method ( /* On error, we must delete the new walk state */ cleanup: - if (next_walk_state->method_desc) { + if (next_walk_state && (next_walk_state->method_desc)) { /* Decrement the thread count on the method parse tree */ next_walk_state->method_desc->method.thread_count--; --- linux-2.6.8-rc1/drivers/acpi/dispatcher/dsmthdat.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dsmthdat.c 2004-07-13 17:09:17.000000000 -0700 @@ -656,11 +656,13 @@ acpi_ds_store_object_to_local ( new_obj_desc, current_obj_desc)); /* - * Store this object to the Node - * (perform the indirect store) + * Store this object to the Node (perform the indirect store) + * NOTE: No implicit conversion is performed, as per the ACPI + * specification rules on storing to Locals/Args. */ status = acpi_ex_store_object_to_node (new_obj_desc, - current_obj_desc->reference.object, walk_state); + current_obj_desc->reference.object, walk_state, + ACPI_NO_IMPLICIT_CONVERSION); /* Remove local reference if we copied the object above */ --- linux-2.6.8-rc1/drivers/acpi/dispatcher/dsopcode.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dsopcode.c 2004-07-13 17:09:17.000000000 -0700 @@ -79,7 +79,6 @@ acpi_ds_execute_arguments ( acpi_status status; union acpi_parse_object *op; struct acpi_walk_state *walk_state; - union acpi_parse_object *arg; ACPI_FUNCTION_TRACE ("ds_execute_arguments"); @@ -105,7 +104,7 @@ acpi_ds_execute_arguments ( } status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 1); + aml_length, NULL, 1); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); @@ -126,9 +125,7 @@ acpi_ds_execute_arguments ( /* Get and init the Op created above */ - arg = op->common.value.arg; op->common.node = node; - arg->common.node = node; acpi_ps_delete_parse_tree (op); /* Evaluate the deferred arguments */ @@ -150,7 +147,7 @@ acpi_ds_execute_arguments ( /* Execute the opcode and arguments */ status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, - aml_length, NULL, NULL, 3); + aml_length, NULL, 3); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); --- linux-2.6.8-rc1/drivers/acpi/dispatcher/dswload.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dswload.c 2004-07-13 17:09:17.000000000 -0700 @@ -50,6 +50,9 @@ #include #include +#ifdef _ACPI_ASL_COMPILER +#include +#endif #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dswload") @@ -180,7 +183,17 @@ acpi_ds_load1_begin_op ( status = acpi_ns_lookup (walk_state->scope_info, path, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + acpi_dm_add_to_external_list (path); + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (path, status); + } +#else ACPI_REPORT_NSERROR (path, status); +#endif return (status); } @@ -529,7 +542,16 @@ acpi_ds_load2_begin_op ( status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (buffer_ptr, status); + } +#else ACPI_REPORT_NSERROR (buffer_ptr, status); +#endif return_ACPI_STATUS (status); } /* --- linux-2.6.8-rc1/drivers/acpi/dispatcher/dswstate.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/dispatcher/dswstate.c 2004-07-13 17:09:17.000000000 -0700 @@ -906,8 +906,7 @@ acpi_ds_init_aml_walk ( struct acpi_namespace_node *method_node, u8 *aml_start, u32 aml_length, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc, + struct acpi_parameter_info *info, u32 pass_number) { acpi_status status; @@ -926,8 +925,17 @@ acpi_ds_init_aml_walk ( /* The next_op of the next_walk will be the beginning of the method */ walk_state->next_op = NULL; - walk_state->params = params; - walk_state->caller_return_desc = return_obj_desc; + + if (info) { + if (info->parameter_type == ACPI_PARAM_GPE) { + walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info, + info->parameters); + } + else { + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; + } + } status = acpi_ps_init_scope (&walk_state->parser_state, op); if (ACPI_FAILURE (status)) { @@ -949,7 +957,7 @@ acpi_ds_init_aml_walk ( /* Init the method arguments */ - status = acpi_ds_method_data_init_args (params, ACPI_METHOD_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } --- linux-2.6.8-rc1/drivers/acpi/ec.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/acpi/ec.c 2004-07-13 17:09:17.000000000 -0700 @@ -381,7 +381,7 @@ end: acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } -static void +static u32 acpi_ec_gpe_handler ( void *data) { @@ -389,12 +389,17 @@ acpi_ec_gpe_handler ( struct acpi_ec *ec = (struct acpi_ec *) data; if (!ec) - return; + return ACPI_INTERRUPT_NOT_HANDLED; acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); + + if (status == AE_OK) + return ACPI_INTERRUPT_HANDLED; + else + return ACPI_INTERRUPT_NOT_HANDLED; } /* -------------------------------------------------------------------------- @@ -729,6 +734,8 @@ acpi_ec_start ( if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } + acpi_set_gpe_type (NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -814,6 +821,8 @@ acpi_ec_ecdt_probe (void) if (ACPI_FAILURE(status)) { goto error; } + acpi_set_gpe_type (NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe (NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, --- linux-2.6.8-rc1/drivers/acpi/events/evevent.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/events/evevent.c 2004-07-13 17:09:17.000000000 -0700 @@ -50,7 +50,7 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_initialize + * FUNCTION: acpi_ev_initialize_events * * PARAMETERS: None * @@ -61,13 +61,13 @@ ******************************************************************************/ acpi_status -acpi_ev_initialize ( +acpi_ev_initialize_events ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_initialize"); + ACPI_FUNCTION_TRACE ("ev_initialize_events"); /* Make sure we have ACPI tables */ @@ -104,7 +104,7 @@ acpi_ev_initialize ( /******************************************************************************* * - * FUNCTION: acpi_ev_handler_initialize + * FUNCTION: acpi_ev_install_xrupt_handlers * * PARAMETERS: None * @@ -115,13 +115,13 @@ acpi_ev_initialize ( ******************************************************************************/ acpi_status -acpi_ev_handler_initialize ( +acpi_ev_install_xrupt_handlers ( void) { acpi_status status; - ACPI_FUNCTION_TRACE ("ev_handler_initialize"); + ACPI_FUNCTION_TRACE ("ev_install_xrupt_handlers"); /* Install the SCI handler */ --- linux-2.6.8-rc1/drivers/acpi/events/evgpeblk.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/events/evgpeblk.c 2004-07-13 17:09:17.000000000 -0700 @@ -53,7 +53,7 @@ * * FUNCTION: acpi_ev_valid_gpe_event * - * PARAMETERS: gpe_event_info - Info for this GPE + * PARAMETERS: gpe_event_info - Info for this GPE * * RETURN: TRUE if the gpe_event is valid * @@ -154,6 +154,53 @@ unlock_and_exit: } +/****************************************************************************** + * + * FUNCTION: acpi_ev_delete_gpe_handlers + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Delete all Handler objects found in the GPE data structs. + * Used only prior to termination. + * + ******************************************************************************/ + +acpi_status +acpi_ev_delete_gpe_handlers ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + struct acpi_gpe_event_info *gpe_event_info; + acpi_native_uint i; + acpi_native_uint j; + + + ACPI_FUNCTION_TRACE ("ev_delete_gpe_handlers"); + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + /* Now look at the individual GPEs in this byte register */ + + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { + gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; + + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { + ACPI_MEM_FREE (gpe_event_info->dispatch.handler); + gpe_event_info->dispatch.handler = NULL; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; + } + } + } + + return_ACPI_STATUS (AE_OK); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_save_method_info @@ -188,6 +235,7 @@ acpi_ev_save_method_info ( u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; + acpi_status status; ACPI_FUNCTION_TRACE ("ev_save_method_info"); @@ -206,16 +254,16 @@ acpi_ev_save_method_info ( * 2) Edge/Level determination is based on the 2nd character * of the method name * - * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a - * _PRW object is found that points to this GPE. + * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE + * if a _PRW object is found that points to this GPE. */ switch (name[1]) { case 'L': - type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_LEVEL_TRIGGERED; break; case 'E': - type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; + type = ACPI_GPE_EDGE_TRIGGERED; break; default: @@ -253,27 +301,35 @@ acpi_ev_save_method_info ( /* * Now we can add this information to the gpe_event_info block - * for use during dispatch of this GPE. + * for use during dispatch of this GPE. Default type is RUNTIME, although + * this may change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags = type; - gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; + gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD | + ACPI_GPE_TYPE_RUNTIME); + + gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *) obj_handle; + + /* Update enable mask, but don't enable the HW GPE as of yet */ + + status = acpi_ev_enable_gpe (gpe_event_info, FALSE); ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_ev_get_gpe_type + * FUNCTION: acpi_ev_match_prw_and_gpe * * PARAMETERS: Callback from walk_namespace * - * RETURN: Status + * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is + * not aborted on a single _PRW failure. * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * Device. Run the _PRW method. If present, extract the GPE @@ -282,7 +338,7 @@ acpi_ev_save_method_info ( ******************************************************************************/ static acpi_status -acpi_ev_get_gpe_type ( +acpi_ev_match_prw_and_gpe ( acpi_handle obj_handle, u32 level, void *info, @@ -299,19 +355,18 @@ acpi_ev_get_gpe_type ( acpi_status status; - ACPI_FUNCTION_TRACE ("ev_get_gpe_type"); + ACPI_FUNCTION_TRACE ("ev_match_prw_and_gpe"); /* Check for a _PRW method under this device */ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW, ACPI_BTYPE_PACKAGE, &pkg_desc); - if (status == AE_NOT_FOUND) { + if (ACPI_FAILURE (status)) { + /* Ignore all errors from _PRW, we don't want to abort the subsystem */ + return_ACPI_STATUS (AE_OK); } - else if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } /* The returned _PRW package must have at least two elements */ @@ -370,16 +425,21 @@ acpi_ev_get_gpe_type ( if ((gpe_device == target_gpe_device) && (gpe_number >= gpe_block->block_base_number) && (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - /* Mark GPE for WAKE but DISABLED (even for wake) */ - gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE; + + /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ + + gpe_event_info->flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); + status = acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); } cleanup: acpi_ut_remove_reference (pkg_desc); - - return_ACPI_STATUS (status); + return_ACPI_STATUS (AE_OK); } @@ -742,7 +802,7 @@ acpi_ev_create_gpe_info_blocks ( /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - this_event->bit_mask = acpi_gbl_decode_to8bit[j]; + this_event->register_bit = acpi_gbl_decode_to8bit[j]; this_event->register_info = this_register; this_event++; } @@ -817,6 +877,7 @@ acpi_ev_create_gpe_block ( acpi_status status; struct acpi_gpe_walk_info gpe_info; + ACPI_FUNCTION_TRACE ("ev_create_gpe_block"); @@ -835,6 +896,7 @@ acpi_ev_create_gpe_block ( gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; + gpe_block->node = gpe_device; ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address)); @@ -854,18 +916,6 @@ acpi_ev_create_gpe_block ( return_ACPI_STATUS (status); } - /* Dump info about this GPE block */ - - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, - "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", - gpe_block->block_base_number, - (u32) (gpe_block->block_base_number + - ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), - gpe_device->name.ascii, - gpe_block->register_count, - ACPI_FORMAT_UINT64 (gpe_block->block_address.address), - interrupt_level)); - /* Find all GPE methods (_Lxx, _Exx) for this block */ status = acpi_ns_walk_namespace (ACPI_TYPE_METHOD, gpe_device, @@ -873,27 +923,28 @@ acpi_ev_create_gpe_block ( gpe_block, NULL); /* - * Runtime option: Should Wake GPEs be enabled at runtime? The default is - * No,they should only be enabled just as the machine goes to sleep. + * Runtime option: Should Wake GPEs be enabled at runtime? The default + * is No,they should only be enabled just as the machine goes to sleep. */ if (acpi_gbl_leave_wake_gpes_disabled) { /* - * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each - * GPE that has one or more _PRWs that reference it is by definition a - * WAKE GPE and will not be enabled while the machine is running.) + * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. + * (Each GPE that has one or more _PRWs that reference it is by + * definition a WAKE GPE and will not be enabled while the machine + * is running.) */ gpe_info.gpe_block = gpe_block; gpe_info.gpe_device = gpe_device; status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_match_prw_and_gpe, &gpe_info, NULL); } /* - * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have - * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via - * the acpi_enable_gpe() external interface. + * Enable all GPEs in this block that are 1) "runtime" or "run/wake" GPEs, + * and 2) have a corresponding _Lxx or _Exx method. All other GPEs must + * be enabled via the acpi_enable_gpe() external interface. */ wake_gpe_count = 0; gpe_enabled_count = 0; @@ -903,23 +954,35 @@ acpi_ev_create_gpe_block ( /* Get the info block for this particular GPE */ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->method_node) && - ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) { - /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */ - - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + + if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) && + (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) { gpe_enabled_count++; } - if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) { + if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) { wake_gpe_count++; } } } + /* Dump info about this GPE block */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "GPE %02X to %02X [%4.4s] %u regs at %8.8X%8.8X on int 0x%X\n", + (u32) gpe_block->block_base_number, + (u32) (gpe_block->block_base_number + + ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), + gpe_device->name.ascii, + gpe_block->register_count, + ACPI_FORMAT_UINT64 (gpe_block->block_address.address), + interrupt_level)); + + + /* Enable all valid GPEs found above */ + + status = acpi_hw_enable_runtime_gpe_block (NULL, gpe_block); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Found %u Wake, Enabled %u Runtime GPEs in this block\n", wake_gpe_count, gpe_enabled_count)); @@ -1056,7 +1119,8 @@ acpi_ev_gpe_initialize ( if ((register_count0 + register_count1) == 0) { /* GPEs are not required by ACPI, this is OK */ - ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "There are no GPE blocks defined in the FADT\n")); status = AE_OK; goto cleanup; } --- linux-2.6.8-rc1/drivers/acpi/events/evgpe.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/events/evgpe.c 2004-07-13 17:09:17.000000000 -0700 @@ -51,6 +51,249 @@ /******************************************************************************* * + * FUNCTION: acpi_ev_set_gpe_type + * + * PARAMETERS: gpe_event_info - GPE to set + * Type - New type + * + * RETURN: Status + * + * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run) + * + ******************************************************************************/ + +acpi_status +acpi_ev_set_gpe_type ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_set_gpe_type"); + + + /* Validate type and update register enable masks */ + + switch (type) { + case ACPI_GPE_TYPE_WAKE: + case ACPI_GPE_TYPE_RUNTIME: + case ACPI_GPE_TYPE_WAKE_RUN: + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Disable the GPE if currently enabled */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Type was validated above */ + + gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; /* Clear type bits */ + gpe_event_info->flags |= type; /* Insert type */ + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_update_gpe_enable_masks + * + * PARAMETERS: gpe_event_info - GPE to update + * + * RETURN: Status + * + * DESCRIPTION: Updates GPE register enable masks based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_update_gpe_enable_masks ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type) +{ + struct acpi_gpe_register_info *gpe_register_info; + u8 register_bit; + + + ACPI_FUNCTION_TRACE ("ev_update_gpe_enable_masks"); + + + gpe_register_info = gpe_event_info->register_info; + if (!gpe_register_info) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + register_bit = gpe_event_info->register_bit; + + /* 1) Disable case. Simply clear all enable bits */ + + if (type == ACPI_GPE_DISABLE) { + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + return_ACPI_STATUS (AE_OK); + } + + /* 2) Enable case. Set/Clear the appropriate enable bits */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_RUNTIME: + ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit); + ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_enable_gpe + * + * PARAMETERS: gpe_event_info - GPE to enable + * + * RETURN: Status + * + * DESCRIPTION: Enable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_enable_gpe ( + struct acpi_gpe_event_info *gpe_event_info, + u8 write_to_hardware) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_enable_gpe"); + + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_ENABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-enabled or HW enable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + + if (write_to_hardware) { + /* Clear the GPE (of stale events), then enable it */ + + status = acpi_hw_clear_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Enable the requested runtime GPE */ + + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + } + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_disable_gpe + * + * PARAMETERS: gpe_event_info - GPE to disable + * + * RETURN: Status + * + * DESCRIPTION: Disable a GPE based on the GPE type + * + ******************************************************************************/ + +acpi_status +acpi_ev_disable_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_disable_gpe"); + + + if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { + return_ACPI_STATUS (AE_OK); + } + + /* Make sure HW enable masks are updated */ + + status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Mark wake-disabled or HW disable, or both */ + + switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { + case ACPI_GPE_TYPE_WAKE: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + break; + + case ACPI_GPE_TYPE_WAKE_RUN: + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); + + /*lint -fallthrough */ + + case ACPI_GPE_TYPE_RUNTIME: + + /* Disable the requested runtime GPE */ + + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); + status = acpi_hw_write_gpe_enable_reg (gpe_event_info); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ev_get_gpe_event_info * * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 @@ -139,11 +382,12 @@ acpi_ev_gpe_detect ( u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; u8 enabled_status_byte; struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; + u32 status_reg; + u32 enable_reg; acpi_status status; struct acpi_gpe_block_info *gpe_block; - u32 i; - u32 j; + acpi_native_uint i; + acpi_native_uint j; ACPI_FUNCTION_NAME ("ev_gpe_detect"); @@ -171,33 +415,32 @@ acpi_ev_gpe_detect ( /* Read the Status Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &status_reg, &gpe_register_info->status_address); - gpe_register_info->status = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Read the Enable Register */ - status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &enable_reg, &gpe_register_info->enable_address); - gpe_register_info->enable = (u8) in_value; if (ACPI_FAILURE (status)) { goto unlock_and_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", - ACPI_FORMAT_UINT64 (gpe_register_info->status_address.address), - gpe_register_info->status, - ACPI_FORMAT_UINT64 (gpe_register_info->enable_address.address), - gpe_register_info->enable)); + ACPI_FORMAT_UINT64 ( + gpe_register_info->status_address.address), + status_reg, + ACPI_FORMAT_UINT64 ( + gpe_register_info->enable_address.address), + enable_reg)); /* First check if there is anything active at all in this register */ - enabled_status_byte = (u8) (gpe_register_info->status & - gpe_register_info->enable); + enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { /* No active GPEs in this register, move on */ @@ -216,7 +459,7 @@ acpi_ev_gpe_detect ( */ int_status |= acpi_ev_gpe_dispatch ( &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], - j + gpe_register_info->base_gpe_number); + (u32) j + gpe_register_info->base_gpe_number); } } } @@ -255,6 +498,7 @@ acpi_ev_asynch_execute_gpe_method ( u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method"); @@ -272,6 +516,10 @@ acpi_ev_asynch_execute_gpe_method ( return_VOID; } + /* Set the GPE flags for return to enabled state */ + + (void) acpi_ev_enable_gpe (gpe_event_info, FALSE); + /* * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. @@ -283,23 +531,33 @@ acpi_ev_asynch_execute_gpe_method ( return_VOID; } - if (local_gpe_event_info.method_node) { + /* + * Must check for control method type dispatch one more + * time to avoid race with ev_gpe_install_handler + */ + if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* - * Invoke the GPE Method (_Lxx, _Exx): - * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) + * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx + * control method that corresponds to this GPE */ - status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL); + info.node = local_gpe_event_info.dispatch.method_node; + info.parameters = ACPI_CAST_PTR (union acpi_operand_object *, gpe_event_info); + info.parameter_type = ACPI_PARAM_GPE; + + status = acpi_ns_evaluate_by_handle (&info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), - acpi_ut_get_node_name (local_gpe_event_info.method_node), gpe_number)); + acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node), + gpe_number)); } } if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after handling - * the event. + * GPE is level-triggered, we clear the GPE status bit after + * handling the event. */ status = acpi_hw_clear_gpe (&local_gpe_event_info); if (ACPI_FAILURE (status)) { @@ -309,7 +567,7 @@ acpi_ev_asynch_execute_gpe_method ( /* Enable this GPE */ - (void) acpi_hw_enable_gpe (&local_gpe_event_info); + (void) acpi_hw_write_gpe_enable_reg (&local_gpe_event_info); return_VOID; } @@ -354,6 +612,15 @@ acpi_ev_gpe_dispatch ( } } + /* Save current system state */ + + if (acpi_gbl_system_awake_and_running) { + ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + else { + ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + } + /* * Dispatch the GPE to either an installed handler, or the control * method associated with this GPE (_Lxx or _Exx). @@ -361,10 +628,15 @@ acpi_ev_gpe_dispatch ( * If there is neither a handler nor a method, we disable the level to * prevent further events from coming in here. */ - if (gpe_event_info->handler) { - /* Invoke the installed handler (at interrupt level) */ + switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { + case ACPI_GPE_DISPATCH_HANDLER: - gpe_event_info->handler (gpe_event_info->context); + /* + * Invoke the installed handler (at interrupt level) + * Ignore return status for now. TBD: leave GPE disabled on error? + */ + (void) gpe_event_info->dispatch.handler->address ( + gpe_event_info->dispatch.handler->context); /* It is now safe to clear level-triggered events. */ @@ -377,13 +649,15 @@ acpi_ev_gpe_dispatch ( return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - } - else if (gpe_event_info->method_node) { + break; + + case ACPI_GPE_DISPATCH_METHOD: + /* * Disable GPE, so it doesn't keep firing before the method has a * chance to run. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", @@ -402,8 +676,10 @@ acpi_ev_gpe_dispatch ( "acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%2X], event is disabled\n", gpe_number)); } - } - else { + break; + + default: + /* No handler or method to run! */ ACPI_REPORT_ERROR (( @@ -414,15 +690,68 @@ acpi_ev_gpe_dispatch ( * Disable the GPE. The GPE will remain disabled until the ACPI * Core Subsystem is restarted, or a handler is installed. */ - status = acpi_hw_disable_gpe (gpe_event_info); + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } + break; } return_VALUE (ACPI_INTERRUPT_HANDLED); } + +#ifdef ACPI_GPE_NOTIFY_CHECK + +/******************************************************************************* + * NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED + * + * FUNCTION: acpi_ev_check_for_wake_only_gpe + * + * PARAMETERS: gpe_event_info - info for this GPE + * + * RETURN: Status + * + * DESCRIPTION: Determine if a a GPE is "wake-only". + * + * Called from Notify() code in interpreter when a "device_wake" + * Notify comes in. + * + ******************************************************************************/ + +acpi_status +acpi_ev_check_for_wake_only_gpe ( + struct acpi_gpe_event_info *gpe_event_info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_check_for_wake_only_gpe"); + + + if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ + ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) /* System state at GPE time */ { + /* This must be a wake-only GPE, disable it */ + + status = acpi_ev_disable_gpe (gpe_event_info); + + /* Set GPE to wake-only. Do not change wake disabled/enabled status */ + + acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE); + + ACPI_REPORT_INFO (("GPE %p was updated from wake/run to wake-only\n", + gpe_event_info)); + + /* This was a wake-only GPE */ + + return_ACPI_STATUS (AE_WAKE_ONLY_GPE); + } + + return_ACPI_STATUS (AE_OK); +} +#endif + + --- linux-2.6.8-rc1/drivers/acpi/events/evmisc.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/acpi/events/evmisc.c 2004-07-13 17:09:17.000000000 -0700 @@ -139,8 +139,7 @@ acpi_ev_queue_notify_request ( acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "notify value: 0x%2.2x **Device Specific**\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", notify_value)); } @@ -197,8 +196,8 @@ acpi_ev_queue_notify_request ( /* There is no per-device notify handler for this device */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "No notify handler for [%4.4s] node %p\n", - acpi_ut_get_node_name (node), node)); + "No notify handler for Notify(%4.4s, %X) node %p\n", + acpi_ut_get_node_name (node), notify_value, node)); } return (status); @@ -558,6 +557,10 @@ acpi_ev_terminate (void) } } + /* Deallocate all handler objects installed within GPE info structs */ + + status = acpi_ev_walk_gpe_list (acpi_ev_delete_gpe_handlers); + /* Return to original mode if necessary */ if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { --- linux-2.6.8-rc1/drivers/acpi/events/evregion.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/events/evregion.c 2004-07-13 17:09:17.000000000 -0700 @@ -61,7 +61,7 @@ static u8 acpi_gbl_def /******************************************************************************* * - * FUNCTION: acpi_ev_init_address_spaces + * FUNCTION: acpi_ev_install_region_handlers * * PARAMETERS: None * @@ -72,15 +72,20 @@ static u8 acpi_gbl_def ******************************************************************************/ acpi_status -acpi_ev_init_address_spaces ( +acpi_ev_install_region_handlers ( void) { acpi_status status; acpi_native_uint i; - ACPI_FUNCTION_TRACE ("ev_init_address_spaces"); + ACPI_FUNCTION_TRACE ("ev_install_region_handlers"); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* * All address spaces (PCI Config, EC, SMBus) are scope dependent * and registration must occur for a specific device. @@ -99,9 +104,8 @@ acpi_ev_init_address_spaces ( * has already been installed (via acpi_install_address_space_handler). * Similar for AE_SAME_HANDLER. */ - for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { - status = acpi_install_address_space_handler ((acpi_handle) acpi_gbl_root_node, + status = acpi_ev_install_space_handler (acpi_gbl_root_node, acpi_gbl_default_address_spaces[i], ACPI_DEFAULT_HANDLER, NULL, NULL); switch (status) { @@ -111,15 +115,63 @@ acpi_ev_init_address_spaces ( /* These exceptions are all OK */ + status = AE_OK; break; default: - return_ACPI_STATUS (status); + goto unlock_and_exit; } } - return_ACPI_STATUS (AE_OK); +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_initialize_op_regions + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG methods for all Operation Regions that have + * an installed default region handler. + * + ******************************************************************************/ + +acpi_status +acpi_ev_initialize_op_regions ( + void) +{ + acpi_status status; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ev_initialize_op_regions"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Run the _REG methods for op_regions in each default address space + */ + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* TBD: Make sure handler is the DEFAULT handler, otherwise + * _REG will have already been run. + */ + status = acpi_ev_execute_reg_methods (acpi_gbl_root_node, + acpi_gbl_default_address_spaces[i]); + } + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); } @@ -138,11 +190,12 @@ acpi_ev_init_address_spaces ( acpi_status acpi_ev_execute_reg_method ( - union acpi_operand_object *region_obj, + union acpi_operand_object *region_obj, u32 function) { - union acpi_operand_object *params[3]; - union acpi_operand_object *region_obj2; + struct acpi_parameter_info info; + union acpi_operand_object *params[3]; + union acpi_operand_object *region_obj2; acpi_status status; @@ -159,10 +212,11 @@ acpi_ev_execute_reg_method ( } /* - * _REG method has two arguments - * Arg0: Integer: Operation region space ID + * The _REG method has two arguments: + * + * Arg0, Integer: Operation region space ID * Same value as region_obj->Region.space_id - * Arg1: Integer: connection status + * Arg1, Integer: connection status * 1 for connecting the handler, * 0 for disconnecting the handler * Passed as a parameter @@ -184,10 +238,15 @@ acpi_ev_execute_reg_method ( params[1]->integer.value = function; params[2] = NULL; + info.node = region_obj2->extra.method_REG; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* Execute the method, no return value */ - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, region_obj2->extra.method_REG, NULL)); - status = acpi_ns_evaluate_by_handle (region_obj2->extra.method_REG, params, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname ( + ACPI_TYPE_METHOD, info.node, NULL)); + status = acpi_ns_evaluate_by_handle (&info); acpi_ut_remove_reference (params[1]); @@ -326,7 +385,7 @@ acpi_ev_address_space_dispatch ( ACPI_FORMAT_UINT64 (address), acpi_ut_get_region_name (region_obj->region.space_id))); - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't @@ -347,7 +406,7 @@ acpi_ev_address_space_dispatch ( acpi_format_exception (status))); } - if (!(handler_desc->address_space.flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { + if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter @@ -676,6 +735,273 @@ acpi_ev_install_handler ( return (status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ev_install_space_handler + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * Handler - Address of the handler + * Setup - Address of the setup function + * Context - Value passed to the handler on each access + * + * RETURN: Status + * + * DESCRIPTION: Install a handler for all op_regions of a given space_id. + * Assumes namespace is locked + * + ******************************************************************************/ + +acpi_status +acpi_ev_install_space_handler ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, + void *context) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *handler_obj; + acpi_status status; + acpi_object_type type; + u16 flags = 0; + + + ACPI_FUNCTION_TRACE ("ev_install_space_handler"); + + + /* + * This registration is valid for only the types below + * and the root. This is where the default handlers + * get placed. + */ + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + if (handler == ACPI_DEFAULT_HANDLER) { + flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; + + switch (space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + handler = acpi_ex_system_memory_space_handler; + setup = acpi_ev_system_memory_region_setup; + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + handler = acpi_ex_system_io_space_handler; + setup = acpi_ev_io_space_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_CONFIG: + handler = acpi_ex_pci_config_space_handler; + setup = acpi_ev_pci_config_region_setup; + break; + + case ACPI_ADR_SPACE_CMOS: + handler = acpi_ex_cmos_space_handler; + setup = acpi_ev_cmos_region_setup; + break; + + case ACPI_ADR_SPACE_PCI_BAR_TARGET: + handler = acpi_ex_pci_bar_space_handler; + setup = acpi_ev_pci_bar_region_setup; + break; + + case ACPI_ADR_SPACE_DATA_TABLE: + handler = acpi_ex_data_table_space_handler; + setup = NULL; + break; + + default: + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* If the caller hasn't specified a setup routine, use the default */ + + if (!setup) { + setup = acpi_ev_default_region_setup; + } + + /* Check for an existing internal object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + /* + * The attached device object already exists. + * Make sure the handler is not already installed. + */ + handler_obj = obj_desc->device.handler; + + /* Walk the handler list for this device */ + + while (handler_obj) { + /* Same space_id indicates a handler already installed */ + + if (handler_obj->address_space.space_id == space_id) { + if (handler_obj->address_space.handler == handler) { + /* + * It is (relatively) OK to attempt to install the SAME + * handler twice. This can easily happen with PCI_Config space. + */ + status = AE_SAME_HANDLER; + goto unlock_and_exit; + } + else { + /* A handler is already installed */ + + status = AE_ALREADY_EXISTS; + } + goto unlock_and_exit; + } + + /* Walk the linked list of handlers */ + + handler_obj = handler_obj->address_space.next; + } + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Creating object on Device %p while installing handler\n", node)); + + /* obj_desc does not exist, create one */ + + if (node->type == ACPI_TYPE_ANY) { + type = ACPI_TYPE_DEVICE; + } + else { + type = node->type; + } + + obj_desc = acpi_ut_create_internal_object (type); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init new descriptor */ + + obj_desc->common.type = (u8) type; + + /* Attach the new object to the Node */ + + status = acpi_ns_attach_object (node, obj_desc, type); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", + acpi_ut_get_region_name (space_id), space_id, + acpi_ut_get_node_name (node), node, obj_desc)); + + /* + * Install the handler + * + * At this point there is no existing handler. + * Just allocate the object for the handler and link it + * into the list. + */ + handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); + if (!handler_obj) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Init handler obj */ + + handler_obj->address_space.space_id = (u8) space_id; + handler_obj->address_space.hflags = flags; + handler_obj->address_space.region_list = NULL; + handler_obj->address_space.node = node; + handler_obj->address_space.handler = handler; + handler_obj->address_space.context = context; + handler_obj->address_space.setup = setup; + + /* Install at head of Device.address_space list */ + + handler_obj->address_space.next = obj_desc->device.handler; + + /* + * The Device object is the first reference on the handler_obj. + * Each region that uses the handler adds a reference. + */ + obj_desc->device.handler = handler_obj; + + /* + * Walk the namespace finding all of the regions this + * handler will manage. + * + * Start at the device and search the branch toward + * the leaf nodes until either the leaf is encountered or + * a device is detected that has an address handler of the + * same type. + * + * In either case, back up and search down the remainder + * of the branch + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, + handler_obj, NULL); + +unlock_and_exit: + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_execute_reg_methods + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * + * RETURN: Status + * + * DESCRIPTION: Run _REG methods for the Space ID; + * Note: assumes namespace is locked, or system init time. + * + ******************************************************************************/ + +acpi_status +acpi_ev_execute_reg_methods ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_execute_reg_methods"); + + + /* + * Run all _REG methods for all Operation Regions for this + * space ID. This is a separate walk in order to handle any + * interdependencies between regions and _REG methods. (i.e. handlers + * must be installed for all regions of this Space ID before we + * can run any _REG methods) + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, + &space_id, NULL); + + return_ACPI_STATUS (status); +} + + /******************************************************************************* * * FUNCTION: acpi_ev_reg_run @@ -693,19 +1019,13 @@ acpi_ev_reg_run ( void *context, void **return_value) { - union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; + acpi_adr_space_type space_id; acpi_status status; - handler_obj = (union acpi_operand_object *) context; - - /* Parameter validation */ - - if (!handler_obj) { - return (AE_OK); - } + space_id = *ACPI_CAST_PTR (acpi_adr_space_type, context); /* Convert and validate the device handle */ @@ -732,10 +1052,9 @@ acpi_ev_reg_run ( return (AE_OK); } - /* Object is a Region */ - if (obj_desc->region.space_id != handler_obj->address_space.space_id) { + if (obj_desc->region.space_id != space_id) { /* * This region is for a different address space * -- just ignore it --- linux-2.6.8-rc1/drivers/acpi/events/evxface.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/acpi/events/evxface.c 2004-07-13 17:09:17.000000000 -0700 @@ -188,6 +188,7 @@ acpi_remove_fixed_event_handler ( * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * Context - Value passed to the handler on each GPE * @@ -243,20 +244,21 @@ acpi_install_notify_handler ( if (device == ACPI_ROOT_OBJECT) { /* Make sure the handler is not already installed */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && acpi_gbl_device_notify.handler)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = node; acpi_gbl_system_notify.handler = handler; acpi_gbl_system_notify.context = context; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = node; acpi_gbl_device_notify.handler = handler; acpi_gbl_device_notify.context = context; @@ -284,9 +286,9 @@ acpi_install_notify_handler ( if (obj_desc) { /* Object exists - make sure there's no handler */ - if (((handler_type == ACPI_SYSTEM_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && obj_desc->common_notify.system_notify) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + ((handler_type & ACPI_DEVICE_NOTIFY) && obj_desc->common_notify.device_notify)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; @@ -308,7 +310,6 @@ acpi_install_notify_handler ( /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); - if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -326,12 +327,19 @@ acpi_install_notify_handler ( notify_obj->notify.handler = handler; notify_obj->notify.context = context; - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; } - else /* ACPI_DEVICE_NOTIFY */ { + + if (handler_type & ACPI_DEVICE_NOTIFY) { obj_desc->common_notify.device_notify = notify_obj; } + + if (handler_type == ACPI_ALL_NOTIFY) { + /* Extra ref if installed in both */ + + acpi_ut_add_reference (notify_obj); + } } @@ -349,6 +357,7 @@ unlock_and_exit: * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * RETURN: Status * @@ -398,9 +407,9 @@ acpi_remove_notify_handler ( if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); - if (((handler_type == ACPI_SYSTEM_NOTIFY) && - !acpi_gbl_system_notify.handler) || - ((handler_type == ACPI_DEVICE_NOTIFY) && + if (((handler_type & ACPI_SYSTEM_NOTIFY) && + !acpi_gbl_system_notify.handler) || + ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -415,12 +424,13 @@ acpi_remove_notify_handler ( return_ACPI_STATUS (status); } - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } - else { + + if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; @@ -448,38 +458,47 @@ acpi_remove_notify_handler ( /* Object exists - make sure there's an existing handler */ - if (handler_type == ACPI_SYSTEM_NOTIFY) { + if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; - } - else { - notify_obj = obj_desc->common_notify.device_notify; - } + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - /* Make sure all deferred tasks are completed */ + /* Remove the handler */ + obj_desc->common_notify.system_notify = NULL; + acpi_ut_remove_reference (notify_obj); + } - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + if (handler_type & ACPI_DEVICE_NOTIFY) { + notify_obj = obj_desc->common_notify.device_notify; + if ((!notify_obj) || + (notify_obj->notify.handler != handler)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ - /* Remove the handler */ + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - if (handler_type == ACPI_SYSTEM_NOTIFY) { - obj_desc->common_notify.system_notify = NULL; - } - else { + /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; + acpi_ut_remove_reference (notify_obj); } - - acpi_ut_remove_reference (notify_obj); } @@ -497,7 +516,7 @@ unlock_and_exit: * gpe_block - GPE block (NULL == FADT GPEs) * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. - * Handler - Address of the handler + * Address - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status @@ -511,11 +530,12 @@ acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler"); @@ -523,7 +543,7 @@ acpi_install_gpe_handler ( /* Parameter validation */ - if (!handler) { + if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -542,27 +562,41 @@ acpi_install_gpe_handler ( /* Make sure that there isn't a handler there already */ - if (gpe_event_info->handler) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } - /* Install the handler */ + /* Allocate and init handler object */ - acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = handler; - gpe_event_info->context = context; - gpe_event_info->flags = (u8) type; - acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info)); + if (!handler) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - /* Clear the GPE (of stale events), the enable it */ + handler->address = address; + handler->context = context; + handler->method_node = gpe_event_info->dispatch.method_node; - status = acpi_hw_clear_gpe (gpe_event_info); + /* Disable the GPE before installing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - status = acpi_hw_enable_gpe (gpe_event_info); + /* Install the handler */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + gpe_event_info->dispatch.handler = handler; + + /* Setup up dispatch flags to indicate handler (vs. method) */ + + gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */ + gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); + + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); unlock_and_exit: @@ -577,7 +611,7 @@ unlock_and_exit: * * PARAMETERS: gpe_number - The event to remove a handler * gpe_block - GPE block (NULL == FADT GPEs) - * Handler - Address of the handler + * Address - Address of the handler * * RETURN: Status * @@ -589,10 +623,11 @@ acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler) + acpi_event_handler address) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; + struct acpi_handler_info *handler; + acpi_status status; ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler"); @@ -600,7 +635,7 @@ acpi_remove_gpe_handler ( /* Parameter validation */ - if (!handler) { + if (!address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -617,21 +652,27 @@ acpi_remove_gpe_handler ( goto unlock_and_exit; } - /* Disable the GPE before removing the handler */ + /* Make sure that a handler is indeed installed */ - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) { + status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ - if (gpe_event_info->handler != handler) { - (void) acpi_hw_enable_gpe (gpe_event_info); + if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } + /* Disable the GPE before removing the handler */ + + status = acpi_ev_disable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); @@ -644,10 +685,21 @@ acpi_remove_gpe_handler ( /* Remove the handler */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); - gpe_event_info->handler = NULL; - gpe_event_info->context = NULL; + handler = gpe_event_info->dispatch.handler; + + /* Restore Method node (if any), set dispatch flags */ + + gpe_event_info->dispatch.method_node = handler->method_node; + gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */ + if (handler->method_node) { + gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD; + } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + /* Now we can free the handler object */ + + ACPI_MEM_FREE (handler); + unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); --- linux-2.6.8-rc1/drivers/acpi/events/evxfevnt.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/events/evxfevnt.c 2004-07-13 17:09:17.000000000 -0700 @@ -204,12 +204,11 @@ acpi_enable_event ( /******************************************************************************* * - * FUNCTION: acpi_enable_gpe + * FUNCTION: acpi_set_gpe_type * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? - * Called from ISR or not + * Type - New GPE type * * RETURN: Status * @@ -218,26 +217,17 @@ acpi_enable_event ( ******************************************************************************/ acpi_status -acpi_enable_gpe ( +acpi_set_gpe_type ( acpi_handle gpe_device, u32 gpe_number, - u32 flags) + u8 type) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - + ACPI_FUNCTION_TRACE ("acpi_set_gpe_type"); - /* Use semaphore lock if not executing at interrupt level */ - - if (flags & ACPI_NOT_ISR) { - status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - } /* Ensure that we have a valid GPE number */ @@ -247,91 +237,72 @@ acpi_enable_gpe ( goto unlock_and_exit; } - /* Check for Wake vs Runtime GPE */ - - if (flags & ACPI_EVENT_WAKE_ENABLE) { - /* Ensure the requested wake GPE is disabled */ - - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - - /* Defer Enable of Wake GPE until sleep time */ - - acpi_hw_enable_gpe_for_wakeup (gpe_event_info); + if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) { + return_ACPI_STATUS (AE_OK); } - else { - /* Enable the requested runtime GPE */ - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } + /* Set the new type (will disable GPE if currently enabled) */ + status = acpi_ev_set_gpe_type (gpe_event_info, type); unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); - } return_ACPI_STATUS (status); } /******************************************************************************* * - * FUNCTION: acpi_disable_event + * FUNCTION: acpi_enable_gpe * - * PARAMETERS: Event - The fixed eventto be enabled - * Flags - Reserved + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Just enable, or also wake enable? + * Called from ISR or not * * RETURN: Status * - * DESCRIPTION: Disable an ACPI event (fixed) + * DESCRIPTION: Enable an ACPI event (general purpose) * ******************************************************************************/ acpi_status -acpi_disable_event ( - u32 event, +acpi_enable_gpe ( + acpi_handle gpe_device, + u32 gpe_number, u32 flags) { acpi_status status = AE_OK; - u32 value; + struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE ("acpi_disable_event"); + ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - /* Decode the Fixed Event */ + /* Use semaphore lock if not executing at interrupt level */ - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } - /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, - 0, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Ensure that we have a valid GPE number */ - status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, - &value, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; } - if (value != 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not disable %s events\n", acpi_ut_get_event_name (event))); - return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); - } + /* Perform the enable */ + status = acpi_ev_enable_gpe (gpe_event_info, TRUE); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -342,7 +313,7 @@ acpi_disable_event ( * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? + * Flags - Just disable, or also wake disable? * Called from ISR or not * * RETURN: Status @@ -381,21 +352,69 @@ acpi_disable_gpe ( goto unlock_and_exit; } + status = acpi_ev_disable_gpe (gpe_event_info); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_disable_event + * + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved + * + * RETURN: Status + * + * DESCRIPTION: Disable an ACPI event (fixed) + * + ******************************************************************************/ + +acpi_status +acpi_disable_event ( + u32 event, + u32 flags) +{ + acpi_status status = AE_OK; + u32 value; + + + ACPI_FUNCTION_TRACE ("acpi_disable_event"); + + + /* Decode the Fixed Event */ + + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + /* - * Only disable the requested GPE number for wake if specified. - * Otherwise, turn it totally off + * Disable the requested fixed event (by writing a zero to the + * enable register bit) */ - if (flags & ACPI_EVENT_WAKE_DISABLE) { - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - else { - status = acpi_hw_disable_gpe (gpe_event_info); + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } -unlock_and_exit: - if (flags & ACPI_NOT_ISR) { - (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + if (value != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable %s events\n", acpi_ut_get_event_name (event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); } + return_ACPI_STATUS (status); } --- linux-2.6.8-rc1/drivers/acpi/events/evxfregn.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/events/evxfregn.c 2004-07-13 17:09:17.000000000 -0700 @@ -46,7 +46,6 @@ #include #include #include -#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evxfregn") @@ -76,12 +75,8 @@ acpi_install_address_space_handler ( acpi_adr_space_setup setup, void *context) { - union acpi_operand_object *obj_desc; - union acpi_operand_object *handler_obj; struct acpi_namespace_node *node; acpi_status status; - acpi_object_type type; - u16 flags = 0; ACPI_FUNCTION_TRACE ("acpi_install_address_space_handler"); @@ -106,202 +101,16 @@ acpi_install_address_space_handler ( goto unlock_and_exit; } - /* - * This registration is valid for only the types below - * and the root. This is where the default handlers - * get placed. - */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR) && - (node->type != ACPI_TYPE_THERMAL) && - (node != acpi_gbl_root_node)) { - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - - if (handler == ACPI_DEFAULT_HANDLER) { - flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - handler = acpi_ex_system_memory_space_handler; - setup = acpi_ev_system_memory_region_setup; - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - handler = acpi_ex_system_io_space_handler; - setup = acpi_ev_io_space_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_CONFIG: - handler = acpi_ex_pci_config_space_handler; - setup = acpi_ev_pci_config_region_setup; - break; - - case ACPI_ADR_SPACE_CMOS: - handler = acpi_ex_cmos_space_handler; - setup = acpi_ev_cmos_region_setup; - break; - - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - handler = acpi_ex_pci_bar_space_handler; - setup = acpi_ev_pci_bar_region_setup; - break; - - case ACPI_ADR_SPACE_DATA_TABLE: - handler = acpi_ex_data_table_space_handler; - setup = NULL; - break; - - default: - status = AE_BAD_PARAMETER; - goto unlock_and_exit; - } - } + /* Install the handler for all Regions for this Space ID */ - /* If the caller hasn't specified a setup routine, use the default */ - - if (!setup) { - setup = acpi_ev_default_region_setup; - } - - /* Check for an existing internal object */ - - obj_desc = acpi_ns_get_attached_object (node); - if (obj_desc) { - /* - * The attached device object already exists. - * Make sure the handler is not already installed. - */ - handler_obj = obj_desc->device.handler; - - /* Walk the handler list for this device */ - - while (handler_obj) { - /* Same space_id indicates a handler already installed */ - - if(handler_obj->address_space.space_id == space_id) { - if (handler_obj->address_space.handler == handler) { - /* - * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with PCI_Config space. - */ - status = AE_SAME_HANDLER; - goto unlock_and_exit; - } - else { - /* A handler is already installed */ - - status = AE_ALREADY_EXISTS; - } - goto unlock_and_exit; - } - - /* Walk the linked list of handlers */ - - handler_obj = handler_obj->address_space.next; - } - } - else { - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Creating object on Device %p while installing handler\n", node)); - - /* obj_desc does not exist, create one */ - - if (node->type == ACPI_TYPE_ANY) { - type = ACPI_TYPE_DEVICE; - } - else { - type = node->type; - } - - obj_desc = acpi_ut_create_internal_object (type); - if (!obj_desc) { - status = AE_NO_MEMORY; - goto unlock_and_exit; - } - - /* Init new descriptor */ - - obj_desc->common.type = (u8) type; - - /* Attach the new object to the Node */ - - status = acpi_ns_attach_object (node, obj_desc, type); - - /* Remove local reference to the object */ - - acpi_ut_remove_reference (obj_desc); - - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", - acpi_ut_get_region_name (space_id), space_id, - acpi_ut_get_node_name (node), node, obj_desc)); - - /* - * Install the handler - * - * At this point there is no existing handler. - * Just allocate the object for the handler and link it - * into the list. - */ - handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); - if (!handler_obj) { - status = AE_NO_MEMORY; + status = acpi_ev_install_space_handler (node, space_id, handler, setup, context); + if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - /* Init handler obj */ + /* Run all _REG methods for this address space */ - handler_obj->address_space.space_id = (u8) space_id; - handler_obj->address_space.hflags = flags; - handler_obj->address_space.region_list = NULL; - handler_obj->address_space.node = node; - handler_obj->address_space.handler = handler; - handler_obj->address_space.context = context; - handler_obj->address_space.setup = setup; - - /* Install at head of Device.address_space list */ - - handler_obj->address_space.next = obj_desc->device.handler; - - /* - * The Device object is the first reference on the handler_obj. - * Each region that uses the handler adds a reference. - */ - obj_desc->device.handler = handler_obj; - - /* - * Walk the namespace finding all of the regions this - * handler will manage. - * - * Start at the device and search the branch toward - * the leaf nodes until either the leaf is encountered or - * a device is detected that has an address handler of the - * same type. - * - * In either case, back up and search down the remainder - * of the branch - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, - handler_obj, NULL); - - /* - * Now we can run the _REG methods for all Regions for this - * space ID. This is a separate walk in order to handle any - * interdependencies between regions and _REG methods. (i.e. handlers - * must be installed for all regions of this Space ID before we - * can run any _REG methods. - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX, - ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - handler_obj, NULL); + status = acpi_ev_execute_reg_methods (node, space_id); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); --- linux-2.6.8-rc1/drivers/acpi/executer/exconfig.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/executer/exconfig.c 2004-07-13 17:09:17.000000000 -0700 @@ -48,6 +48,7 @@ #include #include #include +#include #define _COMPONENT ACPI_EXECUTER @@ -285,7 +286,7 @@ acpi_ex_load_op ( union acpi_operand_object *ddb_handle; union acpi_operand_object *buffer_desc = NULL; struct acpi_table_header *table_ptr = NULL; - u8 *table_data_ptr; + acpi_physical_address address; struct acpi_table_header table_header; u32 i; @@ -300,18 +301,39 @@ acpi_ex_load_op ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n", obj_desc, acpi_ut_get_object_type_name (obj_desc))); - /* Get the table header */ + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_region_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Get the base physical address of the region */ + + address = obj_desc->region.address; + + /* Get the table length from the table header */ table_header.length = 0; - for (i = 0; i < sizeof (struct acpi_table_header); i++) { + for (i = 0; i < 8; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, + (acpi_physical_address) (i + address), 8, ((u8 *) &table_header) + i); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } + /* Sanity check the table length */ + + if (table_header.length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } + /* Allocate a buffer for the entire table */ table_ptr = ACPI_MEM_ALLOCATE (table_header.length); @@ -319,17 +341,12 @@ acpi_ex_load_op ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* Copy the header to the buffer */ - - ACPI_MEMCPY (table_ptr, &table_header, sizeof (struct acpi_table_header)); - table_data_ptr = ACPI_PTR_ADD (u8, table_ptr, sizeof (struct acpi_table_header)); - - /* Get the table from the op region */ + /* Get the entire table from the op region */ for (i = 0; i < table_header.length; i++) { status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, - (acpi_physical_address) i, 8, - ((u8 *) table_data_ptr + i)); + (acpi_physical_address) (i + address), 8, + ((u8 *) table_ptr + i)); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -355,6 +372,12 @@ acpi_ex_load_op ( } table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + + /* Sanity check the table length */ + + if (table_ptr->length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } break; --- linux-2.6.8-rc1/drivers/acpi/executer/exfldio.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/executer/exfldio.c 2004-07-13 17:09:17.000000000 -0700 @@ -277,7 +277,7 @@ acpi_ex_access_region ( rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_REPORT_ERROR (( "Region %s(%X) has no handler\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); @@ -766,14 +766,83 @@ acpi_ex_set_buffer_datum ( /******************************************************************************* * + * FUNCTION: acpi_ex_common_buffer_setup + * + * PARAMETERS: obj_desc - Field object + * buffer_length - Length of caller's buffer + * datum_count - Where the datum_count is returned + * + * RETURN: Status, datum_count + * + * DESCRIPTION: Common code to validate the incoming buffer size and compute + * the number of field "datums" that must be read or written. + * A "datum" is the smallest unit that can be read or written + * to the field, it is either 1,2,4, or 8 bytes. + * + ******************************************************************************/ + +acpi_status +acpi_ex_common_buffer_setup ( + union acpi_operand_object *obj_desc, + u32 buffer_length, + u32 *datum_count) +{ + u32 byte_field_length; + u32 actual_byte_field_length; + + + ACPI_FUNCTION_TRACE ("ex_common_buffer_setup"); + + + /* + * Incoming buffer must be at least as long as the field, we do not + * allow "partial" field reads/writes. We do not care if the buffer is + * larger than the field, this typically happens when an integer is + * read/written to a field that is actually smaller than an integer. + */ + byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); + if (byte_field_length > buffer_length) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field size %X (bytes) is too large for buffer (%X)\n", + byte_field_length, buffer_length)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + + /* + * Create "actual" field byte count (minimum number of bytes that + * must be read), then convert to datum count (minimum number + * of datum-sized units that must be read) + */ + actual_byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.start_field_bit_offset + + obj_desc->common_field.bit_length); + + + *datum_count = ACPI_ROUND_UP_TO (actual_byte_field_length, + obj_desc->common_field.access_byte_width); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "buffer_bytes %X, actual_bytes %X, Datums %X, byte_gran %X\n", + byte_field_length, actual_byte_field_length, + *datum_count, obj_desc->common_field.access_byte_width)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ex_extract_from_field * - * PARAMETERS: *obj_desc - Field to be read - * *Value - Where to store value + * PARAMETERS: obj_desc - Field to be read + * Buffer - Where to store the field data + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Retrieve the value of the given field + * DESCRIPTION: Retrieve the current value of the given field * ******************************************************************************/ @@ -789,7 +858,6 @@ acpi_ex_extract_from_field ( acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; - u32 byte_field_length; u32 datum_count; u32 i; @@ -797,39 +865,13 @@ acpi_ex_extract_from_field ( ACPI_FUNCTION_TRACE ("ex_extract_from_field"); - /* - * The field must fit within the caller's buffer - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); - if (byte_field_length > buffer_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Field size %X (bytes) too large for buffer (%X)\n", - byte_field_length, buffer_length)); - - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); - } - - /* Convert field byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); + /* Validate buffer, compute number of datums */ - /* - * If the field is not aligned on a datum boundary and does not - * fit within a single datum, we must read an extra datum. - * - * We could just split the aligned and non-aligned cases since the - * aligned case is so very simple, but this would require more code. - */ - if ((obj_desc->common_field.end_field_valid_bits != 0) && - (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { - datum_count++; + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "byte_len %X, datum_len %X, byte_gran %X\n", - byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); - /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer @@ -942,12 +984,13 @@ acpi_ex_extract_from_field ( * * FUNCTION: acpi_ex_insert_into_field * - * PARAMETERS: *obj_desc - Field to be set - * Buffer - Value to store + * PARAMETERS: obj_desc - Field to be written + * Buffer - Data to be written + * buffer_length - Length of Buffer * * RETURN: Status * - * DESCRIPTION: Store the value into the given field + * DESCRIPTION: Store the Buffer contents into the given field * ******************************************************************************/ @@ -964,42 +1007,19 @@ acpi_ex_insert_into_field ( acpi_integer merged_datum; acpi_integer previous_raw_datum; acpi_integer this_raw_datum; - u32 byte_field_length; u32 datum_count; ACPI_FUNCTION_TRACE ("ex_insert_into_field"); - /* - * Incoming buffer must be at least as long as the field, we do not - * allow "partial" field writes. We do not care if the buffer is - * larger than the field, this typically happens when an integer is - * written to a field that is actually smaller than an integer. - */ - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.bit_length); - if (buffer_length < byte_field_length) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Buffer length %X too small for field %X\n", - buffer_length, byte_field_length)); + /* Validate buffer, compute number of datums */ - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES ( - obj_desc->common_field.start_field_bit_offset + - obj_desc->common_field.bit_length); - - /* Convert byte count to datum count, round up if necessary */ - - datum_count = ACPI_ROUND_UP_TO (byte_field_length, - obj_desc->common_field.access_byte_width); - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Bytes %X, Datums %X, byte_gran %X\n", - byte_field_length, datum_count, obj_desc->common_field.access_byte_width)); - /* * Break the request into up to three parts (similar to an I/O request): * 1) non-aligned part at start --- linux-2.6.8-rc1/drivers/acpi/executer/exmisc.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/executer/exmisc.c 2004-07-13 17:09:17.000000000 -0700 @@ -389,6 +389,8 @@ acpi_ex_do_math_op ( acpi_integer operand1) { + ACPI_FUNCTION_ENTRY (); + switch (opcode) { case AML_ADD_OP: /* Add (Operand0, Operand1, Result) */ @@ -452,15 +454,17 @@ acpi_ex_do_math_op ( * FUNCTION: acpi_ex_do_logical_op * * PARAMETERS: Opcode - AML opcode - * Operand0 - Integer operand #0 - * Operand1 - Integer operand #1 + * obj_desc0 - operand #0 + * obj_desc1 - operand #1 * * RETURN: TRUE/FALSE result of the operation * * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the * functions here is to prevent a lot of pointer dereferencing * to obtain the operands and to simplify the generation of the - * logical value. + * logical value. Both operands must already be validated as + * 1) Both the same type, and + * 2) Either Integer, Buffer, or String type. * * Note: cleanest machine code seems to be produced by the code * below, rather than using statements of the form: @@ -471,54 +475,137 @@ acpi_ex_do_math_op ( u8 acpi_ex_do_logical_op ( u16 opcode, - acpi_integer operand0, - acpi_integer operand1) + union acpi_operand_object *obj_desc0, + union acpi_operand_object *obj_desc1) { + acpi_integer operand0; + acpi_integer operand1; + u8 *ptr0; + u8 *ptr1; + u32 length0; + u32 length1; + u32 i; - switch (opcode) { + ACPI_FUNCTION_ENTRY (); - case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 && operand1) { - return (TRUE); - } - break; + if (ACPI_GET_OBJECT_TYPE (obj_desc0) == ACPI_TYPE_INTEGER) { + /* Both operands are of type integer */ + operand0 = obj_desc0->integer.value; + operand1 = obj_desc1->integer.value; - case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + switch (opcode) { + case AML_LAND_OP: /* LAnd (Operand0, Operand1) */ - if (operand0 == operand1) { - return (TRUE); - } - break; + if (operand0 && operand1) { + return (TRUE); + } + break; + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ - case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + if (operand0 == operand1) { + return (TRUE); + } + break; - if (operand0 > operand1) { - return (TRUE); - } - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + if (operand0 > operand1) { + return (TRUE); + } + break; - case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ - if (operand0 < operand1) { - return (TRUE); - } - break; + if (operand0 < operand1) { + return (TRUE); + } + break; + case AML_LOR_OP: /* LOr (Operand0, Operand1) */ - case AML_LOR_OP: /* LOr (Operand0, Operand1) */ + if (operand0 || operand1) { + return (TRUE); + } + break; - if (operand0 || operand1) { - return (TRUE); + default: + break; } - break; + } + else { + /* + * Case for Buffer/String objects. + * NOTE: takes advantage of common Buffer/String object fields + */ + length0 = obj_desc0->buffer.length; + ptr0 = obj_desc0->buffer.pointer; + + length1 = obj_desc1->buffer.length; + ptr1 = obj_desc1->buffer.pointer; + + switch (opcode) { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + /* Length and all bytes must be equal */ + + if (length0 != length1) { + return (FALSE); + } + + for (i = 0; i < length0; i++) { + if (ptr0[i] != ptr1[i]) { + return (FALSE); + } + } + return (TRUE); - default: - break; + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + /* Check lengths first */ + + if (length0 > length1) { + return (TRUE); + } + else if (length0 < length1) { + return (FALSE); + } + + /* Lengths equal, now scan the data */ + + for (i = 0; i < length0; i++) { + if (ptr0[i] > ptr1[i]) { + return (TRUE); + } + } + return (FALSE); + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + /* Check lengths first */ + + if (length0 < length1) { + return (TRUE); + } + else if (length0 > length1) { + return (FALSE); + } + + /* Lengths equal, now scan the data */ + + for (i = 0; i < length0; i++) { + if (ptr0[i] < ptr1[i]) { + return (TRUE); + } + } + return (FALSE); + + default: + break; + } } return (FALSE); --- linux-2.6.8-rc1/drivers/acpi/executer/exmutex.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/executer/exmutex.c 2004-07-13 17:09:17.000000000 -0700 @@ -54,7 +54,7 @@ * * FUNCTION: acpi_ex_unlink_mutex * - * PARAMETERS: *obj_desc - The mutex to be unlinked + * PARAMETERS: obj_desc - The mutex to be unlinked * * RETURN: Status * @@ -73,6 +73,8 @@ acpi_ex_unlink_mutex ( return; } + /* Doubly linked list */ + if (obj_desc->mutex.next) { (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; } @@ -90,8 +92,8 @@ acpi_ex_unlink_mutex ( * * FUNCTION: acpi_ex_link_mutex * - * PARAMETERS: *obj_desc - The mutex to be linked - * *list_head - head of the "acquired_mutex" list + * PARAMETERS: obj_desc - The mutex to be linked + * list_head - head of the "acquired_mutex" list * * RETURN: Status * @@ -130,8 +132,8 @@ acpi_ex_link_mutex ( * * FUNCTION: acpi_ex_acquire_mutex * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -173,9 +175,8 @@ acpi_ex_acquire_mutex ( return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Support for multiple acquires by the owning thread - */ + /* Support for multiple acquires by the owning thread */ + if (obj_desc->mutex.owner_thread) { /* Special case for Global Lock, allow all threads */ @@ -199,10 +200,11 @@ acpi_ex_acquire_mutex ( return_ACPI_STATUS (status); } - /* Have the mutex, update mutex and walk info */ + /* Have the mutex: update mutex and walk info and save the sync_level */ - obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.owner_thread = walk_state->thread; obj_desc->mutex.acquisition_depth = 1; + obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; @@ -218,7 +220,7 @@ acpi_ex_acquire_mutex ( * * FUNCTION: acpi_ex_release_mutex * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * @@ -281,9 +283,8 @@ acpi_ex_release_mutex ( return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* - * Match multiple Acquires with multiple Releases - */ + /* Match multiple Acquires with multiple Releases */ + obj_desc->mutex.acquisition_depth--; if (obj_desc->mutex.acquisition_depth != 0) { /* Just decrement the depth and return */ @@ -299,10 +300,10 @@ acpi_ex_release_mutex ( status = acpi_ex_system_release_mutex (obj_desc); - /* Update the mutex and walk state */ + /* Update the mutex and walk state, restore sync_level before acquire */ obj_desc->mutex.owner_thread = NULL; - walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; return_ACPI_STATUS (status); } @@ -312,7 +313,7 @@ acpi_ex_release_mutex ( * * FUNCTION: acpi_ex_release_all_mutexes * - * PARAMETERS: *mutex_list - Head of the mutex list + * PARAMETERS: mutex_list - Head of the mutex list * * RETURN: Status * @@ -332,9 +333,8 @@ acpi_ex_release_all_mutexes ( ACPI_FUNCTION_ENTRY (); - /* - * Traverse the list of owned mutexes, releasing each one. - */ + /* Traverse the list of owned mutexes, releasing each one */ + while (next) { this = next; next = this->mutex.next; @@ -352,7 +352,11 @@ acpi_ex_release_all_mutexes ( /* Mark mutex unowned */ - this->mutex.owner_thread = NULL; + this->mutex.owner_thread = NULL; + + /* Update Thread sync_level (Last mutex is the important one) */ + + thread->current_sync_level = this->mutex.original_sync_level; } } --- linux-2.6.8-rc1/drivers/acpi/executer/exoparg2.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/executer/exoparg2.c 2004-07-13 17:09:17.000000000 -0700 @@ -97,6 +97,7 @@ acpi_ex_opcode_2A_0T_0R ( { union acpi_operand_object **operand = &walk_state->operands[0]; struct acpi_namespace_node *node; + u32 value; acpi_status status = AE_OK; @@ -113,16 +114,46 @@ acpi_ex_opcode_2A_0T_0R ( node = (struct acpi_namespace_node *) operand[0]; + /* Second value is the notify value */ + + value = (u32) operand[1]->integer.value; + /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unexpected notify object type [%s]\n", acpi_ut_get_type_name (node->type))); status = AE_AML_OPERAND_TYPE; break; } +#ifdef ACPI_GPE_NOTIFY_CHECK + /* + * GPE method wake/notify check. Here, we want to ensure that we + * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx + * GPE method during system runtime. If we do, the GPE is marked + * as "wake-only" and disabled. + * + * 1) Is the Notify() value == device_wake? + * 2) Is this a GPE deferred method? (An _Lxx or _Exx method) + * 3) Did the original GPE happen at system runtime? + * (versus during wake) + * + * If all three cases are true, this is a wake-only GPE that should + * be disabled at runtime. + */ + if (value == 2) /* device_wake */ { + status = acpi_ev_check_for_wake_only_gpe (walk_state->gpe_event_info); + if (ACPI_FAILURE (status)) { + /* AE_WAKE_ONLY_GPE only error, means ignore this notify */ + + return_ACPI_STATUS (AE_OK) + } + } +#endif + /* * Dispatch the notify to the appropriate handler * NOTE: the request is queued for execution after this method @@ -130,8 +161,7 @@ acpi_ex_opcode_2A_0T_0R ( * from this thread -- because handlers may in turn run other * control methods. */ - status = acpi_ev_queue_notify_request (node, - (u32) operand[1]->integer.value); + status = acpi_ev_queue_notify_request (node, value); break; @@ -543,9 +573,17 @@ acpi_ex_opcode_2A_0T_1R ( * Execute the Opcode */ if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + /* Both operands must be of the same type */ + + if (ACPI_GET_OBJECT_TYPE (operand[0]) != + ACPI_GET_OBJECT_TYPE (operand[1])) { + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + logical_result = acpi_ex_do_logical_op (walk_state->opcode, - operand[0]->integer.value, - operand[1]->integer.value); + operand[0], + operand[1]); goto store_logical_result; } --- linux-2.6.8-rc1/drivers/acpi/executer/exresolv.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/executer/exresolv.c 2004-07-13 17:09:17.000000000 -0700 @@ -187,15 +187,15 @@ acpi_ex_resolve_object_to_value ( return_ACPI_STATUS (status); } + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n", + stack_desc->reference.offset, obj_desc)); + /* * Now we can delete the original Reference Object and - * replace it with the resolve value + * replace it with the resolved value */ acpi_ut_remove_reference (stack_desc); *stack_ptr = obj_desc; - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] value_obj is %p\n", - stack_desc->reference.offset, obj_desc)); break; --- linux-2.6.8-rc1/drivers/acpi/executer/exstore.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/executer/exstore.c 2004-07-13 17:09:17.000000000 -0700 @@ -102,7 +102,8 @@ acpi_ex_store ( * Storing an object into a Named node. */ status = acpi_ex_store_object_to_node (source_desc, - (struct acpi_namespace_node *) dest_desc, walk_state); + (struct acpi_namespace_node *) dest_desc, walk_state, + ACPI_IMPLICIT_CONVERSION); return_ACPI_STATUS (status); } @@ -153,7 +154,7 @@ acpi_ex_store ( /* Storing an object into a Name "container" */ status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, - walk_state); + walk_state, ACPI_IMPLICIT_CONVERSION); break; @@ -399,6 +400,7 @@ acpi_ex_store_object_to_index ( * PARAMETERS: source_desc - Value to be stored * Node - Named object to receive the value * walk_state - Current walk state + * implicit_conversion - Perform implicit conversion (yes/no) * * RETURN: Status * @@ -421,7 +423,8 @@ acpi_status acpi_ex_store_object_to_node ( union acpi_operand_object *source_desc, struct acpi_namespace_node *node, - struct acpi_walk_state *walk_state) + struct acpi_walk_state *walk_state, + u8 implicit_conversion) { acpi_status status = AE_OK; union acpi_operand_object *target_desc; @@ -451,6 +454,14 @@ acpi_ex_store_object_to_node ( return_ACPI_STATUS (status); } + /* If no implicit conversion, drop into the default case below */ + + if (!implicit_conversion) { + /* Force execution of default (no implicit conversion) */ + + target_type = ACPI_TYPE_ANY; + } + /* * Do the actual store operation */ --- linux-2.6.8-rc1/drivers/acpi/hardware/hwgpe.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/hardware/hwgpe.c 2004-07-13 17:09:17.000000000 -0700 @@ -51,104 +51,24 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_enable_gpe + * FUNCTION: acpi_hw_write_gpe_enable_reg * * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled * * RETURN: Status * - * DESCRIPTION: Enable a single GPE. + * DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must + * already be cleared or set in the parent register + * enable_for_run mask. * ******************************************************************************/ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; - acpi_status status; - - - ACPI_FUNCTION_ENTRY (); - - - /* - * Read the current value of the register, set the appropriate bit - * to enable the GPE, and write out the new register. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_event_info->register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Write with the new GPE bit enabled */ - - status = acpi_hw_low_level_write (8, (in_byte | gpe_event_info->bit_mask), - &gpe_event_info->register_info->enable_address); - - return (status); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_enable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ - -void -acpi_hw_enable_gpe_for_wakeup ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* - * Set the bit so we will not enable this GPE when sleeping (and disable - * it upon wake) - */ - gpe_register_info->wake_enable |= gpe_event_info->bit_mask; - gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: Status - * - * DESCRIPTION: Disable a single GPE. - * - ******************************************************************************/ - -acpi_status -acpi_hw_disable_gpe ( - struct acpi_gpe_event_info *gpe_event_info) -{ - u32 in_byte; acpi_status status; - struct acpi_gpe_register_info *gpe_register_info; ACPI_FUNCTION_ENTRY (); @@ -158,67 +78,15 @@ acpi_hw_disable_gpe ( gpe_register_info = gpe_event_info->register_info; if (!gpe_register_info) { - return (AE_BAD_PARAMETER); + return (AE_NOT_EXIST); } - /* - * Read the current value of the register, clear the appropriate bit, - * and write out the new register value to disable the GPE. - */ - status = acpi_hw_low_level_read (8, &in_byte, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Write the byte with this GPE bit cleared */ + /* Write the entire GPE (runtime) enable register */ - status = acpi_hw_low_level_write (8, (in_byte & ~(gpe_event_info->bit_mask)), + status = acpi_hw_low_level_write (8, gpe_register_info->enable_for_run, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - - /* Make sure this GPE is disabled for wake, also */ - - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); - return (AE_OK); -} - - -/****************************************************************************** - * - * FUNCTION: acpi_hw_disable_gpe_for_wakeup - * - * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled - * - * RETURN: None - * - * DESCRIPTION: Keep track of which GPEs the OS has requested not be - * disabled when going to sleep. - * - ******************************************************************************/ - -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info) -{ - struct acpi_gpe_register_info *gpe_register_info; - - - ACPI_FUNCTION_ENTRY (); - - /* Get the info block for the entire GPE register */ - - gpe_register_info = gpe_event_info->register_info; - if (!gpe_register_info) { - return; - } - - /* Clear the bit so we will disable this when sleeping */ - - gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask); + return (status); } @@ -248,7 +116,7 @@ acpi_hw_clear_gpe ( * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write (8, gpe_event_info->bit_mask, + status = acpi_hw_low_level_write (8, gpe_event_info->register_bit, &gpe_event_info->register_info->status_address); return (status); @@ -274,7 +142,7 @@ acpi_hw_get_gpe_status ( acpi_event_status *event_status) { u32 in_byte; - u8 bit_mask; + u8 register_bit; struct acpi_gpe_register_info *gpe_register_info; acpi_status status; acpi_event_status local_event_status = 0; @@ -293,33 +161,28 @@ acpi_hw_get_gpe_status ( /* Get the register bitmask for this GPE */ - bit_mask = gpe_event_info->bit_mask; + register_bit = gpe_event_info->register_bit; - /* GPE Enabled? */ - - status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } + /* GPE currently enabled? (enabled for runtime?) */ - if (bit_mask & in_byte) { + if (register_bit & gpe_register_info->enable_for_run) { local_event_status |= ACPI_EVENT_FLAG_ENABLED; } - /* GPE Enabled for wake? */ + /* GPE enabled for wake? */ - if (bit_mask & gpe_register_info->wake_enable) { + if (register_bit & gpe_register_info->enable_for_wake) { local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED; } - /* GPE active (set)? */ + /* GPE currently active (status bit == 1)? */ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } - if (bit_mask & in_byte) { + if (register_bit & in_byte) { local_event_status |= ACPI_EVENT_FLAG_SET; } @@ -411,64 +274,43 @@ acpi_hw_clear_gpe_block ( /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpe_block_for_sleep + * FUNCTION: acpi_hw_enable_runtime_gpe_block * * PARAMETERS: gpe_xrupt_info - GPE Interrupt info * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within - * a single GPE block + * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ -static acpi_status -acpi_hw_prepare_gpe_block_for_sleep ( +acpi_status +acpi_hw_enable_runtime_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) { u32 i; - struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; acpi_status status; - /* Get the register info for the entire GPE block */ - - gpe_register_info = gpe_block->register_info; + /* NOTE: assumes that all GPEs are currently disabled */ /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { - /* - * Read the enabled/disabled status of all GPEs. We - * will be using it to restore all the GPEs later. - * - * NOTE: Wake GPEs are are ALL disabled at this time, so when we wake - * and restore this register, they will be automatically disabled. - */ - status = acpi_hw_low_level_read (8, &in_value, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); + if (!gpe_block->register_info[i].enable_for_run) { + continue; } - gpe_register_info->enable = (u8) in_value; + /* Enable all "runtime" GPEs in this register */ - /* - * 1) Disable all runtime GPEs - * 2) Enable all wakeup GPEs - */ - status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, - &gpe_register_info->enable_address); + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE (status)) { return (status); } - - /* Point to next GPE register */ - - gpe_register_info++; } return (AE_OK); @@ -477,122 +319,125 @@ acpi_hw_prepare_gpe_block_for_sleep ( /****************************************************************************** * - * FUNCTION: acpi_hw_prepare_gpes_for_sleep + * FUNCTION: acpi_hw_enable_wakeup_gpe_block * - * PARAMETERS: None + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs. - * Called with interrupts disabled. The interrupt handler also - * modifies gpe_register_info->Enable, so it should not be - * given the chance to run until after the runtime GPEs are - * re-enabled. + * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes + * combination wake/run GPEs.) * ******************************************************************************/ acpi_status -acpi_hw_prepare_gpes_for_sleep ( - void) +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) { + u32 i; acpi_status status; - ACPI_FUNCTION_ENTRY (); + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + if (!gpe_block->register_info[i].enable_for_wake) { + continue; + } + /* Enable all "wake" GPEs in this register */ - status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep); - return (status); + status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i].enable_address); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + return (AE_OK); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpe_block_on_wake + * FUNCTION: acpi_hw_disable_all_gpes * - * PARAMETERS: gpe_xrupt_info - GPE Interrupt info - * gpe_block - Gpe Block info + * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one - * GPE block + * DESCRIPTION: Disable and clear all GPEs * ******************************************************************************/ -static acpi_status -acpi_hw_restore_gpe_block_on_wake ( - struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) +acpi_status +acpi_hw_disable_all_gpes ( + void) { - u32 i; - struct acpi_gpe_register_info *gpe_register_info; acpi_status status; - /* This callback processes one entire GPE block */ + ACPI_FUNCTION_TRACE ("hw_disable_all_gpes"); - /* Get the register info for the entire GPE block */ - gpe_register_info = gpe_block->register_info; + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block); + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); + return_ACPI_STATUS (status); +} - /* Examine each GPE register within the block */ - for (i = 0; i < gpe_block->register_count; i++) { - /* Clear the entire status register */ +/****************************************************************************** + * + * FUNCTION: acpi_hw_enable_all_runtime_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all GPEs of the given type + * + ******************************************************************************/ - status = acpi_hw_low_level_write (8, 0xFF, - &gpe_block->register_info[i].status_address); - if (ACPI_FAILURE (status)) { - return (status); - } +acpi_status +acpi_hw_enable_all_runtime_gpes ( + void) +{ + acpi_status status; - /* - * Restore the GPE Enable register, which will do the following: - * - * 1) Disable all wakeup GPEs - * 2) Enable all runtime GPEs - * - * (On sleep, we saved the enabled status of all GPEs) - */ - status = acpi_hw_low_level_write (8, gpe_register_info->enable, - &gpe_register_info->enable_address); - if (ACPI_FAILURE (status)) { - return (status); - } - /* Point to next GPE register */ + ACPI_FUNCTION_TRACE ("hw_enable_all_runtime_gpes"); - gpe_register_info++; - } - return (AE_OK); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_runtime_gpe_block); + return_ACPI_STATUS (status); } /****************************************************************************** * - * FUNCTION: acpi_hw_restore_gpes_on_wake + * FUNCTION: acpi_hw_enable_all_wakeup_gpes * * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all - * GPE blocks + * DESCRIPTION: Enable all GPEs of the given type * ******************************************************************************/ acpi_status -acpi_hw_restore_gpes_on_wake ( +acpi_hw_enable_all_wakeup_gpes ( void) { acpi_status status; - ACPI_FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE ("hw_enable_all_wakeup_gpes"); - status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake); - return (status); + status = acpi_ev_walk_gpe_list (acpi_hw_enable_wakeup_gpe_block); + return_ACPI_STATUS (status); } + --- linux-2.6.8-rc1/drivers/acpi/hardware/hwregs.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/hardware/hwregs.c 2004-07-13 17:09:17.000000000 -0700 @@ -135,7 +135,7 @@ acpi_get_sleep_type_data ( u8 *sleep_type_b) { acpi_status status = AE_OK; - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); @@ -152,8 +152,9 @@ acpi_get_sleep_type_data ( /* * Evaluate the namespace object containing the values for this state */ + info.parameters = NULL; status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], - NULL, &obj_desc); + &info); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); @@ -163,48 +164,50 @@ acpi_get_sleep_type_data ( /* Must have a return object */ - if (!obj_desc) { + if (!info.return_object) { ACPI_REPORT_ERROR (("Missing Sleep State object\n")); status = AE_NOT_EXIST; } /* It must be of type Package */ - else if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_PACKAGE) { + else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); status = AE_AML_OPERAND_TYPE; } /* The package must have at least two elements */ - else if (obj_desc->package.count < 2) { + else if (info.return_object->package.count < 2) { ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); status = AE_AML_NO_OPERAND; } /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) { + else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", - acpi_ut_get_object_type_name (obj_desc->package.elements[0]), - acpi_ut_get_object_type_name (obj_desc->package.elements[1]))); + acpi_ut_get_object_type_name (info.return_object->package.elements[0]), + acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { /* * Valid _Sx_ package size, type, and value */ - *sleep_type_a = (u8) (obj_desc->package.elements[0])->integer.value; - *sleep_type_b = (u8) (obj_desc->package.elements[1])->integer.value; + *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", + acpi_gbl_sleep_state_names[sleep_state], info.return_object, + acpi_ut_get_object_type_name (info.return_object))); } - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (status); } --- linux-2.6.8-rc1/drivers/acpi/hardware/hwsleep.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/hardware/hwsleep.c 2004-07-13 17:09:17.000000000 -0700 @@ -265,19 +265,21 @@ acpi_enter_sleep_state ( sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); - if (sleep_state != ACPI_STATE_S5) { - /* Clear wake status */ + /* Clear wake status */ - status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } - status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + /* Clear all fixed and general purpose status bits */ + status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (sleep_state != ACPI_STATE_S5) { /* Disable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); @@ -287,10 +289,16 @@ acpi_enter_sleep_state ( } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -420,10 +428,16 @@ acpi_enter_sleep_state_s4bios ( } /* - * 1) Disable all runtime GPEs + * 1) Disable/Clear all GPEs * 2) Enable all wakeup GPEs */ - status = acpi_hw_prepare_gpes_for_sleep (); + status = acpi_hw_disable_all_gpes (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = FALSE; + + status = acpi_hw_enable_all_wakeup_gpes (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -540,19 +554,25 @@ acpi_leave_sleep_state ( /* * Restore the GPEs: - * 1) Disable all wakeup GPEs + * 1) Disable/Clear all GPEs * 2) Enable all runtime GPEs */ - status = acpi_hw_restore_gpes_on_wake (); + status = acpi_hw_disable_all_gpes (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_gbl_system_awake_and_running = TRUE; + + status = acpi_hw_enable_all_runtime_gpes (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Enable power button */ - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); /* Enable BM arbitration */ --- linux-2.6.8-rc1/drivers/acpi/Makefile 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/acpi/Makefile 2004-07-13 17:09:17.588599000 -0700 @@ -47,4 +47,4 @@ obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-$(CONFIG_ACPI_BUS) += scan.o +obj-$(CONFIG_ACPI_BUS) += scan.o motherboard.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/acpi/motherboard.c 2004-07-13 17:09:17.000000000 -0700 @@ -0,0 +1,161 @@ +/* + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("acpi_motherboard") + +/* Dell use PNP0C01 instead of PNP0C02 */ +#define ACPI_MB_HID1 "PNP0C01" +#define ACPI_MB_HID2 "PNP0C02" + +/** + * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved + * Doesn't care about the failure of 'request_region', since other may reserve + * the io ports as well + */ +#define IS_RESERVED_ADDR(base, len) \ + (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ + && ((base) + (len) > PCIBIOS_MIN_IO)) + +static acpi_status +acpi_reserve_io_ranges (struct acpi_resource *res, void *data) +{ + ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges"); + + if (res->id == ACPI_RSTYPE_IO) { + struct acpi_resource_io *io_res = &res->data.io; + + if (io_res->min_base_address != io_res->max_base_address) + return AE_OK; + if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + io_res->min_base_address, + io_res->min_base_address + io_res->range_length)); + request_region(io_res->min_base_address, + io_res->range_length, "motherboard"); + } + }else if (res->id == ACPI_RSTYPE_FIXED_IO) { + struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io; + + if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n", + fixed_io_res->base_address, + fixed_io_res->base_address + fixed_io_res->range_length)); + request_region(fixed_io_res->base_address, + fixed_io_res->range_length, "motherboard"); + } + }else { + /* Memory mapped IO? */ + } + + return AE_OK; +} + +static int acpi_motherboard_add (struct acpi_device *device) +{ + if (!device) + return -EINVAL; + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + acpi_reserve_io_ranges, NULL); + + return 0; +} + +static struct acpi_driver acpi_motherboard_driver1 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID1, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static struct acpi_driver acpi_motherboard_driver2 = { + .name = "motherboard", + .class = "", + .ids = ACPI_MB_HID2, + .ops = { + .add = acpi_motherboard_add, + }, +}; + +static void __init +acpi_reserve_resources (void) +{ + if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1a_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len) + request_region(acpi_gbl_FADT->xpm1b_evt_blk.address, + acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK"); + + if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK"); + + if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len) + request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address, + acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK"); + + if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4) + request_region(acpi_gbl_FADT->xpm_tmr_blk.address, + 4, "PM_TMR"); + + if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len) + request_region(acpi_gbl_FADT->xpm2_cnt_blk.address, + acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK"); + + /* Length of GPE blocks must be a non-negative multiple of 2 */ + + if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len && + !(acpi_gbl_FADT->gpe0_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe0_blk.address, + acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK"); + + if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len && + !(acpi_gbl_FADT->gpe1_blk_len & 0x1)) + request_region(acpi_gbl_FADT->xgpe1_blk.address, + acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK"); +} + +static int __init acpi_motherboard_init(void) +{ + acpi_bus_register_driver(&acpi_motherboard_driver1); + acpi_bus_register_driver(&acpi_motherboard_driver2); + /* + * Guarantee motherboard IO reservation first + * This module must run after scan.c + */ + if (!acpi_disabled) + acpi_reserve_resources (); + return 0; +} + +subsys_initcall(acpi_motherboard_init); --- linux-2.6.8-rc1/drivers/acpi/namespace/nsaccess.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/namespace/nsaccess.c 2004-07-13 17:09:17.000000000 -0700 @@ -193,7 +193,7 @@ acpi_ns_root_initialize (void) case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; - obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL + obj_desc->mutex.sync_level = (u8) ACPI_STRTOUL (val, NULL, 10); if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { --- linux-2.6.8-rc1/drivers/acpi/namespace/nsalloc.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/acpi/namespace/nsalloc.c 2004-07-13 17:09:17.000000000 -0700 @@ -267,7 +267,7 @@ acpi_ns_install_node ( else { #ifdef ACPI_ALPHABETIC_NAMESPACE /* - * Walk the list whilst searching for the the correct + * Walk the list whilst searching for the correct * alphabetic placement. */ previous_child_node = NULL; --- linux-2.6.8-rc1/drivers/acpi/namespace/nseval.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/namespace/nseval.c 2004-07-13 17:09:17.000000000 -0700 @@ -77,13 +77,10 @@ acpi_status acpi_ns_evaluate_relative ( - struct acpi_namespace_node *handle, char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *node = NULL; union acpi_generic_state *scope_info; char *internal_path = NULL; @@ -95,7 +92,7 @@ acpi_ns_evaluate_relative ( /* * Must have a valid object handle */ - if (!handle) { + if (!info || !info->node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -118,8 +115,8 @@ acpi_ns_evaluate_relative ( goto cleanup; } - prefix_node = acpi_ns_map_handle_to_node (handle); - if (!prefix_node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; @@ -127,7 +124,7 @@ acpi_ns_evaluate_relative ( /* Lookup the name in the namespace */ - scope_info->scope.node = prefix_node; + scope_info->scope.node = info->node; status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); @@ -147,7 +144,8 @@ acpi_ns_evaluate_relative ( ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", pathname, node, acpi_ns_get_attached_object (node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + info->node = node; + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -166,6 +164,7 @@ cleanup1: * FUNCTION: acpi_ns_evaluate_by_name * * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Contains: * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * Params - List of parameters to pass to the method, @@ -184,11 +183,9 @@ cleanup1: acpi_status acpi_ns_evaluate_by_name ( char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { acpi_status status; - struct acpi_namespace_node *node = NULL; char *internal_path = NULL; @@ -211,7 +208,7 @@ acpi_ns_evaluate_by_name ( status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, - &node); + &info->node); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -226,9 +223,9 @@ acpi_ns_evaluate_by_name ( * to evaluate it. */ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", - pathname, node, acpi_ns_get_attached_object (node))); + pathname, info->node, acpi_ns_get_attached_object (info->node))); - status = acpi_ns_evaluate_by_handle (node, params, return_object); + status = acpi_ns_evaluate_by_handle (info); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", pathname)); @@ -254,6 +251,7 @@ cleanup: * Params - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. + * param_type - Type of Parameter list * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * @@ -267,13 +265,9 @@ cleanup: acpi_status acpi_ns_evaluate_by_handle ( - struct acpi_namespace_node *handle, - union acpi_operand_object **params, - union acpi_operand_object **return_object) + struct acpi_parameter_info *info) { - struct acpi_namespace_node *node; acpi_status status; - union acpi_operand_object *local_return_object; ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle"); @@ -287,15 +281,13 @@ acpi_ns_evaluate_by_handle ( /* Parameter Validation */ - if (!handle) { + if (!info) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - if (return_object) { - /* Initialize the return value to an invalid object */ + /* Initialize the return value to an invalid object */ - *return_object = NULL; - } + info->return_object = NULL; /* Get the prefix handle and Node */ @@ -304,8 +296,8 @@ acpi_ns_evaluate_by_handle ( return_ACPI_STATUS (status); } - node = acpi_ns_map_handle_to_node (handle); - if (!node) { + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -315,8 +307,8 @@ acpi_ns_evaluate_by_handle ( * so that proper scoping context will be established * before execution. */ - if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { - node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); + if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object); } /* @@ -328,19 +320,18 @@ acpi_ns_evaluate_by_handle ( * In both cases, the namespace is unlocked by the * acpi_ns* procedure */ - if (acpi_ns_get_type (node) == ACPI_TYPE_METHOD) { + if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) { /* * Case 1) We have an actual control method to execute */ - status = acpi_ns_execute_control_method (node, params, - &local_return_object); + status = acpi_ns_execute_control_method (info); } else { /* * Case 2) Object is NOT a method, just return its * current value */ - status = acpi_ns_get_object_value (node, &local_return_object); + status = acpi_ns_get_object_value (info); } /* @@ -348,20 +339,6 @@ acpi_ns_evaluate_by_handle ( * be dealt with */ if (status == AE_CTRL_RETURN_VALUE) { - /* - * If the Method returned a value and the caller - * provided a place to store a returned value, Copy - * the returned value to the object descriptor provided - * by the caller. - */ - if (return_object) { - /* - * Valid return object, copy the pointer to - * the returned object - */ - *return_object = local_return_object; - } - /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ status = AE_OK; @@ -396,9 +373,7 @@ acpi_ns_evaluate_by_handle ( acpi_status acpi_ns_execute_control_method ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -409,7 +384,7 @@ acpi_ns_execute_control_method ( /* Verify that there is a method associated with this object */ - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n")); @@ -417,7 +392,7 @@ acpi_ns_execute_control_method ( return_ACPI_STATUS (AE_NULL_OBJECT); } - ACPI_DUMP_PATHNAME (method_node, "Execute Method:", + ACPI_DUMP_PATHNAME (info->node, "Execute Method:", ACPI_LV_INFO, _COMPONENT); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", @@ -444,7 +419,7 @@ acpi_ns_execute_control_method ( return_ACPI_STATUS (status); } - status = acpi_psx_execute (method_node, params, return_obj_desc); + status = acpi_psx_execute (info); acpi_ex_exit_interpreter (); return_ACPI_STATUS (status); @@ -468,11 +443,10 @@ acpi_ns_execute_control_method ( acpi_status acpi_ns_get_object_value ( - struct acpi_namespace_node *node, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status = AE_OK; - struct acpi_namespace_node *resolved_node = node; + struct acpi_namespace_node *resolved_node = info->node; ACPI_FUNCTION_TRACE ("ns_get_object_value"); @@ -518,9 +492,9 @@ acpi_ns_get_object_value ( if (ACPI_SUCCESS (status)) { status = AE_CTRL_RETURN_VALUE; - *return_obj_desc = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); + info->return_object = ACPI_CAST_PTR (union acpi_operand_object, resolved_node); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n", - *return_obj_desc, acpi_ut_get_object_type_name (*return_obj_desc))); + info->return_object, acpi_ut_get_object_type_name (info->return_object))); } } --- linux-2.6.8-rc1/drivers/acpi/namespace/nsinit.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/namespace/nsinit.c 2004-07-13 17:09:17.000000000 -0700 @@ -149,7 +149,7 @@ acpi_ns_initialize_devices ( return_ACPI_STATUS (status); } - /* Walk namespace for all objects of type Device or Processor */ + /* Walk namespace for all objects */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); @@ -337,25 +337,29 @@ acpi_ns_init_one_device ( void *context, void **return_value) { - acpi_status status; - struct acpi_namespace_node *node; - u32 flags; struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context; + struct acpi_parameter_info pinfo; + u32 flags; + acpi_status status; ACPI_FUNCTION_TRACE ("ns_init_one_device"); - node = acpi_ns_map_handle_to_node (obj_handle); - if (!node) { + pinfo.parameters = NULL; + pinfo.parameter_type = ACPI_PARAM_ARGS; + + pinfo.node = acpi_ns_map_handle_to_node (obj_handle); + if (!pinfo.node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* - * We will run _STA/_INI on Devices and Processors only + * We will run _STA/_INI on Devices, Processors and thermal_zones only */ - if ((node->type != ACPI_TYPE_DEVICE) && - (node->type != ACPI_TYPE_PROCESSOR)) { + if ((pinfo.node->type != ACPI_TYPE_DEVICE) && + (pinfo.node->type != ACPI_TYPE_PROCESSOR) && + (pinfo.node->type != ACPI_TYPE_THERMAL)) { return_ACPI_STATUS (AE_OK); } @@ -368,17 +372,17 @@ acpi_ns_init_one_device ( /* * Run _STA to determine if we can run _INI on the device. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, node, "_STA")); - status = acpi_ut_execute_STA (node, &flags); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + status = acpi_ut_execute_STA (pinfo.node, &flags); if (ACPI_FAILURE (status)) { - if (node->type == ACPI_TYPE_DEVICE) { + if (pinfo.node->type == ACPI_TYPE_DEVICE) { /* Ignore error and move on to next device */ return_ACPI_STATUS (AE_OK); } - /* _STA is not required for Processor objects */ + /* _STA is not required for Processor or thermal_zone objects */ } else { info->num_STA++; @@ -393,22 +397,22 @@ acpi_ns_init_one_device ( /* * The device is present. Run _INI. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, obj_handle, "_INI")); - status = acpi_ns_evaluate_relative (obj_handle, "_INI", NULL, NULL); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); + status = acpi_ns_evaluate_relative ("_INI", &pinfo); if (ACPI_FAILURE (status)) { /* No _INI (AE_NOT_FOUND) means device requires no initialization */ if (status != AE_NOT_FOUND) { /* Ignore error and move on to next device */ - #ifdef ACPI_DEBUG_OUTPUT - char *scope_name = acpi_ns_get_external_pathname (obj_handle); +#ifdef ACPI_DEBUG_OUTPUT + char *scope_name = acpi_ns_get_external_pathname (pinfo.node); ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", scope_name, acpi_format_exception (status))); ACPI_MEM_FREE (scope_name); - #endif +#endif } status = AE_OK; @@ -422,7 +426,7 @@ acpi_ns_init_one_device ( if (acpi_gbl_init_handler) { /* External initialization handler is present, call it */ - status = acpi_gbl_init_handler (obj_handle, ACPI_INIT_DEVICE_INI); + status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI); } --- linux-2.6.8-rc1/drivers/acpi/namespace/nsparse.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/namespace/nsparse.c 2004-07-13 17:09:17.000000000 -0700 @@ -94,8 +94,9 @@ acpi_ns_one_complete_parse ( return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, table_desc->aml_start, - table_desc->aml_length, NULL, NULL, pass_number); + status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, + table_desc->aml_start, table_desc->aml_length, + NULL, pass_number); if (ACPI_FAILURE (status)) { acpi_ds_delete_walk_state (walk_state); return_ACPI_STATUS (status); --- linux-2.6.8-rc1/drivers/acpi/namespace/nsxfeval.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/namespace/nsxfeval.c 2004-07-13 17:09:17.000000000 -0700 @@ -174,8 +174,7 @@ acpi_evaluate_object ( { acpi_status status; acpi_status status2; - union acpi_operand_object **internal_params = NULL; - union acpi_operand_object *internal_return_obj = NULL; + struct acpi_parameter_info info; acpi_size buffer_space_needed; u32 i; @@ -183,6 +182,11 @@ acpi_evaluate_object ( ACPI_FUNCTION_TRACE ("acpi_evaluate_object"); + info.node = handle; + info.parameters = NULL; + info.return_object = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* * If there are parameters to be passed to the object * (which must be a control method), the external objects @@ -193,9 +197,10 @@ acpi_evaluate_object ( * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ - internal_params = ACPI_MEM_CALLOCATE (((acpi_size) external_params->count + 1) * - sizeof (void *)); - if (!internal_params) { + info.parameters = ACPI_MEM_CALLOCATE ( + ((acpi_size) external_params->count + 1) * + sizeof (void *)); + if (!info.parameters) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -205,15 +210,16 @@ acpi_evaluate_object ( */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], - &internal_params[i]); + &info.parameters[i]); if (ACPI_FAILURE (status)) { - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); return_ACPI_STATUS (status); } } - internal_params[external_params->count] = NULL; + info.parameters[external_params->count] = NULL; } + /* * Three major cases: * 1) Fully qualified pathname @@ -225,8 +231,7 @@ acpi_evaluate_object ( /* * The path is fully qualified, just evaluate by name */ - status = acpi_ns_evaluate_by_name (pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_name (pathname, &info); } else if (!handle) { /* @@ -256,15 +261,13 @@ acpi_evaluate_object ( * The null pathname case means the handle is for * the actual object to be evaluated */ - status = acpi_ns_evaluate_by_handle (handle, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_by_handle (&info); } else { /* * Both a Handle and a relative Pathname */ - status = acpi_ns_evaluate_relative (handle, pathname, internal_params, - &internal_return_obj); + status = acpi_ns_evaluate_relative (pathname, &info); } } @@ -274,11 +277,11 @@ acpi_evaluate_object ( * copy the return value to an external object. */ if (return_buffer) { - if (!internal_return_obj) { + if (!info.return_object) { return_buffer->length = 0; } else { - if (ACPI_GET_DESCRIPTOR_TYPE (internal_return_obj) == ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE (info.return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to @@ -288,7 +291,7 @@ acpi_evaluate_object ( * support for various types at a later date if necessary. */ status = AE_TYPE; - internal_return_obj = NULL; /* No need to delete a NS Node */ + info.return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } @@ -297,7 +300,7 @@ acpi_evaluate_object ( * Find out how large a buffer is needed * to contain the returned object */ - status = acpi_ut_get_object_size (internal_return_obj, + status = acpi_ut_get_object_size (info.return_object, &buffer_space_needed); if (ACPI_SUCCESS (status)) { /* Validate/Allocate/Clear caller buffer */ @@ -309,13 +312,14 @@ acpi_evaluate_object ( */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Needed buffer size %X, %s\n", - (u32) buffer_space_needed, acpi_format_exception (status))); + (u32) buffer_space_needed, + acpi_format_exception (status))); } else { /* * We have enough space for the object, build it */ - status = acpi_ut_copy_iobject_to_eobject (internal_return_obj, + status = acpi_ut_copy_iobject_to_eobject (info.return_object, return_buffer); } } @@ -323,7 +327,7 @@ acpi_evaluate_object ( } } - if (internal_return_obj) { + if (info.return_object) { /* * Delete the internal return object. NOTE: Interpreter * must be locked to avoid race condition. @@ -334,7 +338,7 @@ acpi_evaluate_object ( * Delete the internal return object. (Or at least * decrement the reference count by one) */ - acpi_ut_remove_reference (internal_return_obj); + acpi_ut_remove_reference (info.return_object); acpi_ex_exit_interpreter (); } } @@ -342,10 +346,10 @@ acpi_evaluate_object ( /* * Free the input parameter list (if we created one), */ - if (internal_params) { + if (info.parameters) { /* Free the allocated parameter block */ - acpi_ut_delete_internal_object_list (internal_params); + acpi_ut_delete_internal_object_list (info.parameters); } return_ACPI_STATUS (status); --- linux-2.6.8-rc1/drivers/acpi/namespace/nsxfname.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/namespace/nsxfname.c 2004-07-13 17:09:17.000000000 -0700 @@ -281,7 +281,7 @@ acpi_get_object_info ( if (info.type == ACPI_TYPE_DEVICE) { /* * Get extra info for ACPI Devices objects only: - * Run the Device _HID, _UID, _CID, _STA, and _ADR methods. + * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info.Valid bitfield is used @@ -330,7 +330,7 @@ acpi_get_object_info ( status = acpi_ut_execute_sxds (node, info.highest_dstates); if (ACPI_SUCCESS (status)) { - info.valid |= ACPI_VALID_STA; + info.valid |= ACPI_VALID_SXDS; } status = AE_OK; --- linux-2.6.8-rc1/drivers/acpi/osl.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/acpi/osl.c 2004-07-13 17:09:17.630592616 -0700 @@ -1066,15 +1066,15 @@ __setup("acpi_serialize", acpi_serialize * Run-time events on the same GPE this flag is available * to tell Linux to keep the wake-time GPEs enabled at run-time. */ -static int __init -acpi_leave_gpes_disabled_setup(char *str) +int __init +acpi_wake_gpes_always_on_setup(char *str) { - printk(KERN_INFO PREFIX "leave wake GPEs disabled\n"); + printk(KERN_INFO PREFIX "wake GPEs not disabled\n"); - acpi_gbl_leave_wake_gpes_disabled = TRUE; + acpi_gbl_leave_wake_gpes_disabled = FALSE; return 1; } -__setup("acpi_leave_gpes_disabled", acpi_leave_gpes_disabled_setup); +__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); --- linux-2.6.8-rc1/drivers/acpi/parser/psopcode.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/parser/psopcode.c 2004-07-13 17:09:17.000000000 -0700 @@ -251,7 +251,7 @@ #define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) #define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) #define ARGI_DEBUG_OP ARG_NONE #define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) #define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) @@ -270,10 +270,10 @@ #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) #define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE --- linux-2.6.8-rc1/drivers/acpi/parser/psxface.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/parser/psxface.c 2004-07-13 17:09:17.000000000 -0700 @@ -57,7 +57,7 @@ * * FUNCTION: acpi_psx_execute * - * PARAMETERS: method_node - A method object containing both the AML + * PARAMETERS: Info->Node - A method object containing both the AML * address and length. * **Params - List of parameters to pass to method, * terminated by NULL. Params itself may be @@ -73,9 +73,7 @@ acpi_status acpi_psx_execute ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc) + struct acpi_parameter_info *info) { acpi_status status; union acpi_operand_object *obj_desc; @@ -89,29 +87,30 @@ acpi_psx_execute ( /* Validate the Node and get the attached object */ - if (!method_node) { + if (!info || !info->node) { return_ACPI_STATUS (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_node); + obj_desc = acpi_ns_get_attached_object (info->node); if (!obj_desc) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Init for new method, wait on concurrency semaphore */ - status = acpi_ds_begin_method_execution (method_node, obj_desc, NULL); + status = acpi_ds_begin_method_execution (info->node, obj_desc, NULL); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* * The caller "owns" the parameters, so give each one an extra * reference */ - for (i = 0; params[i]; i++) { - acpi_ut_add_reference (params[i]); + for (i = 0; info->parameters[i]; i++) { + acpi_ut_add_reference (info->parameters[i]); } } @@ -121,7 +120,7 @@ acpi_psx_execute ( */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Parse **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -147,8 +146,9 @@ acpi_psx_execute ( goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, NULL, NULL, 1); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -159,7 +159,6 @@ acpi_psx_execute ( acpi_ps_delete_parse_tree (op); if (ACPI_FAILURE (status)) { goto cleanup1; /* Walk state is already deleted */ - } /* @@ -167,7 +166,7 @@ acpi_psx_execute ( */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Begin Method Execution **** Entry=%p obj=%p\n", - method_node, obj_desc)); + info->node, obj_desc)); /* Create and init a Root Node */ @@ -179,8 +178,8 @@ acpi_psx_execute ( /* Init new op with the method name and pointer back to the NS node */ - acpi_ps_set_name (op, method_node->name.integer); - op->common.node = method_node; + acpi_ps_set_name (op, info->node->name.integer); + op->common.node = info->node; /* Create and initialize a new walk state */ @@ -190,8 +189,9 @@ acpi_psx_execute ( goto cleanup2; } - status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, params, return_obj_desc, 3); + status = acpi_ds_init_aml_walk (walk_state, op, info->node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, info, 3); if (ACPI_FAILURE (status)) { goto cleanup3; } @@ -210,13 +210,14 @@ cleanup2: acpi_ps_delete_parse_tree (op); cleanup1: - if (params) { + if ((info->parameter_type == ACPI_PARAM_ARGS) && + (info->parameters)) { /* Take away the extra reference that we gave the parameters above */ - for (i = 0; params[i]; i++) { + for (i = 0; info->parameters[i]; i++) { /* Ignore errors, just do them all */ - (void) acpi_ut_update_object_reference (params[i], REF_DECREMENT); + (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT); } } @@ -228,10 +229,10 @@ cleanup1: * If the method has returned an object, signal this to the caller with * a control exception code */ - if (*return_obj_desc) { + if (info->return_object) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned obj_desc=%p\n", - *return_obj_desc)); - ACPI_DUMP_STACK_ENTRY (*return_obj_desc); + info->return_object)); + ACPI_DUMP_STACK_ENTRY (info->return_object); status = AE_CTRL_RETURN_VALUE; } --- linux-2.6.8-rc1/drivers/acpi/processor.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/acpi/processor.c 2004-07-13 17:09:17.000000000 -0700 @@ -2234,7 +2234,6 @@ acpi_processor_get_info ( * (In particular, allocating the IO range for Cardbus) */ request_region(pr->throttling.address, 6, "ACPI CPU throttle"); - request_region(acpi_fadt.xpm_tmr_blk.address, 4, "ACPI timer"); } acpi_processor_get_power_info(pr); --- linux-2.6.8-rc1/drivers/acpi/resources/rsutils.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/resources/rsutils.c 2004-07-13 17:09:17.000000000 -0700 @@ -289,6 +289,7 @@ acpi_rs_set_srs_method_data ( acpi_handle handle, struct acpi_buffer *in_buffer) { + struct acpi_parameter_info info; union acpi_operand_object *params[2]; acpi_status status; struct acpi_buffer buffer; @@ -329,10 +330,14 @@ acpi_rs_set_srs_method_data ( params[0]->common.flags = AOPOBJ_DATA_VALID; params[1] = NULL; + info.node = handle; + info.parameters = params; + info.parameter_type = ACPI_PARAM_ARGS; + /* * Execute the method, no return value */ - status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL); + status = acpi_ns_evaluate_relative ("_SRS", &info); /* * Clean up and return the status from acpi_ns_evaluate_relative --- linux-2.6.8-rc1/drivers/acpi/resources/rsxface.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/acpi/resources/rsxface.c 2004-07-13 17:09:17.000000000 -0700 @@ -259,7 +259,8 @@ acpi_walk_resources ( /* Setup pointers */ resource = (struct acpi_resource *) buffer.pointer; - buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length); + buffer_end = ACPI_CAST_PTR (struct acpi_resource, + ((u8 *) buffer.pointer + buffer.length)); /* Walk the resource list */ --- linux-2.6.8-rc1/drivers/acpi/sleep/main.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/acpi/sleep/main.c 2004-07-13 17:09:17.000000000 -0700 @@ -35,16 +35,16 @@ static int init_8259A_after_S1; /** * acpi_pm_prepare - Do preliminary suspend work. - * @state: suspend state we're entering. + * @pm_state: suspend state we're entering. * * Make sure we support the state. If we do, and we need it, set the * firmware waking vector and do arch-specific nastiness to get the * wakeup code to the waking vector. */ -static int acpi_pm_prepare(u32 state) +static int acpi_pm_prepare(u32 pm_state) { - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; if (!sleep_states[acpi_state]) return -EPERM; @@ -52,7 +52,7 @@ static int acpi_pm_prepare(u32 state) /* do we have a wakeup address for S2 and S3? */ /* Here, we support only S4BIOS, those we set the wakeup address */ /* S4OS is only supported for now via swsusp.. */ - if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) { + if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) { if (!acpi_wakeup_address) return -EFAULT; acpi_set_firmware_waking_vector( @@ -66,23 +66,23 @@ static int acpi_pm_prepare(u32 state) /** * acpi_pm_enter - Actually enter a sleep state. - * @state: State we're entering. + * @pm_state: State we're entering. * * Flush caches and go to sleep. For STR or STD, we have to call * arch-specific assembly, which in turn call acpi_enter_sleep_state(). * It's unfortunate, but it works. Please fix if you're feeling frisky. */ -static int acpi_pm_enter(u32 state) +static int acpi_pm_enter(u32 pm_state) { acpi_status status = AE_OK; unsigned long flags = 0; - u32 acpi_state = acpi_suspend_states[state]; + u32 acpi_state = acpi_suspend_states[pm_state]; ACPI_FLUSH_CPU_CACHE(); /* Do arch specific saving of state. */ - if (state > PM_SUSPEND_STANDBY) { + if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; @@ -90,7 +90,7 @@ static int acpi_pm_enter(u32 state) local_irq_save(flags); - switch (state) + switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); @@ -118,7 +118,7 @@ static int acpi_pm_enter(u32 state) * And, in the case of the latter, the memory image should have already * been loaded from disk. */ - if (state > PM_SUSPEND_STANDBY) + if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); @@ -128,15 +128,17 @@ static int acpi_pm_enter(u32 state) /** * acpi_pm_finish - Finish up suspend sequence. - * @state: State we're coming out of. + * @pm_state: State we're coming out of. * * This is called after we wake back up (or if entering the sleep state * failed). */ -static int acpi_pm_finish(u32 state) +static int acpi_pm_finish(u32 pm_state) { - acpi_leave_sleep_state(state); + u32 acpi_state = acpi_suspend_states[pm_state]; + + acpi_leave_sleep_state(acpi_state); /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); @@ -199,7 +201,7 @@ static int __init acpi_sleep_init(void) return 0; printk(KERN_INFO PREFIX "(supports"); - for (i=0; iphysical_address = phys_addr; - return_ACPI_STATUS (AE_OK); + ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); + physical_address <<= 4; /* Convert segment to physical address */ + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + status = acpi_os_map_memory ((acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, + (void *) &table_ptr); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", + physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); + } + + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); + + if (mem_rover) { + /* Found it, return the physical address */ + + physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); + + table_info->physical_address = (acpi_physical_address) physical_address; + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - status = acpi_os_map_memory ((u64) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE, + status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } @@ -459,10 +483,9 @@ acpi_tb_find_rsdp ( if (mem_rover) { /* Found it, return the physical address */ - phys_addr = ACPI_HI_RSDP_WINDOW_BASE; - phys_addr += ACPI_PTR_DIFF (mem_rover, table_ptr); + physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = phys_addr; + table_info->physical_address = (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -472,19 +495,29 @@ acpi_tb_find_rsdp ( */ else { /* - * 1) Search EBDA (low memory) paragraphs + * 1a) Get the location of the EBDA */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_LO_RSDP_WINDOW_BASE), - ACPI_LO_RSDP_WINDOW_SIZE); - if (mem_rover) { - /* Found it, return the physical address */ + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); + physical_address <<= 4; /* Convert segment to physical address */ - table_info->physical_address = ACPI_TO_INTEGER (mem_rover); - return_ACPI_STATUS (AE_OK); + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + */ + mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + ACPI_EBDA_WINDOW_SIZE); + if (mem_rover) { + /* Found it, return the physical address */ + + table_info->physical_address = ACPI_TO_INTEGER (mem_rover); + return_ACPI_STATUS (AE_OK); + } } /* - * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); --- linux-2.6.8-rc1/drivers/acpi/toshiba_acpi.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/acpi/toshiba_acpi.c 2004-07-13 17:09:13.000000000 -0700 @@ -115,7 +115,7 @@ is_valid_acpi_path(const char* methodNam acpi_handle handle; acpi_status status; - status = acpi_get_handle(0, (char*)methodName, &handle); + status = acpi_get_handle(NULL, (char*)methodName, &handle); return !ACPI_FAILURE(status); } @@ -131,7 +131,7 @@ write_acpi_int(const char* methodName, i in_objs[0].type = ACPI_TYPE_INTEGER; in_objs[0].integer.value = val; - status = acpi_evaluate_object(0, (char*)methodName, ¶ms, 0); + status = acpi_evaluate_object(NULL, (char*)methodName, ¶ms, NULL); return (status == AE_OK); } @@ -178,7 +178,7 @@ hci_raw(const u32 in[HCI_WORDS], u32 out results.length = sizeof(out_objs); results.pointer = out_objs; - status = acpi_evaluate_object(0, (char*)method_hci, ¶ms, + status = acpi_evaluate_object(NULL, (char*)method_hci, ¶ms, &results); if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) { for (i = 0; i < out_objs->package.count; ++i) { @@ -487,8 +487,8 @@ ProcItem proc_items[] = { "video" , read_video , write_video }, { "fan" , read_fan , write_fan }, { "keys" , read_keys , write_keys }, - { "version" , read_version , 0 }, - { 0 , 0 , 0 }, + { "version" , read_version , NULL }, + { NULL } }; static acpi_status __init --- linux-2.6.8-rc1/drivers/acpi/utilities/utalloc.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/utilities/utalloc.c 2004-07-13 17:09:17.000000000 -0700 @@ -259,8 +259,8 @@ acpi_ut_validate_buffer ( * * FUNCTION: acpi_ut_initialize_buffer * - * PARAMETERS: required_length - Length needed - * Buffer - Buffer to be validated + * PARAMETERS: Buffer - Buffer to be validated + * required_length - Length needed * * RETURN: Status * @@ -603,7 +603,8 @@ acpi_ut_free_and_track ( * * FUNCTION: acpi_ut_find_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * * RETURN: A list element if found; NULL otherwise. * @@ -646,7 +647,8 @@ acpi_ut_find_allocation ( * * FUNCTION: acpi_ut_track_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Size - Size of the allocation * alloc_type - MEM_MALLOC or MEM_CALLOC * Component - Component type of caller @@ -733,7 +735,8 @@ unlock_and_exit: * * FUNCTION: acpi_ut_remove_allocation * - * PARAMETERS: Allocation - Address of allocated memory + * PARAMETERS: list_id - Memory list to search + * Allocation - Address of allocated memory * Component - Component type of caller * Module - Source file name of caller * Line - Line number of caller --- linux-2.6.8-rc1/drivers/acpi/utilities/uteval.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/utilities/uteval.c 2004-07-13 17:09:17.000000000 -0700 @@ -133,7 +133,7 @@ acpi_ut_evaluate_object ( u32 expected_return_btypes, union acpi_operand_object **return_desc) { - union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; acpi_status status; u32 return_btype; @@ -141,9 +141,13 @@ acpi_ut_evaluate_object ( ACPI_FUNCTION_TRACE ("ut_evaluate_object"); + info.node = prefix_node; + info.parameters = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + /* Evaluate the object/method */ - status = acpi_ns_evaluate_relative (prefix_node, path, NULL, &obj_desc); + status = acpi_ns_evaluate_relative (path, &info); if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", @@ -159,7 +163,7 @@ acpi_ut_evaluate_object ( /* Did we get a return object? */ - if (!obj_desc) { + if (!info.return_object) { if (expected_return_btypes) { ACPI_REPORT_METHOD_ERROR ("No object was returned from", prefix_node, path, AE_NOT_EXIST); @@ -172,7 +176,7 @@ acpi_ut_evaluate_object ( /* Map the return object type to the bitmapped type */ - switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + switch (ACPI_GET_OBJECT_TYPE (info.return_object)) { case ACPI_TYPE_INTEGER: return_btype = ACPI_BTYPE_INTEGER; break; @@ -202,17 +206,17 @@ acpi_ut_evaluate_object ( ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Type returned from %s was incorrect: %X\n", - path, ACPI_GET_OBJECT_TYPE (obj_desc))); + path, ACPI_GET_OBJECT_TYPE (info.return_object))); /* On error exit, we must delete the return object */ - acpi_ut_remove_reference (obj_desc); + acpi_ut_remove_reference (info.return_object); return_ACPI_STATUS (AE_TYPE); } /* Object type is OK, return it */ - *return_desc = obj_desc; + *return_desc = info.return_object; return_ACPI_STATUS (AE_OK); } --- linux-2.6.8-rc1/drivers/acpi/utilities/utglobal.c 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/acpi/utilities/utglobal.c 2004-07-13 17:09:17.000000000 -0700 @@ -171,27 +171,40 @@ u8 acpi const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; -const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { - "\\_S0_", - "\\_S1_", - "\\_S2_", - "\\_S3_", - "\\_S4_", - "\\_S5_"}; - -const char *acpi_gbl_highest_dstate_names[4] = { - "_S1D", - "_S2D", - "_S3D", - "_S4D"}; - -/* Strings supported by the _OSI predefined (internal) method */ - -const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { - "Linux", - "Windows 2000", - "Windows 2001", - "Windows 2001.1"}; +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = +{ + "\\_S0_", + "\\_S1_", + "\\_S2_", + "\\_S3_", + "\\_S4_", + "\\_S5_" +}; + +const char *acpi_gbl_highest_dstate_names[4] = +{ + "_S1D", + "_S2D", + "_S3D", + "_S4D" +}; + +/* + * Strings supported by the _OSI predefined (internal) method. + * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS. + */ +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = +{ + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1", + "Windows 2001 SP0", + "Windows 2001 SP1", + "Windows 2001 SP2", + "Windows 2001 SP3", + "Windows 2001 SP4" +}; /****************************************************************************** @@ -213,7 +226,7 @@ const struct acpi_predefined_names {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, - {"_TZ_", ACPI_TYPE_LOCAL_SCOPE, NULL}, + {"_TZ_", ACPI_TYPE_THERMAL, NULL}, {"_REV", ACPI_TYPE_INTEGER, "2"}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, @@ -561,26 +574,37 @@ acpi_ut_get_node_name ( struct acpi_namespace_node *node = (struct acpi_namespace_node *) object; + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + if (!object) { - return ("NULL NODE"); + return ("NULL"); } - if (object == ACPI_ROOT_OBJECT) + /* Check for Root node */ + + if ((object == ACPI_ROOT_OBJECT) || + (object == acpi_gbl_root_node)) { - node = acpi_gbl_root_node; + return ("\"\\\" "); } + /* Descriptor must be a namespace node */ + if (node->descriptor != ACPI_DESC_TYPE_NAMED) { - return ("****"); + return ("####"); } + /* Name must be a valid ACPI name */ + if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) { - return ("----"); + return ("????"); } + /* Return the name */ + return (node->name.ascii); } @@ -783,10 +807,6 @@ acpi_ut_init_globals ( ACPI_FUNCTION_TRACE ("ut_init_globals"); - /* Runtime configuration */ - - acpi_gbl_create_osi_method = TRUE; - acpi_gbl_all_methods_serialized = FALSE; /* Memory allocation and cache lists */ @@ -880,6 +900,7 @@ acpi_ut_init_globals ( /* Hardware oriented */ acpi_gbl_events_initialized = FALSE; + acpi_gbl_system_awake_and_running = TRUE; /* Namespace */ --- linux-2.6.8-rc1/drivers/acpi/utilities/utxface.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/acpi/utilities/utxface.c 2004-07-13 17:09:17.000000000 -0700 @@ -157,9 +157,8 @@ acpi_enable_subsystem ( } } - /* - * Enable ACPI mode - */ + /* Enable ACPI mode */ + if (!(flags & ACPI_NO_ACPI_ENABLE)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n")); @@ -173,7 +172,21 @@ acpi_enable_subsystem ( } /* - * Initialize ACPI Event handling + * Install the default op_region handlers. These are installed unless + * other handlers have already been installed via the + * install_address_space_handler interface. + */ + if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + + status = acpi_ev_install_region_handlers (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Initialize ACPI Event handling (Fixed and General Purpose) * * NOTE: We must have the hardware AND events initialized before we can execute * ANY control methods SAFELY. Any control method can require ACPI hardware @@ -182,18 +195,18 @@ acpi_enable_subsystem ( if (!(flags & ACPI_NO_EVENT_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); - status = acpi_ev_initialize (); + status = acpi_ev_initialize_events (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } - /* Install the SCI handler, Global Lock handler, and GPE handlers */ + /* Install the SCI handler and Global Lock handler */ if (!(flags & ACPI_NO_HANDLER_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL/GPE handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); - status = acpi_ev_handler_initialize (); + status = acpi_ev_install_xrupt_handlers (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -226,18 +239,16 @@ acpi_initialize_objects ( /* - * Install the default op_region handlers. These are installed unless - * other handlers have already been installed via the - * install_address_space_handler interface. + * Run all _REG methods * - * NOTE: This will cause _REG methods to be run. Any objects accessed + * NOTE: Any objects accessed * by the _REG methods will be automatically initialized, even if they * contain executable AML (see call to acpi_ns_initialize_objects below). */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); - status = acpi_ev_init_address_spaces (); + status = acpi_ev_initialize_op_regions (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -249,7 +260,7 @@ acpi_initialize_objects ( * objects: operation_regions, buffer_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Objects\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); status = acpi_ns_initialize_objects (); if (ACPI_FAILURE (status)) { --- linux-2.6.8-rc1/drivers/atm/ambassador.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/ambassador.c 2004-07-13 17:09:13.000000000 -0700 @@ -1126,7 +1126,7 @@ static int amb_open (struct atm_vcc * at } else { r = round_up; } - error = make_rate (pcr, r, &tx_rate_bits, 0); + error = make_rate (pcr, r, &tx_rate_bits, NULL); tx_vc_bits = TX_UBR_CAPPED; tx_frame_bits = TX_FRAME_CAPPED; } @@ -1333,7 +1333,7 @@ static void amb_close (struct atm_vcc * PRINTK (KERN_ERR, "%s vcc=%p rxer[vci]=%p", "arghhh! we're going to die!", vcc, dev->rxer[vci]); - dev->rxer[vci] = 0; + dev->rxer[vci] = NULL; while (command_do (dev, &cmd)) schedule(); --- linux-2.6.8-rc1/drivers/atm/firestream.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/firestream.c 2004-07-13 17:09:29.000000000 -0700 @@ -576,7 +576,7 @@ static inline void write_fs (struct fs_d } -static inline u32 read_fs (struct fs_dev *dev, int offset) +static inline u32 read_fs (struct fs_dev *dev, int offset) { return readl (dev->base + offset); } @@ -1000,7 +1000,7 @@ static int fs_open(struct atm_vcc *atm_v } else { r = ROUND_UP; } - error = make_rate (pcr, r, &tmc0, 0); + error = make_rate (pcr, r, &tmc0, NULL); } fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr); } @@ -1380,7 +1380,7 @@ static void __devinit *aligned_kmalloc ( if (alignment <= 0x10) { t = kmalloc (size, flags); - if ((unsigned int)t & (alignment-1)) { + if ((unsigned long)t & (alignment-1)) { printk ("Kmalloc doesn't align things correctly! %p\n", t); kfree (t); return aligned_kmalloc (size, flags, alignment * 4); @@ -1496,7 +1496,7 @@ static void top_off_fp (struct fs_dev *d ne->skb = skb; ne->fp = fp; - qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset))); + qe = (struct FS_BPENTRY *)(long)(read_fs (dev, FP_EA(fp->offset))); fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe); if (qe) { qe = bus_to_virt ((long) qe); --- linux-2.6.8-rc1/drivers/atm/fore200e.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/fore200e.c 2004-07-13 17:09:53.000000000 -0700 @@ -110,8 +110,8 @@ #endif -extern const struct atmdev_ops fore200e_ops; -extern const struct fore200e_bus fore200e_bus[]; +static const struct atmdev_ops fore200e_ops; +static const struct fore200e_bus fore200e_bus[]; static struct fore200e* fore200e_boards = NULL; --- linux-2.6.8-rc1/drivers/atm/he.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/he.c 2004-07-13 17:09:13.000000000 -0700 @@ -360,7 +360,7 @@ he_init_one(struct pci_dev *pci_dev, con goto init_one_failure; } - atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, 0); + atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, NULL); if (!atm_dev) { err = -ENODEV; goto init_one_failure; --- linux-2.6.8-rc1/drivers/atm/horizon.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/horizon.c 2004-07-13 17:09:13.000000000 -0700 @@ -1184,7 +1184,7 @@ static void tx_schedule (hrz_dev * const // tx_regions == 0 // that's all folks - end of frame struct sk_buff * skb = dev->tx_skb; - dev->tx_iovec = 0; + dev->tx_iovec = NULL; // VC layer stats atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); @@ -1761,7 +1761,7 @@ static int hrz_send (struct atm_vcc * at if (tx_iovcnt) { // scatter gather transfer dev->tx_regions = tx_iovcnt; - dev->tx_iovec = 0; /* @@@ needs rewritten */ + dev->tx_iovec = NULL; /* @@@ needs rewritten */ dev->tx_bytes = 0; PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", skb->data, tx_len); @@ -1771,7 +1771,7 @@ static int hrz_send (struct atm_vcc * at } else { // simple transfer dev->tx_regions = 0; - dev->tx_iovec = 0; + dev->tx_iovec = NULL; dev->tx_bytes = tx_len; dev->tx_addr = skb->data; PRINTD (DBG_TX|DBG_BUS, "TX start simple transfer (addr %p, len %d)", @@ -2278,7 +2278,7 @@ static int hrz_open (struct atm_vcc *atm // we take "the PCR" as a rate-cap // not reserved vcc.tx_rate = 0; - make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, 0); + make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, NULL); vcc.tx_xbr_bits = ABR_RATE_TYPE; break; } @@ -2583,7 +2583,7 @@ static void hrz_close (struct atm_vcc * PRINTK (KERN_ERR, "%s atm_vcc=%p rxer[channel]=%p", "arghhh! we're going to die!", atm_vcc, dev->rxer[channel]); - dev->rxer[channel] = 0; + dev->rxer[channel] = NULL; } // atomically release our rate reservation @@ -2806,8 +2806,8 @@ static int __init hrz_probe (void) { dev->tx_regions = 0; dev->tx_bytes = 0; - dev->tx_skb = 0; - dev->tx_iovec = 0; + dev->tx_skb = NULL; + dev->tx_iovec = NULL; dev->tx_cell_count = 0; dev->rx_cell_count = 0; --- linux-2.6.8-rc1/drivers/atm/idt77252.c 2004-04-03 20:39:12.000000000 -0800 +++ 25/drivers/atm/idt77252.c 2004-07-13 17:09:13.000000000 -0700 @@ -3729,7 +3729,7 @@ idt77252_init_one(struct pci_dev *pcidev return -EIO; } - dev = atm_dev_register("idt77252", &idt77252_ops, -1, 0); + dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL); if (!dev) { printk("%s: can't register atm device\n", card->name); iounmap((void *) card->membase); --- linux-2.6.8-rc1/drivers/atm/iphase.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/iphase.c 2004-07-13 17:09:13.000000000 -0700 @@ -2667,7 +2667,7 @@ static void ia_close(struct atm_vcc *vcc } // Drain the packets rx_dle_intr(vcc->dev); - iadev->rx_open[vcc->vci] = 0; + iadev->rx_open[vcc->vci] = NULL; } kfree(INPH_IA_VCC(vcc)); ia_vcc = NULL; --- linux-2.6.8-rc1/drivers/atm/iphase.h 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/iphase.h 2004-07-13 17:09:54.000000000 -0700 @@ -68,8 +68,6 @@ #define IF_IADBG_SUNI_STAT 0x02000000 // suni statistics #define IF_IADBG_RESET 0x04000000 -extern unsigned int IADebugFlag; - #define IF_IADBG(f) if (IADebugFlag & (f)) #ifdef CONFIG_ATM_IA_DEBUG /* Debug build */ --- linux-2.6.8-rc1/drivers/atm/lanai.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/atm/lanai.c 2004-07-13 17:09:13.000000000 -0700 @@ -2702,7 +2702,7 @@ static int __devinit lanai_init_one(stru return -ENOMEM; } - atmdev = atm_dev_register(DEV_LABEL, &ops, -1, 0); + atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); if (atmdev == NULL) { printk(KERN_ERR DEV_LABEL ": couldn't register atm device!\n"); --- linux-2.6.8-rc1/drivers/base/bus.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/base/bus.c 2004-07-13 17:09:21.000000000 -0700 @@ -415,7 +415,7 @@ static int device_add_attrs(struct bus_t static void device_remove_attrs(struct bus_type * bus, struct device * dev) { int i; - + if (bus->dev_attrs) { for (i = 0; attr_name(bus->dev_attrs[i]); i++) device_remove_file(dev,&bus->dev_attrs[i]); @@ -471,6 +471,37 @@ void bus_remove_device(struct device * d } } +static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv) +{ + int error = 0; + int i; + + if (bus->drv_attrs) { + for (i = 0; attr_name(bus->drv_attrs[i]); i++) { + error = driver_create_file(drv, &bus->drv_attrs[i]); + if (error) + goto Err; + } + } + Done: + return error; + Err: + while (--i >= 0) + driver_remove_file(drv, &bus->drv_attrs[i]); + goto Done; +} + + +static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv) +{ + int i; + + if (bus->drv_attrs) { + for (i = 0; attr_name(bus->drv_attrs[i]); i++) + driver_remove_file(drv, &bus->drv_attrs[i]); + } +} + /** * bus_add_driver - Add a driver to the bus. @@ -499,6 +530,7 @@ int bus_add_driver(struct device_driver driver_attach(drv); up_write(&bus->subsys.rwsem); + driver_add_attrs(bus, drv); } return error; } @@ -516,6 +548,7 @@ int bus_add_driver(struct device_driver void bus_remove_driver(struct device_driver * drv) { if (drv->bus) { + driver_remove_attrs(drv->bus, drv); down_write(&drv->bus->subsys.rwsem); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); @@ -574,6 +607,8 @@ void put_bus(struct bus_type * bus) * * Call kset_find_obj() to iterate over list of buses to * find a bus by name. Return bus if found. + * + * Note that kset_find_obj increments bus' reference count. */ struct bus_type * find_bus(char * name) @@ -610,7 +645,7 @@ static int bus_add_attrs(struct bus_type static void bus_remove_attrs(struct bus_type * bus) { int i; - + if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) bus_remove_file(bus,&bus->bus_attrs[i]); --- linux-2.6.8-rc1/drivers/base/core.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/base/core.c 2004-07-13 17:09:21.000000000 -0700 @@ -378,6 +378,16 @@ int device_for_each_child(struct device return error; } +/** + * device_find - locate device on a bus by name. + * @name: name of the device. + * @bus: bus to scan for the device. + * + * Call kset_find_obj() to iterate over list of devices on + * a bus to find device by name. Return device if found. + * + * Note that kset_find_obj increments device's reference count. + */ struct device *device_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(&bus->devices, name); --- linux-2.6.8-rc1/drivers/base/driver.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/base/driver.c 2004-07-13 17:09:21.000000000 -0700 @@ -111,10 +111,29 @@ void driver_unregister(struct device_dri up(&drv->unload_sem); } +/** + * driver_find - locate driver on a bus by its name. + * @name: name of the driver. + * @bus: bus to scan for the driver. + * + * Call kset_find_obj() to iterate over list of drivers on + * a bus to find driver by name. Return driver if found. + * + * Note that kset_find_obj increments driver's reference count. + */ +struct device_driver *driver_find(const char *name, struct bus_type *bus) +{ + struct kobject *k = kset_find_obj(&bus->drivers, name); + if (k) + return to_drv(k); + return NULL; +} + EXPORT_SYMBOL(driver_register); EXPORT_SYMBOL(driver_unregister); EXPORT_SYMBOL(get_driver); EXPORT_SYMBOL(put_driver); +EXPORT_SYMBOL(driver_find); EXPORT_SYMBOL(driver_create_file); EXPORT_SYMBOL(driver_remove_file); --- linux-2.6.8-rc1/drivers/base/Kconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/base/Kconfig 2004-07-13 17:09:21.000000000 -0700 @@ -18,7 +18,7 @@ config FW_LOADER the kernel tree does. config DEBUG_DRIVER - bool "Driver Core verbose debug messages" + bool "Driver Core verbose debug messages" depends on DEBUG_KERNEL help Say Y here if you want the Driver core to produce a bunch of --- linux-2.6.8-rc1/drivers/base/platform.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/base/platform.c 2004-07-13 17:35:08.000000000 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include struct device platform_bus = { .bus_id = "platform", @@ -133,19 +134,85 @@ int platform_device_register(struct plat return ret; } +/** + * platform_device_unregister - remove a platform-level device + * @dev: platform device we're removing + * + * Note that this function will also release all memory- and port-based + * resources owned by the device (@dev->resource). + */ void platform_device_unregister(struct platform_device * pdev) { int i; if (pdev) { - device_unregister(&pdev->dev); - for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO)) release_resource(r); } + + device_unregister(&pdev->dev); + } +} + +struct platform_object { + struct platform_device pdev; + struct resource resources[0]; +}; + +static void platform_device_release_simple(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + kfree(container_of(pdev, struct platform_object, pdev)); +} + +/** + * platform_device_register_simple + * @name: base name of the device we're adding + * @id: instance id + * @res: set of resources that needs to be allocated for the device + * @num: number of resources + * + * This function creates a simple platform device that requires minimal + * resource and memory management. Canned release function freeing + * memory allocated for the device allows drivers using such devices + * to be unloaded iwithout waiting for the last reference to the device + * to be dropped. + */ +struct platform_device *platform_device_register_simple(char *name, unsigned int id, + struct resource *res, unsigned int num) +{ + struct platform_object *pobj; + int retval; + + pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL); + if (!pobj) { + retval = -ENOMEM; + goto error; } + + memset(pobj, 0, sizeof(*pobj)); + pobj->pdev.name = name; + pobj->pdev.id = id; + pobj->pdev.dev.release = platform_device_release_simple; + + if (num) { + memcpy(pobj->resources, res, sizeof(struct resource) * num); + pobj->pdev.resource = pobj->resources; + pobj->pdev.num_resources = num; + } + + retval = platform_device_register(&pobj->pdev); + if (retval) + goto error; + + return &pobj->pdev; + +error: + kfree(pobj); + return ERR_PTR(retval); } @@ -237,6 +304,7 @@ EXPORT_SYMBOL(dma_get_required_mask); EXPORT_SYMBOL(platform_bus); EXPORT_SYMBOL(platform_bus_type); EXPORT_SYMBOL(platform_device_register); +EXPORT_SYMBOL(platform_device_register_simple); EXPORT_SYMBOL(platform_device_unregister); EXPORT_SYMBOL(platform_get_irq); EXPORT_SYMBOL(platform_get_resource); --- linux-2.6.8-rc1/drivers/block/cryptoloop.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/block/cryptoloop.c 2004-07-13 17:09:13.000000000 -0700 @@ -93,8 +93,8 @@ cryptoloop_transfer_ecb(struct loop_devi int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; - struct scatterlist sg_out = { 0, }; - struct scatterlist sg_in = { 0, }; + struct scatterlist sg_out = { NULL, }; + struct scatterlist sg_in = { NULL, }; encdec_ecb_t encdecfunc; struct page *in_page, *out_page; @@ -147,8 +147,8 @@ cryptoloop_transfer_cbc(struct loop_devi int size, sector_t IV) { struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data; - struct scatterlist sg_out = { 0, }; - struct scatterlist sg_in = { 0, }; + struct scatterlist sg_out = { NULL, }; + struct scatterlist sg_in = { NULL, }; encdec_cbc_t encdecfunc; struct page *in_page, *out_page; --- linux-2.6.8-rc1/drivers/block/floppy.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/block/floppy.c 2004-07-13 17:35:09.000000000 -0700 @@ -4228,7 +4228,6 @@ int __init floppy_init(void) int err, dr; raw_cmd = NULL; - i = 0; for (dr = 0; dr < N_DRIVE; dr++) { disks[dr] = alloc_disk(1); --- linux-2.6.8-rc1/drivers/block/Kconfig 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/block/Kconfig 2004-07-13 17:09:42.000000000 -0700 @@ -340,6 +340,39 @@ config LBD your machine, or if you want to have a raid or loopback device bigger than 2TB. Otherwise say N. +config CDROM_PKTCDVD + tristate "Packet writing on CD/DVD media" + help + If you have a CDROM drive that supports packet writing, say Y to + include preliminary support. It should work with any MMC/Mt Fuji + compliant ATAPI or SCSI drive, which is just about any newer CD + writer. + + Currently only writing to CD-RW, DVD-RW and DVD+RW discs is possible. + DVD-RW disks must be in restricted overwrite mode. + + To compile this driver as a module, choose M here: the + module will be called pktcdvd. + +config CDROM_PKTCDVD_BUFFERS + int "Free buffers for data gathering" + depends on CDROM_PKTCDVD + default "8" + help + This controls the maximum number of active concurrent packets. More + concurrent packets can increase write performance, but also require + more memory. Each concurrent packet will require approximately 64Kb + of non-swappable kernel memory, memory which will be allocated at + pktsetup time. + +config CDROM_PKTCDVD_WCACHE + bool "Enable write caching" + depends on CDROM_PKTCDVD + help + If enabled, write caching will be set for the CD-R/W device. For now + this option is dangerous unless the CD-RW media is known good, as we + don't do deferred write error handling yet. + source "drivers/s390/block/Kconfig" endmenu --- linux-2.6.8-rc1/drivers/block/ll_rw_blk.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/block/ll_rw_blk.c 2004-07-13 17:09:51.000000000 -0700 @@ -263,6 +263,45 @@ void blk_queue_make_request(request_queu EXPORT_SYMBOL(blk_queue_make_request); /** + * blk_queue_ordered - does this queue support ordered writes + * @q: the request queue + * @flag: see below + * + * Description: + * For journalled file systems, doing ordered writes on a commit + * block instead of explicitly doing wait_on_buffer (which is bad + * for performance) can be a big win. Block drivers supporting this + * feature should call this function and indicate so. + * + **/ +void blk_queue_ordered(request_queue_t *q, int flag) +{ + if (flag) + set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); + else + clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); +} + +EXPORT_SYMBOL(blk_queue_ordered); + +/** + * blk_queue_issue_flush_fn - set function for issuing a flush + * @q: the request queue + * @iff: the function to be called issuing the flush + * + * Description: + * If a driver supports issuing a flush command, the support is notified + * to the block layer by defining it through this call. + * + **/ +void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff) +{ + q->issue_flush_fn = iff; +} + +EXPORT_SYMBOL(blk_queue_issue_flush_fn); + +/** * blk_queue_bounce_limit - set bounce buffer limit for queue * @q: the request queue for the device * @dma_addr: bus address limit @@ -1205,6 +1244,7 @@ EXPORT_SYMBOL(__generic_unplug_device); **/ void generic_unplug_device(request_queue_t *q) { + might_sleep(); spin_lock_irq(q->queue_lock); __generic_unplug_device(q); spin_unlock_irq(q->queue_lock); @@ -1817,50 +1857,43 @@ EXPORT_SYMBOL(blk_insert_request); struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, unsigned int len) { - struct request *rq = NULL; - char *buf = NULL; + unsigned long uaddr; + struct request *rq; struct bio *bio; - int ret; + + if (len > (q->max_sectors << 9)) + return ERR_PTR(-EINVAL); + if ((!len && ubuf) || (len && !ubuf)) + return ERR_PTR(-EINVAL); rq = blk_get_request(q, rw, __GFP_WAIT); if (!rq) return ERR_PTR(-ENOMEM); - bio = bio_map_user(q, NULL, (unsigned long) ubuf, len, rw == READ); - if (!bio) { - int bytes = (len + 511) & ~511; - - buf = kmalloc(bytes, q->bounce_gfp | GFP_USER); - if (!buf) { - ret = -ENOMEM; - goto fault; - } - - if (rw == WRITE) { - if (copy_from_user(buf, ubuf, len)) { - ret = -EFAULT; - goto fault; - } - } else - memset(buf, 0, len); - } + /* + * if alignment requirement is satisfied, map in user pages for + * direct dma. else, set up kernel bounce buffers + */ + uaddr = (unsigned long) ubuf; + if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) + bio = bio_map_user(q, NULL, uaddr, len, rw == READ); + else + bio = bio_copy_user(q, uaddr, len, rw == READ); - rq->bio = rq->biotail = bio; - if (rq->bio) + if (!IS_ERR(bio)) { + rq->bio = rq->biotail = bio; blk_rq_bio_prep(q, rq, bio); - rq->buffer = rq->data = buf; - rq->data_len = len; - return rq; -fault: - if (buf) - kfree(buf); - if (bio) - bio_unmap_user(bio, 1); - if (rq) - blk_put_request(rq); + rq->buffer = rq->data = NULL; + rq->data_len = len; + return rq; + } - return ERR_PTR(ret); + /* + * bio is the err-ptr + */ + blk_put_request(rq); + return (struct request *) bio; } EXPORT_SYMBOL(blk_rq_map_user); @@ -1874,18 +1907,15 @@ EXPORT_SYMBOL(blk_rq_map_user); * Description: * Unmap a request previously mapped by blk_rq_map_user(). */ -int blk_rq_unmap_user(struct request *rq, void __user *ubuf, struct bio *bio, - unsigned int ulen) +int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) { - const int read = rq_data_dir(rq) == READ; int ret = 0; - if (bio) - bio_unmap_user(bio, read); - if (rq->buffer) { - if (read && copy_to_user(ubuf, rq->buffer, ulen)) - ret = -EFAULT; - kfree(rq->buffer); + if (bio) { + if (bio_flagged(bio, BIO_USER_MAPPED)) + bio_unmap_user(bio); + else + ret = bio_uncopy_user(bio); } blk_put_request(rq); @@ -1926,10 +1956,11 @@ int blk_execute_rq(request_queue_t *q, s } rq->flags |= REQ_NOMERGE; - rq->waiting = &wait; + if (!rq->waiting) + rq->waiting = &wait; elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); generic_unplug_device(q); - wait_for_completion(&wait); + wait_for_completion(rq->waiting); rq->waiting = NULL; if (rq->errors) @@ -1940,6 +1971,72 @@ int blk_execute_rq(request_queue_t *q, s EXPORT_SYMBOL(blk_execute_rq); +/** + * blkdev_issue_flush - queue a flush + * @bdev: blockdev to issue flush for + * @error_sector: error sector + * + * Description: + * Issue a flush for the block device in question. Caller can supply + * room for storing the error offset in case of a flush error, if they + * wish to. Caller must run wait_for_completion() on its own. + */ +int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) +{ + request_queue_t *q; + + if (bdev->bd_disk == NULL) + return -ENXIO; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + if (!q->issue_flush_fn) + return -EOPNOTSUPP; + + return q->issue_flush_fn(q, bdev->bd_disk, error_sector); +} + +EXPORT_SYMBOL(blkdev_issue_flush); + +/** + * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices + * @q: device queue + * @disk: gendisk + * @error_sector: error offset + * + * Description: + * Devices understanding the SCSI command set, can use this function as + * a helper for issuing a cache flush. Note: driver is required to store + * the error offset (in case of error flushing) in ->sector of struct + * request. + */ +int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT); + int ret; + + rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->sector = 0; + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = 0x35; + rq->cmd_len = 12; + rq->data = NULL; + rq->data_len = 0; + rq->timeout = 60 * HZ; + + ret = blk_execute_rq(q, disk, rq); + + if (ret && error_sector) + *error_sector = rq->sector; + + blk_put_request(rq); + return ret; +} + +EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn); + void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -2193,7 +2290,7 @@ EXPORT_SYMBOL(__blk_attempt_remerge); static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; sector_t sector; sector = bio->bi_sector; @@ -2211,9 +2308,11 @@ static int __make_request(request_queue_ spin_lock_prefetch(q->queue_lock); - barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); - - ra = bio->bi_rw & (1 << BIO_RW_AHEAD); + barrier = bio_barrier(bio); + if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) { + err = -EOPNOTSUPP; + goto end_io; + } again: spin_lock_irq(q->queue_lock); @@ -2293,7 +2392,8 @@ get_rq: /* * READA bit set */ - if (ra) + err = -EWOULDBLOCK; + if (bio_rw_ahead(bio)) goto end_io; freereq = get_request_wait(q, rw); @@ -2304,10 +2404,9 @@ get_rq: req->flags |= REQ_CMD; /* - * inherit FAILFAST from bio and don't stack up - * retries for read ahead + * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ - if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw)) + if (bio_rw_ahead(bio) || bio_failfast(bio)) req->flags |= REQ_FAILFAST; /* @@ -2341,7 +2440,7 @@ out: return 0; end_io: - bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); + bio_endio(bio, nr_sectors << 9, err); return 0; } @@ -2400,6 +2499,7 @@ void generic_make_request(struct bio *bi sector_t maxsector; int ret, nr_sectors = bio_sectors(bio); + might_sleep(); /* Test device or partition size, when known. */ maxsector = bio->bi_bdev->bd_inode->i_size >> 9; if (maxsector) { @@ -2648,10 +2748,17 @@ void blk_recalc_rq_sectors(struct reques static int __end_that_request_first(struct request *req, int uptodate, int nr_bytes) { - int total_bytes, bio_nbytes, error = 0, next_idx = 0; + int total_bytes, bio_nbytes, error, next_idx = 0; struct bio *bio; /* + * extend uptodate bool to allow < 0 value to be direct io error + */ + error = 0; + if (end_io_error(uptodate)) + error = !uptodate ? -EIO : uptodate; + + /* * for a REQ_BLOCK_PC request, we want to carry any eventual * sense key with us all the way through */ @@ -2659,7 +2766,6 @@ static int __end_that_request_first(stru req->errors = 0; if (!uptodate) { - error = -EIO; if (blk_fs_request(req) && !(req->flags & REQ_QUIET)) printk("end_request: I/O error, dev %s, sector %llu\n", req->rq_disk ? req->rq_disk->disk_name : "?", @@ -2742,7 +2848,7 @@ static int __end_that_request_first(stru /** * end_that_request_first - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_sectors: number of sectors to end I/O on * * Description: @@ -2763,7 +2869,7 @@ EXPORT_SYMBOL(end_that_request_first); /** * end_that_request_chunk - end I/O on a request * @req: the request being processed - * @uptodate: 0 for I/O error + * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error * @nr_bytes: number of bytes to complete * * Description: --- linux-2.6.8-rc1/drivers/block/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/block/Makefile 2004-07-13 17:09:41.000000000 -0700 @@ -35,6 +35,7 @@ obj-$(CONFIG_BLK_DEV_XD) += xd.o obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o +obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o --- linux-2.6.8-rc1/drivers/block/paride/paride.c 2004-02-17 20:48:42.000000000 -0800 +++ 25/drivers/block/paride/paride.c 2004-07-13 17:09:13.000000000 -0700 @@ -264,7 +264,7 @@ void pi_unregister(PIP * pr) printk("paride: %s not registered\n", pr->name); return; } - protocols[pr->index] = 0; + protocols[pr->index] = NULL; } EXPORT_SYMBOL(pi_unregister); --- linux-2.6.8-rc1/drivers/block/paride/pcd.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/block/paride/pcd.c 2004-07-13 17:09:13.000000000 -0700 @@ -752,7 +752,7 @@ static void do_pcd_request(request_queue pcd_count = pcd_req->current_nr_sectors; pcd_buf = pcd_req->buffer; pcd_busy = 1; - ps_set_intr(do_pcd_read, 0, 0, nice); + ps_set_intr(do_pcd_read, NULL, 0, nice); return; } else end_request(pcd_req, 0); --- linux-2.6.8-rc1/drivers/block/paride/pf.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/block/paride/pf.c 2004-07-13 17:09:13.000000000 -0700 @@ -841,7 +841,7 @@ static inline void next_request(int succ /* detach from the calling context - in case the spinlock is held */ static void do_pf_read(void) { - ps_set_intr(do_pf_read_start, 0, 0, nice); + ps_set_intr(do_pf_read_start, NULL, 0, nice); } static void do_pf_read_start(void) @@ -887,7 +887,7 @@ static void do_pf_read_drq(void) static void do_pf_write(void) { - ps_set_intr(do_pf_write_start, 0, 0, nice); + ps_set_intr(do_pf_write_start, NULL, 0, nice); } static void do_pf_write_start(void) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/block/pktcdvd.c 2004-07-13 17:09:42.000000000 -0700 @@ -0,0 +1,2632 @@ +/* + * Copyright (C) 2000 Jens Axboe + * Copyright (C) 2001-2004 Peter Osterlund + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices (aka an exercise in block layer masturbation) + * + * + * TODO: (circa order of when I will fix it) + * - Only able to write on CD-RW media right now. + * - check host application code on media and set it in write page + * - interface for UDF <-> packet to negotiate a new location when a write + * fails. + * - handle OPC, especially for -RW media + * + * Theory of operation: + * + * We use a custom make_request_fn function that forwards reads directly to + * the underlying CD device. Write requests are either attached directly to + * a live packet_data object, or simply stored sequentially in a list for + * later processing by the kcdrwd kernel thread. This driver doesn't use + * any elevator functionally as defined by the elevator_s struct, but the + * underlying CD device uses a standard elevator. + * + * This strategy makes it possible to do very late merging of IO requests. + * A new bio sent to pkt_make_request can be merged with a live packet_data + * object even if the object is in the data gathering state. + * + *************************************************************************/ + +#define VERSION_CODE "v0.1.6a 2004-07-01 Jens Axboe (axboe@suse.de) and petero2@telia.com" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for invalidate_bdev() */ +#include +#include +#include +#include + +#include + +#define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1)) + +static struct pktcdvd_device *pkt_devs; +static struct proc_dir_entry *pkt_proc; + +static struct pktcdvd_device *pkt_find_dev(request_queue_t *q) +{ + int i; + + for (i = 0; i < MAX_WRITERS; i++) + if (pkt_devs[i].bdev && bdev_get_queue(pkt_devs[i].bdev) == q) + return &pkt_devs[i]; + + return NULL; +} + +/* + * The underlying block device is not allowed to merge write requests. Some + * CDRW drives can not handle writes larger than one packet, even if the size + * is a multiple of the packet size. + */ +static int pkt_lowlevel_elv_merge_fn(request_queue_t *q, struct request **req, struct bio *bio) +{ + struct pktcdvd_device *pd = pkt_find_dev(q); + BUG_ON(!pd); + + if (bio_data_dir(bio) == WRITE) + return ELEVATOR_NO_MERGE; + + if (pd->cdrw.elv_merge_fn) + return pd->cdrw.elv_merge_fn(q, req, bio); + + return ELEVATOR_NO_MERGE; +} + +static void pkt_lowlevel_elv_completed_req_fn(request_queue_t *q, struct request *req) +{ + struct pktcdvd_device *pd = pkt_find_dev(q); + BUG_ON(!pd); + + if (elv_queue_empty(q)) { + VPRINTK("pktcdvd: queue empty\n"); + atomic_set(&pd->iosched.attention, 1); + wake_up(&pd->wqueue); + } + + if (pd->cdrw.elv_completed_req_fn) + pd->cdrw.elv_completed_req_fn(q, req); +} + +static int pkt_lowlevel_merge_requests_fn(request_queue_t *q, struct request *rq, struct request *next) +{ + struct pktcdvd_device *pd = pkt_find_dev(q); + BUG_ON(!pd); + + if (rq_data_dir(rq) == WRITE) + return 0; + + return pd->cdrw.merge_requests_fn(q, rq, next); +} + +static void pkt_bio_init(struct bio *bio) +{ + bio->bi_next = NULL; + bio->bi_flags = 1 << BIO_UPTODATE; + bio->bi_rw = 0; + bio->bi_vcnt = 0; + bio->bi_idx = 0; + bio->bi_phys_segments = 0; + bio->bi_hw_segments = 0; + bio->bi_size = 0; + bio->bi_max_vecs = 0; + bio->bi_end_io = NULL; + atomic_set(&bio->bi_cnt, 1); + bio->bi_private = NULL; +} + +static void pkt_bio_destructor(struct bio *bio) +{ + kfree(bio->bi_io_vec); + kfree(bio); +} + +static struct bio *pkt_bio_alloc(int nr_iovecs) +{ + struct bio_vec *bvl = NULL; + struct bio *bio; + + bio = kmalloc(sizeof(struct bio), GFP_KERNEL); + if (!bio) + goto no_bio; + pkt_bio_init(bio); + + bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL); + if (!bvl) + goto no_bvl; + memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec)); + + bio->bi_max_vecs = nr_iovecs; + bio->bi_io_vec = bvl; + bio->bi_destructor = pkt_bio_destructor; + + return bio; + + no_bvl: + kfree(bio); + no_bio: + return NULL; +} + +/* + * Allocate a packet_data struct + */ +static struct packet_data *pkt_alloc_packet_data(void) +{ + int i; + struct packet_data *pkt; + + pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL); + if (!pkt) + goto no_pkt; + memset(pkt, 0, sizeof(struct packet_data)); + + pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE); + if (!pkt->w_bio) + goto no_bio; + + for (i = 0; i < PAGES_PER_PACKET; i++) { + pkt->pages[i] = alloc_page(GFP_KERNEL); + if (!pkt->pages[i]) + goto no_page; + } + for (i = 0; i < PAGES_PER_PACKET; i++) + clear_page(page_address(pkt->pages[i])); + + spin_lock_init(&pkt->lock); + + for (i = 0; i < PACKET_MAX_SIZE; i++) { + struct bio *bio = pkt_bio_alloc(1); + if (!bio) + goto no_rd_bio; + pkt->r_bios[i] = bio; + } + + return pkt; + +no_rd_bio: + for (i = 0; i < PACKET_MAX_SIZE; i++) { + struct bio *bio = pkt->r_bios[i]; + if (bio) + bio_put(bio); + } + +no_page: + for (i = 0; i < PAGES_PER_PACKET; i++) + if (pkt->pages[i]) + __free_page(pkt->pages[i]); + bio_put(pkt->w_bio); +no_bio: + kfree(pkt); +no_pkt: + return NULL; +} + +/* + * Free a packet_data struct + */ +static void pkt_free_packet_data(struct packet_data *pkt) +{ + int i; + + for (i = 0; i < PACKET_MAX_SIZE; i++) { + struct bio *bio = pkt->r_bios[i]; + if (bio) + bio_put(bio); + } + for (i = 0; i < PAGES_PER_PACKET; i++) + __free_page(pkt->pages[i]); + bio_put(pkt->w_bio); + kfree(pkt); +} + +static void pkt_shrink_pktlist(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *next; + + BUG_ON(!list_empty(&pd->cdrw.pkt_active_list)); + + list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) { + pkt_free_packet_data(pkt); + } +} + +static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets) +{ + struct packet_data *pkt; + + INIT_LIST_HEAD(&pd->cdrw.pkt_free_list); + INIT_LIST_HEAD(&pd->cdrw.pkt_active_list); + spin_lock_init(&pd->cdrw.active_list_lock); + while (nr_packets > 0) { + pkt = pkt_alloc_packet_data(); + if (!pkt) { + pkt_shrink_pktlist(pd); + return 0; + } + pkt->id = nr_packets; + pkt->pd = pd; + list_add(&pkt->list, &pd->cdrw.pkt_free_list); + nr_packets--; + } + return 1; +} + +/* + * Add a bio to a single linked list defined by its head and tail pointers. + */ +static inline void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail) +{ + bio->bi_next = NULL; + if (*list_tail) { + BUG_ON((*list_head) == NULL); + (*list_tail)->bi_next = bio; + (*list_tail) = bio; + } else { + BUG_ON((*list_head) != NULL); + (*list_head) = bio; + (*list_tail) = bio; + } +} + +/* + * Remove and return the first bio from a single linked list defined by its + * head and tail pointers. + */ +static inline struct bio *pkt_get_list_first(struct bio **list_head, struct bio **list_tail) +{ + struct bio *bio; + + if (*list_head == NULL) + return NULL; + + bio = *list_head; + *list_head = bio->bi_next; + if (*list_head == NULL) + *list_tail = NULL; + + bio->bi_next = NULL; + return bio; +} + +/* + * Send a packet_command to the underlying block device and + * wait for completion. + */ +static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc) +{ + char sense[SCSI_SENSE_BUFFERSIZE]; + request_queue_t *q; + struct request *rq; + DECLARE_COMPLETION(wait); + int err = 0; + + if (!pd->bdev) { + printk("pkt_generic_packet: no bdev\n"); + return -ENXIO; + } + + q = bdev_get_queue(pd->bdev); + + rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, + __GFP_WAIT); + rq->errors = 0; + rq->rq_disk = pd->bdev->bd_disk; + rq->bio = NULL; + rq->buffer = NULL; + rq->timeout = 60*HZ; + rq->data = cgc->buffer; + rq->data_len = cgc->buflen; + rq->sense = sense; + memset(sense, 0, sizeof(sense)); + rq->sense_len = 0; + rq->flags |= REQ_BLOCK_PC | REQ_HARDBARRIER; + if (cgc->quiet) + rq->flags |= REQ_QUIET; + memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); + if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) + memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); + + rq->ref_count++; + rq->flags |= REQ_NOMERGE; + rq->waiting = &wait; + elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); + generic_unplug_device(q); + wait_for_completion(&wait); + + if (rq->errors) + err = -EIO; + + blk_put_request(rq); + return err; +} + +/* + * A generic sense dump / resolve mechanism should be implemented across + * all ATAPI + SCSI devices. + */ +static void pkt_dump_sense(struct packet_command *cgc) +{ + static char *info[9] = { "No sense", "Recovered error", "Not ready", + "Medium error", "Hardware error", "Illegal request", + "Unit attention", "Data protect", "Blank check" }; + int i; + struct request_sense *sense = cgc->sense; + + printk("pktcdvd:"); + for (i = 0; i < CDROM_PACKET_SIZE; i++) + printk(" %02x", cgc->cmd[i]); + printk(" - "); + + if (sense == NULL) { + printk("no sense\n"); + return; + } + + printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq); + + if (sense->sense_key > 8) { + printk(" (INVALID)\n"); + return; + } + + printk(" (%s)\n", info[sense->sense_key]); +} + +/* + * flush the drive cache to media + */ +static int pkt_flush_cache(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.quiet = 1; + + /* + * the IMMED bit -- we default to not setting it, although that + * would allow a much faster close, this is safer + */ +#if 0 + cgc.cmd[1] = 1 << 1; +#endif + return pkt_generic_packet(pd, &cgc); +} + +/* + * speed is given as the normal factor, e.g. 4 for 4x + */ +static int pkt_set_speed(struct pktcdvd_device *pd, unsigned write_speed, unsigned read_speed) +{ + struct packet_command cgc; + struct request_sense sense; + int ret; + + write_speed = write_speed * 177; /* should be 176.4, but CD-RWs rounds down */ + write_speed = min_t(unsigned, write_speed, 0xffff); + read_speed = read_speed * 177; + read_speed = min_t(unsigned, read_speed, 0xffff); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_SET_SPEED; + cgc.cmd[2] = (read_speed >> 8) & 0xff; + cgc.cmd[3] = read_speed & 0xff; + cgc.cmd[4] = (write_speed >> 8) & 0xff; + cgc.cmd[5] = write_speed & 0xff; + + if ((ret = pkt_generic_packet(pd, &cgc))) + pkt_dump_sense(&cgc); + + return ret; +} + +/* + * Queue a bio for processing by the low-level CD device. Must be called + * from process context. + */ +static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio, int high_prio_read) +{ + spin_lock(&pd->iosched.lock); + if (bio_data_dir(bio) == READ) { + pkt_add_list_last(bio, &pd->iosched.read_queue, + &pd->iosched.read_queue_tail); + if (high_prio_read) + pd->iosched.high_prio_read = 1; + } else { + pkt_add_list_last(bio, &pd->iosched.write_queue, + &pd->iosched.write_queue_tail); + } + spin_unlock(&pd->iosched.lock); + + atomic_set(&pd->iosched.attention, 1); + wake_up(&pd->wqueue); +} + +/* + * Process the queued read/write requests. This function handles special + * requirements for CDRW drives: + * - A cache flush command must be inserted before a read request if the + * previous request was a write. + * - Switching between reading and writing is slow, so don't it more often + * than necessary. + * - Set the read speed according to current usage pattern. When only reading + * from the device, it's best to use the highest possible read speed, but + * when switching often between reading and writing, it's better to have the + * same read and write speeds. + * - Reads originating from user space should have higher priority than reads + * originating from pkt_gather_data, because some process is usually waiting + * on reads of the first kind. + */ +static void pkt_iosched_process_queue(struct pktcdvd_device *pd) +{ + request_queue_t *q; + + if (atomic_read(&pd->iosched.attention) == 0) + return; + atomic_set(&pd->iosched.attention, 0); + + if (!pd->bdev) + return; + q = bdev_get_queue(pd->bdev); + + for (;;) { + struct bio *bio; + int reads_queued, writes_queued, high_prio_read; + + spin_lock(&pd->iosched.lock); + reads_queued = (pd->iosched.read_queue != NULL); + writes_queued = (pd->iosched.write_queue != NULL); + if (!reads_queued) + pd->iosched.high_prio_read = 0; + high_prio_read = pd->iosched.high_prio_read; + spin_unlock(&pd->iosched.lock); + + if (!reads_queued && !writes_queued) + break; + + if (pd->iosched.writing) { + if (high_prio_read || (!writes_queued && reads_queued)) { + if (!elv_queue_empty(q)) { + VPRINTK("pktcdvd: write, waiting\n"); + break; + } + pkt_flush_cache(pd); + pd->iosched.writing = 0; + } + } else { + if (!reads_queued && writes_queued) { + if (!elv_queue_empty(q)) { + VPRINTK("pktcdvd: read, waiting\n"); + break; + } + pd->iosched.writing = 1; + } + } + + spin_lock(&pd->iosched.lock); + if (pd->iosched.writing) { + bio = pkt_get_list_first(&pd->iosched.write_queue, + &pd->iosched.write_queue_tail); + } else { + bio = pkt_get_list_first(&pd->iosched.read_queue, + &pd->iosched.read_queue_tail); + } + spin_unlock(&pd->iosched.lock); + + if (!bio) + continue; + + if (bio_data_dir(bio) == READ) + pd->iosched.successive_reads += bio->bi_size >> 10; + else + pd->iosched.successive_reads = 0; + if (pd->iosched.successive_reads >= HI_SPEED_SWITCH) { + if (pd->read_speed == pd->write_speed) { + pd->read_speed = 0xff; + pkt_set_speed(pd, pd->write_speed, pd->read_speed); + } + } else { + if (pd->read_speed != pd->write_speed) { + pd->read_speed = pd->write_speed; + pkt_set_speed(pd, pd->write_speed, pd->read_speed); + } + } + + generic_make_request(bio); + } +} + +/* + * Special care is needed if the underlying block device has a small + * max_phys_segments value. + */ +static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q) +{ + if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) { + /* + * The cdrom device can handle one segment/frame + */ + clear_bit(PACKET_MERGE_SEGS, &pd->flags); + return 0; + } else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) { + /* + * We can handle this case at the expense of some extra memory + * copies during write operations + */ + set_bit(PACKET_MERGE_SEGS, &pd->flags); + return 0; + } else { + printk("pktcdvd: cdrom max_phys_segments too small\n"); + return -EIO; + } +} + +/* + * Copy CD_FRAMESIZE bytes from src_bio into a destination page + */ +static void pkt_copy_bio_data(struct bio *src_bio, int seg, int offs, + struct page *dst_page, int dst_offs) +{ + unsigned int copy_size = CD_FRAMESIZE; + + while (copy_size > 0) { + struct bio_vec *src_bvl = bio_iovec_idx(src_bio, seg); + void *vfrom = kmap_atomic(src_bvl->bv_page, KM_USER0) + + src_bvl->bv_offset + offs; + void *vto = page_address(dst_page) + dst_offs; + int len = min_t(int, copy_size, src_bvl->bv_len - offs); + + BUG_ON(len < 0); + memcpy(vto, vfrom, len); + kunmap_atomic(src_bvl->bv_page, KM_USER0); + + seg++; + offs = 0; + dst_offs += len; + copy_size -= len; + } +} + +/* + * Copy all data for this packet to pkt->pages[], so that + * a) The number of required segments for the write bio is minimized, which + * is necessary for some scsi controllers. + * b) The data can be used as cache to avoid read requests if we receive a + * new write request for the same zone. + */ +static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, int *offsets) +{ + int f, p, offs; + + /* Copy all data to pkt->pages[] */ + p = 0; + offs = 0; + for (f = 0; f < pkt->frames; f++) { + if (pages[f] != pkt->pages[p]) { + void *vfrom = kmap_atomic(pages[f], KM_USER0) + offsets[f]; + void *vto = page_address(pkt->pages[p]) + offs; + memcpy(vto, vfrom, CD_FRAMESIZE); + kunmap_atomic(pages[f], KM_USER0); + pages[f] = pkt->pages[p]; + offsets[f] = offs; + } else { + BUG_ON(offsets[f] != offs); + } + offs += CD_FRAMESIZE; + if (offs >= PAGE_SIZE) { + BUG_ON(offs > PAGE_SIZE); + offs = 0; + p++; + } + } +} + +static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err) +{ + struct packet_data *pkt = bio->bi_private; + struct pktcdvd_device *pd = pkt->pd; + BUG_ON(!pd); + + if (bio->bi_size) + return 1; + + VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio, + (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err); + + if (err) + atomic_inc(&pkt->io_errors); + if (atomic_dec_and_test(&pkt->io_wait)) { + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); + } + + return 0; +} + +static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err) +{ + struct packet_data *pkt = bio->bi_private; + struct pktcdvd_device *pd = pkt->pd; + BUG_ON(!pd); + + if (bio->bi_size) + return 1; + + VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err); + + pd->stats.pkt_ended++; + + atomic_dec(&pkt->io_wait); + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); + return 0; +} + +/* + * Schedule reads for the holes in a packet + */ +static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + int frames_read = 0; + struct bio *bio; + int f; + char written[PACKET_MAX_SIZE]; + + BUG_ON(!pkt->orig_bios); + + atomic_set(&pkt->io_wait, 0); + atomic_set(&pkt->io_errors, 0); + + if (pkt->cache_valid) { + VPRINTK("pkt_gather_data: zone %llx cached\n", + (unsigned long long)pkt->sector); + goto out_account; + } + + /* + * Figure out which frames we need to read before we can write. + */ + memset(written, 0, sizeof(written)); + spin_lock(&pkt->lock); + for (bio = pkt->orig_bios; bio; bio = bio->bi_next) { + int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_size / CD_FRAMESIZE; + BUG_ON(first_frame < 0); + BUG_ON(first_frame + num_frames > pkt->frames); + for (f = first_frame; f < first_frame + num_frames; f++) + written[f] = 1; + } + spin_unlock(&pkt->lock); + + /* + * Schedule reads for missing parts of the packet. + */ + for (f = 0; f < pkt->frames; f++) { + int p, offset; + if (written[f]) + continue; + bio = pkt->r_bios[f]; + pkt_bio_init(bio); + bio->bi_max_vecs = 1; + bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); + bio->bi_bdev = pd->bdev; + bio->bi_end_io = pkt_end_io_read; + bio->bi_private = pkt; + + p = (f * CD_FRAMESIZE) / PAGE_SIZE; + offset = (f * CD_FRAMESIZE) % PAGE_SIZE; + VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d\n", + f, pkt->pages[p], offset); + if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset)) + BUG(); + + atomic_inc(&pkt->io_wait); + bio->bi_rw = READ; + pkt_queue_bio(pd, bio, 0); + frames_read++; + } + +out_account: + VPRINTK("pkt_gather_data: need %d frames for zone %llx\n", + frames_read, (unsigned long long)pkt->sector); + pd->stats.pkt_started++; + pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); + pd->stats.secs_w += pd->settings.size; +} + +/* + * Find a packet matching zone, or the least recently used packet if + * there is no match. + */ +static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zone) +{ + struct packet_data *pkt; + + list_for_each_entry(pkt, &pd->cdrw.pkt_free_list, list) { + if (pkt->sector == zone || pkt->list.next == &pd->cdrw.pkt_free_list) { + list_del_init(&pkt->list); + if (pkt->sector != zone) + pkt->cache_valid = 0; + break; + } + } + return pkt; +} + +static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + if (pkt->cache_valid) { + list_add(&pkt->list, &pd->cdrw.pkt_free_list); + } else { + list_add_tail(&pkt->list, &pd->cdrw.pkt_free_list); + } +} + +/* + * recover a failed write, query for relocation if possible + * + * returns 1 if recovery is possible, or 0 if not + * + */ +static int pkt_start_recovery(struct packet_data *pkt) +{ + /* + * FIXME. We need help from the file system to implement + * recovery handling. + */ + return 0; +#if 0 + struct request *rq = pkt->rq; + struct pktcdvd_device *pd = rq->rq_disk->private_data; + struct block_device *pkt_bdev; + struct super_block *sb = NULL; + unsigned long old_block, new_block; + sector_t new_sector; + + pkt_bdev = bdget(kdev_t_to_nr(pd->pkt_dev)); + if (pkt_bdev) { + sb = get_super(pkt_bdev); + bdput(pkt_bdev); + } + + if (!sb) + return 0; + + if (!sb->s_op || !sb->s_op->relocate_blocks) + goto out; + + old_block = pkt->sector / (CD_FRAMESIZE >> 9); + if (sb->s_op->relocate_blocks(sb, old_block, &new_block)) + goto out; + + new_sector = new_block * (CD_FRAMESIZE >> 9); + pkt->sector = new_sector; + + pkt->bio->bi_sector = new_sector; + pkt->bio->bi_next = NULL; + pkt->bio->bi_flags = 1 << BIO_UPTODATE; + pkt->bio->bi_idx = 0; + + BUG_ON(pkt->bio->bi_rw != (1 << BIO_RW)); + BUG_ON(pkt->bio->bi_vcnt != pkt->frames); + BUG_ON(pkt->bio->bi_size != pkt->frames * CD_FRAMESIZE); + BUG_ON(pkt->bio->bi_end_io != pkt_end_io_packet_write); + BUG_ON(pkt->bio->bi_private != pkt); + + drop_super(sb); + return 1; + +out: + drop_super(sb); + return 0; +#endif +} + +static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state state) +{ +#if PACKET_DEBUG > 1 + static const char *state_name[] = { + "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED" + }; + enum packet_data_state old_state = pkt->state; + VPRINTK("pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector, + state_name[old_state], state_name[state]); +#endif + pkt->state = state; +} + +/* + * Scan the work queue to see if we can start a new packet. + * returns non-zero if any work was done. + */ +static int pkt_handle_queue(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *p; + struct bio *bio, *prev, *next; + sector_t zone = 0; /* Suppress gcc warning */ + + VPRINTK("handle_queue\n"); + + atomic_set(&pd->scan_queue, 0); + + if (list_empty(&pd->cdrw.pkt_free_list)) { + VPRINTK("handle_queue: no pkt\n"); + return 0; + } + + /* + * Try to find a zone we are not already working on. + */ + spin_lock(&pd->lock); + for (bio = pd->bio_queue; bio; bio = bio->bi_next) { + zone = ZONE(bio->bi_sector, pd); + list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { + if (p->sector == zone) + goto try_next_bio; + } + break; +try_next_bio: ; + } + spin_unlock(&pd->lock); + if (!bio) { + VPRINTK("handle_queue: no bio\n"); + return 0; + } + + pkt = pkt_get_packet_data(pd, zone); + BUG_ON(!pkt); + + pkt->sector = zone; + pkt->frames = pd->settings.size >> 2; + BUG_ON(pkt->frames > PACKET_MAX_SIZE); + pkt->write_size = 0; + + /* + * Scan work queue for bios in the same zone and link them + * to this packet. + */ + spin_lock(&pd->lock); + prev = NULL; + VPRINTK("pkt_handle_queue: looking for zone %llx\n", (unsigned long long)zone); + bio = pd->bio_queue; + while (bio) { + VPRINTK("pkt_handle_queue: found zone=%llx\n", + (unsigned long long)ZONE(bio->bi_sector, pd)); + if (ZONE(bio->bi_sector, pd) == zone) { + if (prev) { + prev->bi_next = bio->bi_next; + } else { + pd->bio_queue = bio->bi_next; + } + if (bio == pd->bio_queue_tail) + pd->bio_queue_tail = prev; + next = bio->bi_next; + spin_lock(&pkt->lock); + pkt_add_list_last(bio, &pkt->orig_bios, + &pkt->orig_bios_tail); + pkt->write_size += bio->bi_size / CD_FRAMESIZE; + if (pkt->write_size >= pkt->frames) { + VPRINTK("pkt_handle_queue: pkt is full\n"); + next = NULL; /* Stop searching if the packet is full */ + } + spin_unlock(&pkt->lock); + bio = next; + } else { + prev = bio; + bio = bio->bi_next; + } + } + spin_unlock(&pd->lock); + + pkt->sleep_time = max(PACKET_WAIT_TIME, 1); + pkt_set_state(pkt, PACKET_WAITING_STATE); + atomic_set(&pkt->run_sm, 1); + + spin_lock(&pd->cdrw.active_list_lock); + list_add(&pkt->list, &pd->cdrw.pkt_active_list); + spin_unlock(&pd->cdrw.active_list_lock); + + return 1; +} + +/* + * Assemble a bio to write one packet and queue the bio for processing + * by the underlying block device. + */ +static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + struct bio *bio; + struct page *pages[PACKET_MAX_SIZE]; + int offsets[PACKET_MAX_SIZE]; + int f; + int frames_write; + + for (f = 0; f < pkt->frames; f++) { + pages[f] = pkt->pages[(f * CD_FRAMESIZE) / PAGE_SIZE]; + offsets[f] = (f * CD_FRAMESIZE) % PAGE_SIZE; + } + + /* + * Fill-in pages[] and offsets[] with data from orig_bios. + */ + frames_write = 0; + spin_lock(&pkt->lock); + for (bio = pkt->orig_bios; bio; bio = bio->bi_next) { + int segment = bio->bi_idx; + int src_offs = 0; + int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_size / CD_FRAMESIZE; + BUG_ON(first_frame < 0); + BUG_ON(first_frame + num_frames > pkt->frames); + for (f = first_frame; f < first_frame + num_frames; f++) { + struct bio_vec *src_bvl = bio_iovec_idx(bio, segment); + + while (src_offs >= src_bvl->bv_len) { + src_offs -= src_bvl->bv_len; + segment++; + BUG_ON(segment >= bio->bi_vcnt); + src_bvl = bio_iovec_idx(bio, segment); + } + + if (src_bvl->bv_len - src_offs >= CD_FRAMESIZE) { + pages[f] = src_bvl->bv_page; + offsets[f] = src_bvl->bv_offset + src_offs; + } else { + pkt_copy_bio_data(bio, segment, src_offs, + pages[f], offsets[f]); + } + src_offs += CD_FRAMESIZE; + frames_write++; + } + } + pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE); + spin_unlock(&pkt->lock); + + VPRINTK("pkt_start_write: Writing %d frames for zone %llx\n", + frames_write, (unsigned long long)pkt->sector); + BUG_ON(frames_write != pkt->write_size); + + if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) { + pkt_make_local_copy(pkt, pages, offsets); + pkt->cache_valid = 1; + } else { + pkt->cache_valid = 0; + } + + /* Start the write request */ + pkt_bio_init(pkt->w_bio); + pkt->w_bio->bi_max_vecs = PACKET_MAX_SIZE; + pkt->w_bio->bi_sector = pkt->sector; + pkt->w_bio->bi_bdev = pd->bdev; + pkt->w_bio->bi_end_io = pkt_end_io_packet_write; + pkt->w_bio->bi_private = pkt; + for (f = 0; f < pkt->frames; f++) { + if ((f + 1 < pkt->frames) && (pages[f + 1] == pages[f]) && + (offsets[f + 1] = offsets[f] + CD_FRAMESIZE)) { + if (!bio_add_page(pkt->w_bio, pages[f], CD_FRAMESIZE * 2, offsets[f])) + BUG(); + f++; + } else { + if (!bio_add_page(pkt->w_bio, pages[f], CD_FRAMESIZE, offsets[f])) + BUG(); + } + } + VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt); + + atomic_set(&pkt->io_wait, 1); + pkt->w_bio->bi_rw = WRITE; + pkt_queue_bio(pd, pkt->w_bio, 0); +} + +static void pkt_finish_packet(struct packet_data *pkt, int uptodate) +{ + struct bio *bio, *next; + + if (!uptodate) + pkt->cache_valid = 0; + + /* Finish all bios corresponding to this packet */ + bio = pkt->orig_bios; + while (bio) { + next = bio->bi_next; + bio->bi_next = NULL; + bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO); + bio = next; + } + pkt->orig_bios = pkt->orig_bios_tail = NULL; +} + +static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt) +{ + int uptodate; + + VPRINTK("run_state_machine: pkt %d\n", pkt->id); + + for (;;) { + switch (pkt->state) { + case PACKET_WAITING_STATE: + if ((pkt->write_size < pkt->frames) && (pkt->sleep_time > 0)) + return; + + pkt->sleep_time = 0; + pkt_gather_data(pd, pkt); + pkt_set_state(pkt, PACKET_READ_WAIT_STATE); + break; + + case PACKET_READ_WAIT_STATE: + if (atomic_read(&pkt->io_wait) > 0) + return; + + if (atomic_read(&pkt->io_errors) > 0) { + pkt_set_state(pkt, PACKET_RECOVERY_STATE); + } else { + pkt_start_write(pd, pkt); + } + break; + + case PACKET_WRITE_WAIT_STATE: + if (atomic_read(&pkt->io_wait) > 0) + return; + + if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) { + pkt_set_state(pkt, PACKET_FINISHED_STATE); + } else { + pkt_set_state(pkt, PACKET_RECOVERY_STATE); + } + break; + + case PACKET_RECOVERY_STATE: + if (pkt_start_recovery(pkt)) { + pkt_start_write(pd, pkt); + } else { + VPRINTK("No recovery possible\n"); + pkt_set_state(pkt, PACKET_FINISHED_STATE); + } + break; + + case PACKET_FINISHED_STATE: + uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags); + pkt_finish_packet(pkt, uptodate); + return; + + default: + BUG(); + break; + } + } +} + +static void pkt_handle_packets(struct pktcdvd_device *pd) +{ + struct packet_data *pkt, *next; + + VPRINTK("pkt_handle_packets\n"); + + /* + * Run state machine for active packets + */ + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (atomic_read(&pkt->run_sm) > 0) { + atomic_set(&pkt->run_sm, 0); + pkt_run_state_machine(pd, pkt); + } + } + + /* + * Move no longer active packets to the free list + */ + spin_lock(&pd->cdrw.active_list_lock); + list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_active_list, list) { + if (pkt->state == PACKET_FINISHED_STATE) { + list_del(&pkt->list); + pkt_put_packet_data(pd, pkt); + pkt_set_state(pkt, PACKET_IDLE_STATE); + atomic_set(&pd->scan_queue, 1); + } + } + spin_unlock(&pd->cdrw.active_list_lock); +} + +static void pkt_count_states(struct pktcdvd_device *pd, int *states) +{ + struct packet_data *pkt; + int i; + + for (i = 0; i <= PACKET_NUM_STATES; i++) + states[i] = 0; + + spin_lock(&pd->cdrw.active_list_lock); + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + states[pkt->state]++; + } + spin_unlock(&pd->cdrw.active_list_lock); +} + +/* + * kcdrwd is woken up when writes have been queued for one of our + * registered devices + */ +static int kcdrwd(void *foobar) +{ + struct pktcdvd_device *pd = foobar; + struct packet_data *pkt; + long min_sleep_time, residue; + + set_user_nice(current, -20); + + for (;;) { + DECLARE_WAITQUEUE(wait, current); + + /* + * Wait until there is something to do + */ + add_wait_queue(&pd->wqueue, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + /* Check if we need to run pkt_handle_queue */ + if (atomic_read(&pd->scan_queue) > 0) + goto work_to_do; + + /* Check if we need to run the state machine for some packet */ + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (atomic_read(&pkt->run_sm) > 0) + goto work_to_do; + } + + /* Check if we need to process the iosched queues */ + if (atomic_read(&pd->iosched.attention) != 0) + goto work_to_do; + + /* Otherwise, go to sleep */ + if (PACKET_DEBUG > 1) { + int states[PACKET_NUM_STATES]; + pkt_count_states(pd, states); + VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + states[0], states[1], states[2], states[3], + states[4], states[5]); + } + + min_sleep_time = MAX_SCHEDULE_TIMEOUT; + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (pkt->sleep_time && pkt->sleep_time < min_sleep_time) + min_sleep_time = pkt->sleep_time; + } + + if (pd->bdev) { + request_queue_t *q; + q = bdev_get_queue(pd->bdev); + generic_unplug_device(q); + } + + VPRINTK("kcdrwd: sleeping\n"); + residue = schedule_timeout(min_sleep_time); + VPRINTK("kcdrwd: wake up\n"); + + /* make swsusp happy with our thread */ + if (current->flags & PF_FREEZE) + refrigerator(PF_FREEZE); + + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (!pkt->sleep_time) + continue; + pkt->sleep_time -= min_sleep_time - residue; + if (pkt->sleep_time <= 0) { + pkt->sleep_time = 0; + atomic_inc(&pkt->run_sm); + } + } + + if (signal_pending(current)) { + flush_signals(current); + } + if (kthread_should_stop()) + break; + } +work_to_do: + set_current_state(TASK_RUNNING); + remove_wait_queue(&pd->wqueue, &wait); + + if (kthread_should_stop()) + break; + + /* + * if pkt_handle_queue returns true, we can queue + * another request. + */ + while (pkt_handle_queue(pd)) + ; + + /* + * Handle packet state machine + */ + pkt_handle_packets(pd); + + /* + * Handle iosched queues + */ + pkt_iosched_process_queue(pd); + } + + return 0; +} + +static void pkt_print_settings(struct pktcdvd_device *pd) +{ + printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable"); + printk("%u blocks, ", pd->settings.size >> 2); + printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2'); +} + +static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, + int page_code, int page_control) +{ + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + + cgc->cmd[0] = GPCMD_MODE_SENSE_10; + cgc->cmd[2] = page_code | (page_control << 6); + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_READ; + return pkt_generic_packet(pd, cgc); +} + +static int pkt_mode_select(struct pktcdvd_device *pd, struct packet_command *cgc) +{ + memset(cgc->cmd, 0, sizeof(cgc->cmd)); + memset(cgc->buffer, 0, 2); + cgc->cmd[0] = GPCMD_MODE_SELECT_10; + cgc->cmd[1] = 0x10; /* PF */ + cgc->cmd[7] = cgc->buflen >> 8; + cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_WRITE; + return pkt_generic_packet(pd, cgc); +} + +static int pkt_get_disc_info(struct pktcdvd_device *pd, disc_information *di) +{ + struct packet_command cgc; + int ret; + + /* set up command and get the disc info */ + init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_DISC_INFO; + cgc.cmd[8] = cgc.buflen = 2; + cgc.quiet = 1; + + if ((ret = pkt_generic_packet(pd, &cgc))) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; + return pkt_generic_packet(pd, &cgc); +} + +static int pkt_get_track_info(struct pktcdvd_device *pd, __u16 track, __u8 type, track_information *ti) +{ + struct packet_command cgc; + int ret; + + init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); + cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; + cgc.cmd[1] = type & 3; + cgc.cmd[4] = (track & 0xff00) >> 8; + cgc.cmd[5] = track & 0xff; + cgc.cmd[8] = 8; + cgc.quiet = 1; + + if ((ret = pkt_generic_packet(pd, &cgc))) + return ret; + + cgc.buflen = be16_to_cpu(ti->track_information_length) + + sizeof(ti->track_information_length); + + if (cgc.buflen > sizeof(track_information)) + cgc.buflen = sizeof(track_information); + + cgc.cmd[8] = cgc.buflen; + return pkt_generic_packet(pd, &cgc); +} + +static int pkt_get_last_written(struct pktcdvd_device *pd, long *last_written) +{ + disc_information di; + track_information ti; + __u32 last_track; + int ret = -1; + + if ((ret = pkt_get_disc_info(pd, &di))) + return ret; + + last_track = (di.last_track_msb << 8) | di.last_track_lsb; + if ((ret = pkt_get_track_info(pd, last_track, 1, &ti))) + return ret; + + /* if this track is blank, try the previous. */ + if (ti.blank) { + last_track--; + if ((ret = pkt_get_track_info(pd, last_track, 1, &ti))) + return ret; + } + + /* if last recorded field is valid, return it. */ + if (ti.lra_v) { + *last_written = be32_to_cpu(ti.last_rec_address); + } else { + /* make it up instead */ + *last_written = be32_to_cpu(ti.track_start) + + be32_to_cpu(ti.track_size); + if (ti.free_blocks) + *last_written -= (be32_to_cpu(ti.free_blocks) + 7); + } + return 0; +} + +/* + * write mode select package based on pd->settings + */ +static int pkt_set_write_settings(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + struct request_sense sense; + write_param_page *wp; + char buffer[128]; + int ret, size; + + /* doesn't apply to DVD+RW */ + if (pd->mmc3_profile == 0x1a) + return 0; + + memset(buffer, 0, sizeof(buffer)); + init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ); + cgc.sense = &sense; + if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { + pkt_dump_sense(&cgc); + return ret; + } + + size = 2 + ((buffer[0] << 8) | (buffer[1] & 0xff)); + pd->mode_offset = (buffer[6] << 8) | (buffer[7] & 0xff); + if (size > sizeof(buffer)) + size = sizeof(buffer); + + /* + * now get it all + */ + init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ); + cgc.sense = &sense; + if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) { + pkt_dump_sense(&cgc); + return ret; + } + + /* + * write page is offset header + block descriptor length + */ + wp = (write_param_page *) &buffer[sizeof(struct mode_page_header) + pd->mode_offset]; + + wp->fp = pd->settings.fp; + wp->track_mode = pd->settings.track_mode; + wp->write_type = pd->settings.write_type; + wp->data_block_type = pd->settings.block_mode; + + wp->multi_session = 0; + +#ifdef PACKET_USE_LS + wp->link_size = 7; + wp->ls_v = 1; +#endif + + if (wp->data_block_type == PACKET_BLOCK_MODE1) { + wp->session_format = 0; + wp->subhdr2 = 0x20; + } else if (wp->data_block_type == PACKET_BLOCK_MODE2) { + wp->session_format = 0x20; + wp->subhdr2 = 8; +#if 0 + wp->mcn[0] = 0x80; + memcpy(&wp->mcn[1], PACKET_MCN, sizeof(wp->mcn) - 1); +#endif + } else { + /* + * paranoia + */ + printk("pktcdvd: write mode wrong %d\n", wp->data_block_type); + return 1; + } + wp->packet_size = cpu_to_be32(pd->settings.size >> 2); + + cgc.buflen = cgc.cmd[8] = size; + if ((ret = pkt_mode_select(pd, &cgc))) { + pkt_dump_sense(&cgc); + return ret; + } + + pkt_print_settings(pd); + return 0; +} + +/* + * 0 -- we can write to this track, 1 -- we can't + */ +static int pkt_good_track(track_information *ti) +{ + /* + * only good for CD-RW at the moment, not DVD-RW + */ + + /* + * FIXME: only for FP + */ + if (ti->fp == 0) + return 0; + + /* + * "good" settings as per Mt Fuji. + */ + if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1) + return 0; + + if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1) + return 0; + + if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1) + return 0; + + printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet); + return 1; +} + +/* + * 0 -- we can write to this disc, 1 -- we can't + */ +static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di) +{ + switch (pd->mmc3_profile) { + case 0x0a: /* CD-RW */ + case 0xffff: /* MMC3 not supported */ + break; + case 0x1a: /* DVD+RW */ + case 0x13: /* DVD-RW */ + return 0; + default: + printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile); + return 1; + } + + /* + * for disc type 0xff we should probably reserve a new track. + * but i'm not sure, should we leave this to user apps? probably. + */ + if (di->disc_type == 0xff) { + printk("pktcdvd: Unknown disc. No track?\n"); + return 1; + } + + if (di->disc_type != 0x20 && di->disc_type != 0) { + printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type); + return 1; + } + + if (di->erasable == 0) { + printk("pktcdvd: Disc not erasable\n"); + return 1; + } + + if (di->border_status == PACKET_SESSION_RESERVED) { + printk("pktcdvd: Can't write to last track (reserved)\n"); + return 1; + } + + return 0; +} + +static int pkt_probe_settings(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + unsigned char buf[12]; + disc_information di; + track_information ti; + int ret, track; + + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; + cgc.cmd[8] = 8; + ret = pkt_generic_packet(pd, &cgc); + pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7]; + + memset(&di, 0, sizeof(disc_information)); + memset(&ti, 0, sizeof(track_information)); + + if ((ret = pkt_get_disc_info(pd, &di))) { + printk("failed get_disc\n"); + return ret; + } + + if (pkt_good_disc(pd, &di)) + return -ENXIO; + + printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : ""); + pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR; + + track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */ + if ((ret = pkt_get_track_info(pd, track, 1, &ti))) { + printk("pktcdvd: failed get_track\n"); + return ret; + } + + if (pkt_good_track(&ti)) { + printk("pktcdvd: can't write to this track\n"); + return -ENXIO; + } + + /* + * we keep packet size in 512 byte units, makes it easier to + * deal with request calculations. + */ + pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2; + if (pd->settings.size == 0) { + printk("pktcdvd: detected zero packet size!\n"); + pd->settings.size = 128; + } + pd->settings.fp = ti.fp; + pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); + + if (ti.nwa_v) { + pd->nwa = be32_to_cpu(ti.next_writable); + set_bit(PACKET_NWA_VALID, &pd->flags); + } + + /* + * in theory we could use lra on -RW media as well and just zero + * blocks that haven't been written yet, but in practice that + * is just a no-go. we'll use that for -R, naturally. + */ + if (ti.lra_v) { + pd->lra = be32_to_cpu(ti.last_rec_address); + set_bit(PACKET_LRA_VALID, &pd->flags); + } else { + pd->lra = 0xffffffff; + set_bit(PACKET_LRA_VALID, &pd->flags); + } + + /* + * fine for now + */ + pd->settings.link_loss = 7; + pd->settings.write_type = 0; /* packet */ + pd->settings.track_mode = ti.track_mode; + + /* + * mode1 or mode2 disc + */ + switch (ti.data_mode) { + case PACKET_MODE1: + pd->settings.block_mode = PACKET_BLOCK_MODE1; + break; + case PACKET_MODE2: + pd->settings.block_mode = PACKET_BLOCK_MODE2; + break; + default: + printk("pktcdvd: unknown data mode\n"); + return 1; + } + return 0; +} + +/* + * enable/disable write caching on drive + */ +static int pkt_write_caching(struct pktcdvd_device *pd, int set) +{ + struct packet_command cgc; + struct request_sense sense; + unsigned char buf[64]; + int ret; + + memset(buf, 0, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + cgc.sense = &sense; + cgc.buflen = pd->mode_offset + 12; + + /* + * caching mode page might not be there, so quiet this command + */ + cgc.quiet = 1; + + if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0))) + return ret; + + buf[pd->mode_offset + 10] |= (!!set << 2); + + cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); + ret = pkt_mode_select(pd, &cgc); + if (ret) { + printk("pktcdvd: write caching control failed\n"); + pkt_dump_sense(&cgc); + } else if (!ret && set) + printk("pktcdvd: enabled write caching on %s\n", pd->name); + return ret; +} + +static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag) +{ + struct packet_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + cgc.cmd[4] = lockflag ? 1 : 0; + return pkt_generic_packet(pd, &cgc); +} + +/* + * Returns drive maximum write speed + */ +static int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *write_speed) +{ + struct packet_command cgc; + struct request_sense sense; + unsigned char buf[256+18]; + unsigned char *cap_buf; + int ret, offset; + + memset(buf, 0, sizeof(buf)); + cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset]; + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); + cgc.sense = &sense; + + ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + cgc.buflen = pd->mode_offset + cap_buf[1] + 2 + + sizeof(struct mode_page_header); + ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + } + + offset = 20; /* Obsoleted field, used by older drives */ + if (cap_buf[1] >= 28) + offset = 28; /* Current write speed selected */ + if (cap_buf[1] >= 30) { + /* If the drive reports at least one "Logical Unit Write + * Speed Performance Descriptor Block", use the information + * in the first block. (contains the highest speed) + */ + int num_spdb = (cap_buf[30] << 8) + cap_buf[31]; + if (num_spdb > 0) + offset = 34; + } + + *write_speed = ((cap_buf[offset] << 8) | cap_buf[offset + 1]) / 0xb0; + return 0; +} + +/* These tables from cdrecord - I don't have orange book */ +/* standard speed CD-RW (1-4x) */ +static char clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* high speed CD-RW (-10x) */ +static char hs_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +/* ultra high speed CD-RW */ +static char us_clv_to_speed[16] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ + 0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0 +}; + +/* + * reads the maximum media speed from ATIP + */ +static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) +{ + struct packet_command cgc; + struct request_sense sense; + unsigned char buf[64]; + unsigned int size, st, sp; + int ret; + + init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; /* READ ATIP */ + cgc.cmd[8] = 2; + ret = pkt_generic_packet(pd, &cgc); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + size = ((unsigned int) buf[0]<<8) + buf[1] + 2; + if (size > sizeof(buf)) + size = sizeof(buf); + + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); + cgc.sense = &sense; + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = 2; + cgc.cmd[2] = 4; + cgc.cmd[8] = size; + ret = pkt_generic_packet(pd, &cgc); + if (ret) { + pkt_dump_sense(&cgc); + return ret; + } + + if (!buf[6] & 0x40) { + printk("pktcdvd: Disc type is not CD-RW\n"); + return 1; + } + if (!buf[6] & 0x4) { + printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n"); + return 1; + } + + st = (buf[6] >> 3) & 0x7; /* disc sub-type */ + + sp = buf[16] & 0xf; /* max speed from ATIP A1 field */ + + /* Info from cdrecord */ + switch (st) { + case 0: /* standard speed */ + *speed = clv_to_speed[sp]; + break; + case 1: /* high speed */ + *speed = hs_clv_to_speed[sp]; + break; + case 2: /* ultra high speed */ + *speed = us_clv_to_speed[sp]; + break; + default: + printk("pktcdvd: Unknown disc sub-type %d\n",st); + return 1; + } + if (*speed) { + printk("pktcdvd: Max. media speed: %d\n",*speed); + return 0; + } else { + printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st); + return 1; + } +} + +static int pkt_perform_opc(struct pktcdvd_device *pd) +{ + struct packet_command cgc; + struct request_sense sense; + int ret; + + VPRINTK("pktcdvd: Performing OPC\n"); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.sense = &sense; + cgc.timeout = 60*HZ; + cgc.cmd[0] = GPCMD_SEND_OPC; + cgc.cmd[1] = 1; + if ((ret = pkt_generic_packet(pd, &cgc))) + pkt_dump_sense(&cgc); + return ret; +} + +static int pkt_open_write(struct pktcdvd_device *pd) +{ + int ret; + unsigned int write_speed, media_write_speed, read_speed; + + if ((ret = pkt_probe_settings(pd))) { + DPRINTK("pktcdvd: %s failed probe\n", pd->name); + return -EIO; + } + + if ((ret = pkt_set_write_settings(pd))) { + DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name); + return -EIO; + } + + pkt_write_caching(pd, USE_WCACHING); + + if ((ret = pkt_get_max_speed(pd, &write_speed))) + write_speed = 16; + switch (pd->mmc3_profile) { + case 0x13: /* DVD-RW */ + case 0x1a: /* DVD+RW */ + break; + default: + if ((ret = pkt_media_speed(pd, &media_write_speed))) + media_write_speed = 16; + write_speed = min(write_speed, media_write_speed); + break; + } + read_speed = write_speed; + + if ((ret = pkt_set_speed(pd, write_speed, read_speed))) { + DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name); + return -EIO; + } + DPRINTK("pktcdvd: write speed %u\n", write_speed); + pd->write_speed = write_speed; + pd->read_speed = read_speed; + + if ((ret = pkt_perform_opc(pd))) { + DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name); + } + + return 0; +} + +/* + * called at open time. + */ +static int pkt_open_dev(struct pktcdvd_device *pd, int write) +{ + int ret; + long lba; + request_queue_t *q; + int i; + char b[BDEVNAME_SIZE]; + + if (!pd->dev) + return -ENXIO; + + pd->bdev = bdget(pd->dev); + if (!pd->bdev) { + printk("pktcdvd: can't find cdrom block device\n"); + return -ENXIO; + } + + if ((ret = blkdev_get(pd->bdev, FMODE_READ, 0))) { + pd->bdev = NULL; + return ret; + } + + if ((ret = pkt_get_last_written(pd, &lba))) { + printk("pktcdvd: pkt_get_last_written failed\n"); + return ret; + } + + set_capacity(pd->disk, lba << 2); + + /* + * The underlying block device needs to have its merge logic + * modified, so that it doesn't try to merge write requests. + * First make sure the queue isn't already in use by another + * pktcdvd_device. + */ + q = bdev_get_queue(pd->bdev); + for (i = 0; i < MAX_WRITERS; i++) { + if (pd == &pkt_devs[i]) + continue; + if (pkt_devs[i].bdev && bdev_get_queue(pkt_devs[i].bdev) == q) { + printk("pktcdvd: %s request queue busy\n", bdevname(pd->bdev, b)); + return -EBUSY; + } + } + spin_lock_irq(q->queue_lock); + pd->cdrw.elv_merge_fn = q->elevator.elevator_merge_fn; + pd->cdrw.elv_completed_req_fn = q->elevator.elevator_completed_req_fn; + pd->cdrw.merge_requests_fn = q->merge_requests_fn; + q->elevator.elevator_merge_fn = pkt_lowlevel_elv_merge_fn; + q->elevator.elevator_completed_req_fn = pkt_lowlevel_elv_completed_req_fn; + q->merge_requests_fn = pkt_lowlevel_merge_requests_fn; + spin_unlock_irq(q->queue_lock); + + if (write) { + if ((ret = pkt_open_write(pd))) + goto restore_queue; + set_bit(PACKET_WRITABLE, &pd->flags); + } else { + pkt_set_speed(pd, 0xffff, 0xffff); + clear_bit(PACKET_WRITABLE, &pd->flags); + } + + if ((ret = pkt_set_segment_merging(pd, q))) + goto restore_queue; + + if (write) + printk("pktcdvd: %lukB available on disc\n", lba << 1); + + return 0; + +restore_queue: + spin_lock_irq(q->queue_lock); + q->elevator.elevator_merge_fn = pd->cdrw.elv_merge_fn; + q->elevator.elevator_completed_req_fn = pd->cdrw.elv_completed_req_fn; + q->merge_requests_fn = pd->cdrw.merge_requests_fn; + spin_unlock_irq(q->queue_lock); + return ret; +} + +/* + * called when the device is closed. makes sure that the device flushes + * the internal cache before we close. + */ +static void pkt_release_dev(struct pktcdvd_device *pd, int flush) +{ + if (flush && pkt_flush_cache(pd)) + DPRINTK("pktcdvd: %s not flushing cache\n", pd->name); + + if (pd->bdev) { + request_queue_t *q = bdev_get_queue(pd->bdev); + pkt_set_speed(pd, 0xffff, 0xffff); + spin_lock_irq(q->queue_lock); + q->elevator.elevator_merge_fn = pd->cdrw.elv_merge_fn; + q->elevator.elevator_completed_req_fn = pd->cdrw.elv_completed_req_fn; + q->merge_requests_fn = pd->cdrw.merge_requests_fn; + spin_unlock_irq(q->queue_lock); + blkdev_put(pd->bdev); + pd->bdev = NULL; + } +} + +static int pkt_open(struct inode *inode, struct file *file) +{ + struct pktcdvd_device *pd = NULL; + int ret; + int special_open, exclusive; + + VPRINTK("pktcdvd: entering open\n"); + + if (iminor(inode) >= MAX_WRITERS) { + printk("pktcdvd: max %d writers supported\n", MAX_WRITERS); + ret = -ENODEV; + goto out; + } + + special_open = 0; + if (((file->f_flags & O_ACCMODE) == O_RDONLY) && (file->f_flags & O_CREAT)) + special_open = 1; + + exclusive = 0; + if ((file->f_mode & FMODE_WRITE) || special_open) + exclusive = 1; + + /* + * either device is not configured, or pktsetup is old and doesn't + * use O_CREAT to create device + */ + pd = &pkt_devs[iminor(inode)]; + if (!pd->dev && !special_open) { + VPRINTK("pktcdvd: not configured and O_CREAT not set\n"); + ret = -ENXIO; + goto out; + } + + down(&pd->ctl_mutex); + pd->refcnt++; + if (pd->refcnt > 1) { + if (exclusive) { + VPRINTK("pktcdvd: busy open\n"); + ret = -EBUSY; + goto out_dec; + } + + /* + * Not first open, everything is already set up + */ + goto done; + } + + if (!special_open) { + if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) { + ret = -EIO; + goto out_dec; + } + } + + /* + * needed here as well, since ext2 (among others) may change + * the blocksize at mount time + */ + set_blocksize(inode->i_bdev, CD_FRAMESIZE); + +done: + up(&pd->ctl_mutex); + return 0; + +out_dec: + pd->refcnt--; + if (pd->refcnt == 0) { + if (pd->bdev) { + blkdev_put(pd->bdev); + pd->bdev = NULL; + } + } + up(&pd->ctl_mutex); +out: + VPRINTK("pktcdvd: failed open (%d)\n", ret); + return ret; +} + +static int pkt_close(struct inode *inode, struct file *file) +{ + struct pktcdvd_device *pd = &pkt_devs[iminor(inode)]; + int ret = 0; + + down(&pd->ctl_mutex); + pd->refcnt--; + BUG_ON(pd->refcnt < 0); + if (pd->refcnt > 0) + goto out; + if (pd->dev) { + int flush = test_bit(PACKET_WRITABLE, &pd->flags); + pkt_release_dev(pd, flush); + } +out: + up(&pd->ctl_mutex); + return ret; +} + +static int pkt_make_request(request_queue_t *q, struct bio *bio) +{ + struct pktcdvd_device *pd; + char b[BDEVNAME_SIZE]; + sector_t zone; + struct packet_data *pkt; + int was_empty, blocked_bio; + + pd = q->queuedata; + if (!pd) { + printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b)); + goto end_io; + } + + if (!pd->dev) { + printk("pktcdvd: request received for non-active pd\n"); + goto end_io; + } + + /* + * quick remap a READ + */ + if (bio_data_dir(bio) == READ) { + bio->bi_bdev = pd->bdev; + pd->stats.secs_r += bio->bi_size >> 9; + pkt_queue_bio(pd, bio, 1); + return 0; + } + + if (!test_bit(PACKET_WRITABLE, &pd->flags)) { + printk("pktcdvd: WRITE for ro device %s (%llu)\n", + pd->name, (unsigned long long)bio->bi_sector); + goto end_io; + } + + if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { + printk("pktcdvd: wrong bio size\n"); + goto end_io; + } + + blk_queue_bounce(q, &bio); + + zone = ZONE(bio->bi_sector, pd); + VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n", + (unsigned long long)bio->bi_sector, + (unsigned long long)(bio->bi_sector + bio_sectors(bio))); + + /* Check if we have to split the bio */ + { + struct bio_pair *bp; + sector_t last_zone; + int first_sectors; + + last_zone = ZONE(bio->bi_sector + bio_sectors(bio) - 1, pd); + if (last_zone != zone) { + BUG_ON(last_zone != zone + pd->settings.size); + first_sectors = last_zone - bio->bi_sector; + bp = bio_split(bio, bio_split_pool, first_sectors); + BUG_ON(!bp); + pkt_make_request(q, &bp->bio1); + pkt_make_request(q, &bp->bio2); + bio_pair_release(bp); + return 0; + } + } + + /* + * If we find a matching packet in state WAITING or READ_WAIT, we can + * just append this bio to that packet. + */ + spin_lock(&pd->cdrw.active_list_lock); + blocked_bio = 0; + list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) { + if (pkt->sector == zone) { + spin_lock(&pkt->lock); + if ((pkt->state == PACKET_WAITING_STATE) || + (pkt->state == PACKET_READ_WAIT_STATE)) { + pkt_add_list_last(bio, &pkt->orig_bios, + &pkt->orig_bios_tail); + pkt->write_size += bio->bi_size / CD_FRAMESIZE; + if ((pkt->write_size >= pkt->frames) && + (pkt->state == PACKET_WAITING_STATE)) { + atomic_inc(&pkt->run_sm); + wake_up(&pd->wqueue); + } + spin_unlock(&pkt->lock); + spin_unlock(&pd->cdrw.active_list_lock); + return 0; + } else { + blocked_bio = 1; + } + spin_unlock(&pkt->lock); + } + } + spin_unlock(&pd->cdrw.active_list_lock); + + /* + * No matching packet found. Store the bio in the work queue. + */ + spin_lock(&pd->lock); + if (pd->bio_queue == NULL) { + was_empty = 1; + bio->bi_next = NULL; + pd->bio_queue = bio; + pd->bio_queue_tail = bio; + } else { + struct bio *bio2, *insert_after; + int distance, z, cnt; + + was_empty = 0; + z = ZONE(pd->bio_queue_tail->bi_sector, pd); + distance = (zone >= z ? zone - z : INT_MAX); + insert_after = pd->bio_queue_tail; + if (distance > pd->settings.size) { + for (bio2 = pd->bio_queue, cnt = 0; bio2 && (cnt < 10000); + bio2 = bio2->bi_next, cnt++) { + int d2; + z = ZONE(bio2->bi_sector, pd); + d2 = (zone >= z ? zone - z : INT_MAX); + if (d2 < distance) { + distance = d2; + insert_after = bio2; + if (distance == 0) + break; + } + } + } + bio->bi_next = insert_after->bi_next; + insert_after->bi_next = bio; + if (insert_after == pd->bio_queue_tail) + pd->bio_queue_tail = bio; + } + spin_unlock(&pd->lock); + + /* + * Wake up the worker thread. + */ + atomic_set(&pd->scan_queue, 1); + if (was_empty) { + /* This wake_up is required for correct operation */ + wake_up(&pd->wqueue); + } else if (!list_empty(&pd->cdrw.pkt_free_list) && !blocked_bio) { + /* + * This wake up is not required for correct operation, + * but improves performance in some cases. + */ + wake_up(&pd->wqueue); + } + return 0; +end_io: + bio_io_error(bio, bio->bi_size); + return 0; +} + + + +static int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *bvec) +{ + struct pktcdvd_device *pd = &pkt_devs[MINOR(bio->bi_bdev->bd_dev)]; + sector_t zone = ZONE(bio->bi_sector, pd); + int used = ((bio->bi_sector - zone) << 9) + bio->bi_size; + int remaining = (pd->settings.size << 9) - used; + int remaining2; + + /* + * A bio <= PAGE_SIZE must be allowed. If it crosses a packet + * boundary, pkt_make_request() will split the bio. + */ + remaining2 = PAGE_SIZE - bio->bi_size; + remaining = max(remaining, remaining2); + + BUG_ON(remaining < 0); + return remaining; +} + +static void pkt_init_queue(struct pktcdvd_device *pd) +{ + request_queue_t *q = pd->disk->queue; + + blk_queue_make_request(q, pkt_make_request); + blk_queue_hardsect_size(q, CD_FRAMESIZE); + blk_queue_max_sectors(q, PACKET_MAX_SECTORS); + blk_queue_merge_bvec(q, pkt_merge_bvec); + q->queuedata = pd; +} + +static int pkt_seq_show(struct seq_file *m, void *p) +{ + struct pktcdvd_device *pd = m->private; + char *msg; + char bdev_buf[BDEVNAME_SIZE]; + int states[PACKET_NUM_STATES]; + + seq_printf(m, "Writer %s mapped to %s:\n", pd->name, + __bdevname(pd->dev, bdev_buf)); + + seq_printf(m, "\nSettings:\n"); + seq_printf(m, "\tpacket size:\t\t%dkB\n", pd->settings.size / 2); + + if (pd->settings.write_type == 0) + msg = "Packet"; + else + msg = "Unknown"; + seq_printf(m, "\twrite type:\t\t%s\n", msg); + + seq_printf(m, "\tpacket type:\t\t%s\n", pd->settings.fp ? "Fixed" : "Variable"); + seq_printf(m, "\tlink loss:\t\t%d\n", pd->settings.link_loss); + + seq_printf(m, "\ttrack mode:\t\t%d\n", pd->settings.track_mode); + + if (pd->settings.block_mode == PACKET_BLOCK_MODE1) + msg = "Mode 1"; + else if (pd->settings.block_mode == PACKET_BLOCK_MODE2) + msg = "Mode 2"; + else + msg = "Unknown"; + seq_printf(m, "\tblock mode:\t\t%s\n", msg); + + seq_printf(m, "\nStatistics:\n"); + seq_printf(m, "\tpackets started:\t%lu\n", pd->stats.pkt_started); + seq_printf(m, "\tpackets ended:\t\t%lu\n", pd->stats.pkt_ended); + seq_printf(m, "\twritten:\t\t%lukB\n", pd->stats.secs_w >> 1); + seq_printf(m, "\tread gather:\t\t%lukB\n", pd->stats.secs_rg >> 1); + seq_printf(m, "\tread:\t\t\t%lukB\n", pd->stats.secs_r >> 1); + + seq_printf(m, "\nMisc:\n"); + seq_printf(m, "\treference count:\t%d\n", pd->refcnt); + seq_printf(m, "\tflags:\t\t\t0x%lx\n", pd->flags); + seq_printf(m, "\tread speed:\t\t%ukB/s\n", pd->read_speed * 150); + seq_printf(m, "\twrite speed:\t\t%ukB/s\n", pd->write_speed * 150); + seq_printf(m, "\tstart offset:\t\t%lu\n", pd->offset); + seq_printf(m, "\tmode page offset:\t%u\n", pd->mode_offset); + + seq_printf(m, "\nQueue state:\n"); + seq_printf(m, "\tbios queued:\t\t%s\n", pd->bio_queue ? "yes" : "no"); + + pkt_count_states(pd, states); + seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", + states[0], states[1], states[2], states[3], states[4], states[5]); + + return 0; +} + +static int pkt_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, pkt_seq_show, PDE(inode)->data); +} + +static struct file_operations pkt_proc_fops = { + .open = pkt_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +static int pkt_new_dev(struct pktcdvd_device *pd, struct block_device *bdev) +{ + dev_t dev = bdev->bd_dev; + int i; + int ret = 0; + char b[BDEVNAME_SIZE]; + struct proc_dir_entry *proc; + + for (i = 0; i < MAX_WRITERS; i++) { + if (pkt_devs[i].dev == dev) { + printk("pktcdvd: %s already setup\n", bdevname(bdev, b)); + return -EBUSY; + } + } + + /* This is safe, since we have a reference from open(). */ + __module_get(THIS_MODULE); + + memset(&pd->stats, 0, sizeof(struct packet_stats)); + + if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) { + printk("pktcdvd: not enough memory for buffers\n"); + ret = -ENOMEM; + goto out_mem; + } + + set_blocksize(bdev, CD_FRAMESIZE); + pd->dev = dev; + BUG_ON(pd->bdev); + + pkt_init_queue(pd); + + pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name); + if (IS_ERR(pd->cdrw.thread)) { + printk("pktcdvd: can't start kernel thread\n"); + ret = -ENOMEM; + goto out_thread; + } + + proc = create_proc_entry(pd->name, 0, pkt_proc); + if (proc) { + proc->data = pd; + proc->proc_fops = &pkt_proc_fops; + } + DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); + return 0; + +out_thread: + pkt_shrink_pktlist(pd); +out_mem: + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + return ret; +} + +/* + * arg contains file descriptor of CD-ROM device. + */ +static int pkt_setup_dev(struct pktcdvd_device *pd, unsigned int arg) +{ + struct inode *inode; + struct file *file; + int ret; + + if ((file = fget(arg)) == NULL) { + printk("pktcdvd: bad file descriptor passed\n"); + return -EBADF; + } + + inode = file->f_dentry->d_inode; + ret = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) { + printk("pktcdvd: device is not a block device (duh)\n"); + goto out; + } + ret = -EROFS; + if (IS_RDONLY(inode)) { + printk("pktcdvd: Can't write to read-only dev\n"); + goto out; + } + ret = pkt_new_dev(pd, inode->i_bdev); + +out: + fput(file); + return ret; +} + +static int pkt_remove_dev(struct pktcdvd_device *pd, struct block_device *bdev) +{ + if (!IS_ERR(pd->cdrw.thread)) + kthread_stop(pd->cdrw.thread); + + /* + * will also invalidate buffers for CD-ROM + */ + invalidate_bdev(bdev, 1); + + pkt_shrink_pktlist(pd); + + remove_proc_entry(pd->name, pkt_proc); + pd->dev = 0; + DPRINTK("pktcdvd: writer %s unmapped\n", pd->name); + /* This is safe: open() is still holding a reference. */ + module_put(THIS_MODULE); + return 0; +} + +static int pkt_media_changed(struct gendisk *disk) +{ + struct pktcdvd_device *pd = disk->private_data; + struct gendisk *attached_disk; + + if (!pd) + return 0; + if (!pd->bdev) + return 0; + attached_disk = pd->bdev->bd_disk; + if (!attached_disk) + return 0; + return attached_disk->fops->media_changed(attached_disk); +} + +static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pktcdvd_device *pd = &pkt_devs[iminor(inode)]; + int ret; + + VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode)); + + if ((cmd != PACKET_SETUP_DEV) && !pd->dev) { + DPRINTK("pktcdvd: dev not setup\n"); + return -ENXIO; + } + + switch (cmd) { + case PACKET_GET_STATS: + if (copy_to_user(&arg, &pd->stats, sizeof(struct packet_stats))) + return -EFAULT; + break; + + case PACKET_SETUP_DEV: + if (pd->dev) { + printk("pktcdvd: dev already setup\n"); + return -EBUSY; + } + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return pkt_setup_dev(pd, arg); + + case PACKET_TEARDOWN_DEV: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + down(&pd->ctl_mutex); + BUG_ON(pd->refcnt < 1); + if (pd->refcnt != 1) + ret = -EBUSY; + else + ret = pkt_remove_dev(pd, inode->i_bdev); + up(&pd->ctl_mutex); + return ret; + + /* + * forward selected CDROM ioctls to CD-ROM, for UDF + */ + case CDROMMULTISESSION: + case CDROMREADTOCENTRY: + case CDROM_LAST_WRITTEN: + case CDROM_SEND_PACKET: + case SCSI_IOCTL_SEND_COMMAND: + if (!pd->bdev) + return -ENXIO; + return ioctl_by_bdev(pd->bdev, cmd, arg); + + case CDROMEJECT: + if (!pd->bdev) + return -ENXIO; + /* + * The door gets locked when the device is opened, so we + * have to unlock it or else the eject command fails. + */ + pkt_lock_door(pd, 0); + return ioctl_by_bdev(pd->bdev, cmd, arg); + + default: + printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); + return -ENOTTY; + } + + return 0; +} + +static struct block_device_operations pktcdvd_ops = { + .owner = THIS_MODULE, + .open = pkt_open, + .release = pkt_close, + .ioctl = pkt_ioctl, + .media_changed = pkt_media_changed, +}; + +int pkt_init(void) +{ + int i; + + devfs_mk_dir("pktcdvd"); + if (register_blkdev(PACKET_MAJOR, "pktcdvd")) { + printk("unable to register pktcdvd device\n"); + return -EIO; + } + + pkt_devs = kmalloc(MAX_WRITERS * sizeof(struct pktcdvd_device), GFP_KERNEL); + if (pkt_devs == NULL) + goto out_mem; + memset(pkt_devs, 0, MAX_WRITERS * sizeof(struct pktcdvd_device)); + + for (i = 0; i < MAX_WRITERS; i++) { + struct pktcdvd_device *pd = &pkt_devs[i]; + + pd->disk = alloc_disk(1); + if (!pd->disk) + goto out_mem2; + } + + for (i = 0; i < MAX_WRITERS; i++) { + struct pktcdvd_device *pd = &pkt_devs[i]; + struct gendisk *disk = pd->disk; + + spin_lock_init(&pd->lock); + spin_lock_init(&pd->iosched.lock); + sprintf(pd->name, "pktcdvd%d", i); + init_waitqueue_head(&pd->wqueue); + init_MUTEX(&pd->ctl_mutex); + + disk->major = PACKET_MAJOR; + disk->first_minor = i; + disk->fops = &pktcdvd_ops; + disk->flags = GENHD_FL_REMOVABLE; + sprintf(disk->disk_name, "pktcdvd%d", i); + sprintf(disk->devfs_name, "pktcdvd/%d", i); + disk->private_data = pd; + disk->queue = blk_alloc_queue(GFP_KERNEL); + if (!disk->queue) + goto out_mem3; + add_disk(disk); + } + + pkt_proc = proc_mkdir("pktcdvd", proc_root_driver); + + DPRINTK("pktcdvd: %s\n", VERSION_CODE); + return 0; + +out_mem3: + while (i--) + blk_put_queue(pkt_devs[i].disk->queue); + i = MAX_WRITERS; +out_mem2: + while (i--) + put_disk(pkt_devs[i].disk); + kfree(pkt_devs); +out_mem: + printk("pktcdvd: out of memory\n"); + devfs_remove("pktcdvd"); + unregister_blkdev(PACKET_MAJOR, "pktcdvd"); + return -ENOMEM; +} + +void pkt_exit(void) +{ + int i; + for (i = 0; i < MAX_WRITERS; i++) { + struct gendisk *disk = pkt_devs[i].disk; + del_gendisk(disk); + blk_put_queue(disk->queue); + put_disk(disk); + } + + devfs_remove("pktcdvd"); + unregister_blkdev(PACKET_MAJOR, "pktcdvd"); + + remove_proc_entry("pktcdvd", proc_root_driver); + kfree(pkt_devs); +} + +MODULE_DESCRIPTION("Packet writing layer for CD/DVD drives"); +MODULE_AUTHOR("Jens Axboe "); +MODULE_LICENSE("GPL"); + +module_init(pkt_init); +module_exit(pkt_exit); + +MODULE_ALIAS_BLOCKDEV_MAJOR(PACKET_MAJOR); --- linux-2.6.8-rc1/drivers/block/scsi_ioctl.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/block/scsi_ioctl.c 2004-07-13 17:09:50.000000000 -0700 @@ -204,7 +204,7 @@ static int sg_io(request_queue_t *q, str hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(rq, hdr->dxferp, bio, hdr->dxfer_len)) + if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len)) return -EFAULT; /* may not have succeeded, but output values written to control --- linux-2.6.8-rc1/drivers/block/xd.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/block/xd.c 2004-07-13 17:09:13.000000000 -0700 @@ -96,7 +96,7 @@ XD_INFO xd_info[XD_MAXDRIVES]; #include #define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size)) #define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) -static char *xd_dma_buffer = 0; +static char *xd_dma_buffer; static XD_SIGNATURE xd_sigs[] __initdata = { { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */ @@ -344,7 +344,7 @@ static int xd_ioctl (struct inode *inode if (nodma && xd_dma_buffer) { xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200); - xd_dma_buffer = 0; + xd_dma_buffer = NULL; } else if (!nodma && !xd_dma_buffer) { xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); if (!xd_dma_buffer) { @@ -448,7 +448,7 @@ static void xd_recalibrate (u_char drive u_char cmdblk[6]; xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0); - if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) + if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8)) printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive); } @@ -607,7 +607,7 @@ static u_int xd_command (u_char *command if (csb & CSB_ERROR) { /* read sense data if error */ xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0); - if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT)) + if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT)) printk("xd: warning! sense command failed!\n"); } @@ -624,7 +624,7 @@ static u_char __init xd_initdrives (void for (i = 0; i < XD_MAXDRIVES; i++) { xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0); - if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) { + if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(XD_INIT_DISK_DELAY); @@ -714,7 +714,7 @@ static void __init xd_dtc_init_drive (u_ u_char cmdblk[6],buf[64]; xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0); - if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x0A]; /* heads */ xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ @@ -729,7 +729,7 @@ static void __init xd_dtc_init_drive (u_ xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]); xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7); - if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2)) printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive); } else @@ -785,7 +785,7 @@ static void __init xd_wd_init_drive (u_c xd_irq = 9; rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0; xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0); - if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x1AF]; /* heads */ xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */ @@ -862,7 +862,7 @@ static void __init xd_seagate_init_drive u_char cmdblk[6],buf[0x200]; xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0); - if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) { xd_info[drive].heads = buf[0x04]; /* heads */ xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */ xd_info[drive].sectors = buf[0x05]; /* sectors */ @@ -987,7 +987,7 @@ static void __init xd_override_init_driv while (min[i] != max[i] - 1) { test[i] = (min[i] + max[i]) / 2; xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0); - if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2)) min[i] = test[i]; else max[i] = test[i]; @@ -1039,7 +1039,7 @@ static void __init xd_setparam (u_char c /* Some controllers require geometry info as data, not command */ - if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2)) + if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2)) printk("xd: error setting characteristics for xd%c\n", 'a'+drive); } --- linux-2.6.8-rc1/drivers/bluetooth/bfusb.c 2004-07-11 14:13:26.000000000 -0700 +++ 25/drivers/bluetooth/bfusb.c 2004-07-13 17:09:13.000000000 -0700 @@ -586,7 +586,6 @@ static int bfusb_load_firmware(struct bf } bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0; - bfusb->udev->halted[0] = bfusb->udev->halted[1] = 0; buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); if (!buf) { @@ -628,7 +627,6 @@ static int bfusb_load_firmware(struct bf } bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0; - bfusb->udev->halted[0] = bfusb->udev->halted[1] = 0; BT_INFO("BlueFRITZ! USB device ready"); --- linux-2.6.8-rc1/drivers/cdrom/cdrom.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/cdrom/cdrom.c 2004-07-13 17:09:50.000000000 -0700 @@ -821,6 +821,41 @@ static int cdrom_ram_open_write(struct c return ret; } +static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) +{ + struct packet_command cgc; + char buffer[32]; + int ret, mmc3_profile; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; + cgc.cmd[1] = 0; + cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ + cgc.cmd[7] = 0; cgc.cmd [8] = 8; /* Allocation Length */ + cgc.quiet = 1; + + if ((ret = cdi->ops->generic_packet(cdi, &cgc))) { + mmc3_profile = 0xffff; + } else { + mmc3_profile = (buffer[6] << 8) | buffer[7]; + printk(KERN_INFO "cdrom: %s: mmc-3 profile capable, current profile: %Xh\n", + cdi->name, mmc3_profile); + } + cdi->mmc3_profile = mmc3_profile; +} + +static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) +{ + switch (cdi->mmc3_profile) { + case 0x12: /* DVD-RAM */ + case 0x1A: /* DVD+RW */ + return 0; + default: + return 1; + } +} + /* * returns 0 for ok to open write, non-0 to disallow */ @@ -859,10 +894,50 @@ static int cdrom_open_write(struct cdrom ret = cdrom_ram_open_write(cdi); else if (CDROM_CAN(CDC_MO_DRIVE)) ret = mo_open_write(cdi); + else if (!cdrom_is_dvd_rw(cdi)) + ret = 0; return ret; } +static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi) +{ + struct packet_command cgc; + + if (cdi->mmc3_profile != 0x1a) { + cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); + return; + } + + if (!cdi->media_written) { + cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); + return; + } + + printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n", + cdi->name); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + cgc.timeout = 30*HZ; + cdi->ops->generic_packet(cdi, &cgc); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_CLOSE_TRACK; + cgc.timeout = 3000*HZ; + cgc.quiet = 1; + cdi->ops->generic_packet(cdi, &cgc); + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_CLOSE_TRACK; + cgc.cmd[2] = 2; /* Close session */ + cgc.quiet = 1; + cgc.timeout = 3000*HZ; + cdi->ops->generic_packet(cdi, &cgc); + + cdi->media_written = 0; +} + static int cdrom_close_write(struct cdrom_device_info *cdi) { #if 0 @@ -895,6 +970,7 @@ int cdrom_open(struct cdrom_device_info ret = open_for_data(cdi); if (ret) goto err; + cdrom_mmc3_profile(cdi); if (fp->f_mode & FMODE_WRITE) { ret = -EROFS; if (!CDROM_CAN(CDC_RAM)) @@ -902,6 +978,7 @@ int cdrom_open(struct cdrom_device_info if (cdrom_open_write(cdi)) goto err; ret = 0; + cdi->media_written = 0; } } @@ -1093,6 +1170,8 @@ int cdrom_release(struct cdrom_device_in cdi->use_count--; if (cdi->use_count == 0) cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); + if (cdi->use_count == 0) + cdrom_dvd_rw_close_write(cdi); if (cdi->use_count == 0 && (cdo->capability & CDC_LOCK) && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); @@ -1299,6 +1378,7 @@ int media_changed(struct cdrom_device_in if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { cdi->mc_flags = 0x3; /* set bit on both queues */ ret |= 1; + cdi->media_written = 0; } cdi->mc_flags &= ~mask; /* clear bit */ return ret; @@ -2008,7 +2088,7 @@ static int cdrom_read_cdda_bpc(struct cd cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(rq, ubuf, bio, len)) + if (blk_rq_unmap_user(rq, bio, len)) ret = -EFAULT; if (ret) --- linux-2.6.8-rc1/drivers/cdrom/Makefile 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/cdrom/Makefile 2004-07-13 17:09:41.000000000 -0700 @@ -8,6 +8,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += cdrom.o obj-$(CONFIG_BLK_DEV_SR) += cdrom.o obj-$(CONFIG_PARIDE_PCD) += cdrom.o +obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o obj-$(CONFIG_AZTCD) += aztcd.o obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o --- linux-2.6.8-rc1/drivers/char/agp/amd64-agp.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/agp/amd64-agp.c 2004-07-13 17:09:18.000000000 -0700 @@ -563,14 +563,25 @@ static struct pci_device_id agp_amd64_pc .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* VIA K8T890 */ { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_VIA, - .device = PCI_DEVICE_ID_VIA_8380_0, + .device = PCI_DEVICE_ID_VIA_3238_0, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* VIA K8T800/K8M800/K8N800 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_838X_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + /* NForce3 */ { .class = (PCI_CLASS_BRIDGE_HOST << 8), --- linux-2.6.8-rc1/drivers/char/agp/intel-agp.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/agp/intel-agp.c 2004-07-13 17:09:18.000000000 -0700 @@ -5,11 +5,15 @@ /* * Intel(R) 855GM/852GM and 865G support added by David Dawes * . + * + * Intel(R) 915G support added by Alan Hourihane + * . */ #include #include #include +#include #include #include "agp.h" @@ -29,6 +33,14 @@ #define INTEL_I850_MCHCFG 0x50 #define INTEL_I850_ERRSTS 0xc8 +/* intel 915G registers */ +#define I915_GMADDR 0x18 +#define I915_MMADDR 0x10 +#define I915_PTEADDR 0x1C +#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) + + /* Intel 7505 registers */ #define INTEL_I7505_APSIZE 0x74 #define INTEL_I7505_NCAPID 0x60 @@ -143,6 +155,40 @@ static void intel_i810_agp_enable(u32 mo return; } +/* Exists to support ARGB cursors */ +static void *i8xx_alloc_pages(void) +{ + struct page * page; + + page = alloc_pages(GFP_KERNEL, 2); + if (page == NULL) { + return 0; + } + if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + __free_page(page); + return 0; + } + get_page(page); + SetPageLocked(page); + atomic_inc(&agp_bridge->current_memory_agp); + return page_address(page); +} + +static void i8xx_destroy_pages(void *addr) +{ + struct page *page; + + if (addr == NULL) + return; + + page = virt_to_page(addr); + change_page_attr(page, 4, PAGE_KERNEL); + put_page(page); + unlock_page(page); + free_pages((unsigned long)addr, 2); + atomic_dec(&agp_bridge->current_memory_agp); +} + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -218,20 +264,36 @@ static struct agp_memory *alloc_agpphysm struct agp_memory *new; void *addr; - if (pg_count != 1) + if (pg_count != 1 && pg_count != 4) return NULL; - addr = agp_bridge->driver->agp_alloc_page(); + switch (pg_count) { + case 1: addr = agp_bridge->driver->agp_alloc_page(); + break; + case 4: + /* kludge to get 4 physical pages for ARGB cursor */ + addr = i8xx_alloc_pages(); + break; + default: + return NULL; + } + if (addr == NULL) return NULL; - new = agp_create_memory(1); + new = agp_create_memory(pg_count); if (new == NULL) return NULL; - new->memory[0] = agp_bridge->driver->mask_memory(virt_to_phys(addr), type); - new->page_count = 1; - new->num_scratch_pages = 1; + new->memory[0] = virt_to_phys(addr); + if (pg_count == 4) { + /* kludge to get 4 physical pages for ARGB cursor */ + new->memory[1] = new->memory[0] + PAGE_SIZE; + new->memory[2] = new->memory[1] + PAGE_SIZE; + new->memory[3] = new->memory[2] + PAGE_SIZE; + } + new->page_count = pg_count; + new->num_scratch_pages = pg_count; new->type = AGP_PHYS_MEMORY; new->physical = new->memory[0]; return new; @@ -265,7 +327,11 @@ static void intel_i810_free_by_type(stru { agp_free_key(curr->key); if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0])); + if (curr->page_count == 4) + i8xx_destroy_pages(phys_to_virt(curr->memory[0])); + else + agp_bridge->driver->agp_destroy_page( + phys_to_virt(curr->memory[0])); vfree(curr->memory); } kfree(curr); @@ -281,12 +347,14 @@ static struct aper_size_info_fixed intel { {128, 32768, 5}, /* The 64M mode still requires a 128k gatt */ - {64, 16384, 5} + {64, 16384, 5}, + {256, 65536, 6}, }; static struct _intel_i830_private { struct pci_dev *i830_dev; /* device one */ volatile u8 *registers; + volatile u32 *gtt; /* I915G */ int gtt_entries; } intel_i830_private; @@ -297,20 +365,26 @@ static void intel_i830_init_gtt_entries( u8 rdct; int local = 0; static const int ddt[4] = { 0, 16, 32, 64 }; + int size; pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + /* We obtain the size of the GTT, which is also stored (for some + * reason) at the top of stolen memory. Then we add 4KB to that + * for the video BIOS popup, which is also stored in there. */ + size = agp_bridge->driver->fetch_size() + 4; + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I830_GMCH_GMS_STOLEN_512: - gtt_entries = KB(512) - KB(132); + gtt_entries = KB(512) - KB(size); break; case I830_GMCH_GMS_STOLEN_1024: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I830_GMCH_GMS_STOLEN_8192: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: rdct = INREG8(intel_i830_private.registers, @@ -326,20 +400,33 @@ static void intel_i830_init_gtt_entries( } else { switch (gmch_ctrl & I830_GMCH_GMS_MASK) { case I855_GMCH_GMS_STOLEN_1M: - gtt_entries = MB(1) - KB(132); + gtt_entries = MB(1) - KB(size); break; case I855_GMCH_GMS_STOLEN_4M: - gtt_entries = MB(4) - KB(132); + gtt_entries = MB(4) - KB(size); break; case I855_GMCH_GMS_STOLEN_8M: - gtt_entries = MB(8) - KB(132); + gtt_entries = MB(8) - KB(size); break; case I855_GMCH_GMS_STOLEN_16M: - gtt_entries = MB(16) - KB(132); + gtt_entries = MB(16) - KB(size); break; case I855_GMCH_GMS_STOLEN_32M: - gtt_entries = MB(32) - KB(132); + gtt_entries = MB(32) - KB(size); + break; + case I915_GMCH_GMS_STOLEN_48M: + /* Check it's really I915G */ + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB) + gtt_entries = MB(48) - KB(size); + else + gtt_entries = 0; break; + case I915_GMCH_GMS_STOLEN_64M: + /* Check it's really I915G */ + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB) + gtt_entries = MB(64) - KB(size); + else + gtt_entries = 0; default: gtt_entries = 0; break; @@ -421,7 +508,7 @@ static int intel_i830_fetch_size(void) agp_bridge->aperture_size_idx = 0; return(values[0].size); } else { - agp_bridge->previous_size = agp_bridge->current_size = (void *) values; + agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1); agp_bridge->aperture_size_idx = 1; return(values[1].size); } @@ -532,6 +619,161 @@ static struct agp_memory *intel_i830_all return(NULL); } +static int intel_i915_configure(void) +{ + struct aper_size_info_fixed *current_size; + u32 temp; + u16 gmch_ctrl; + int i; + + current_size = A_SIZE_FIX(agp_bridge->current_size); + + pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); + + agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + gmch_ctrl |= I830_GMCH_ENABLED; + pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); + + OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); + global_cache_flush(); + + if (agp_bridge->driver->needs_scratch_page) { + for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); + } + + return (0); +} + +static void intel_i915_cleanup(void) +{ + iounmap((void *) intel_i830_private.gtt); + iounmap((void *) intel_i830_private.registers); +} + +static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, + int type) +{ + int i,j,num_entries; + void *temp; + + temp = agp_bridge->current_size; + num_entries = A_SIZE_FIX(temp)->num_entries; + + if (pg_start < intel_i830_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", + pg_start,intel_i830_private.gtt_entries); + + printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + return (-EINVAL); + } + + if ((pg_start + mem->page_count) > num_entries) + return (-EINVAL); + + /* The i830 can't check the GTT for entries since its read only, + * depend on the caller to make the correct offset decisions. + */ + + if ((type != 0 && type != AGP_PHYS_MEMORY) || + (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) + return (-EINVAL); + + global_cache_flush(); + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + OUTREG32(intel_i830_private.gtt, j, agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); + + global_cache_flush(); + + agp_bridge->driver->tlb_flush(mem); + + return(0); +} + +static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, + int type) +{ + int i; + + global_cache_flush(); + + if (pg_start < intel_i830_private.gtt_entries) { + printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); + return (-EINVAL); + } + + for (i = pg_start; i < (mem->page_count + pg_start); i++) + OUTREG32(intel_i830_private.gtt, i, agp_bridge->scratch_page); + + global_cache_flush(); + + agp_bridge->driver->tlb_flush(mem); + + return (0); +} + +static int intel_i915_fetch_size(void) +{ + struct aper_size_info_fixed *values; + u32 temp, offset = 0; + +#define I915_256MB_ADDRESS_MASK (1<<27) + + values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); + + pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); + if (temp & I915_256MB_ADDRESS_MASK) + offset = 0; /* 128MB aperture */ + else + offset = 2; /* 256MB aperture */ + agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset); + return(values[offset].size); +} + +/* The intel i915 automatically initializes the agp aperture during POST. + * Use the memory already set aside for in the GTT. + */ +static int intel_i915_create_gatt_table(void) +{ + int page_order; + struct aper_size_info_fixed *size; + int num_entries; + u32 temp, temp2; + + size = agp_bridge->current_size; + page_order = size->page_order; + num_entries = size->num_entries; + agp_bridge->gatt_table_real = 0; + + pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); + + intel_i830_private.gtt = (volatile u32 *) ioremap(temp2, 256 * 1024); + if (!intel_i830_private.gtt) + return (-ENOMEM); + + temp &= 0xfff80000; + + intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); + if (!intel_i830_private.registers) + return (-ENOMEM); + + temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; + global_cache_flush(); + + /* we have to call this as early as possible after the MMIO base address is known */ + intel_i830_init_gtt_entries(); + + agp_bridge->gatt_table = NULL; + + agp_bridge->gatt_bus_addr = temp; + + return(0); +} + static int intel_fetch_size(void) { int i; @@ -1041,7 +1283,7 @@ static struct agp_bridge_driver intel_83 .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, - .num_aperture_sizes = 2, + .num_aperture_sizes = 3, .needs_scratch_page = TRUE, .configure = intel_i830_configure, .fetch_size = intel_i830_fetch_size, @@ -1199,6 +1441,31 @@ static struct agp_bridge_driver intel_86 .agp_destroy_page = agp_generic_destroy_page, }; +static struct agp_bridge_driver intel_915_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 3, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i915_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i810_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i915_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, +}; + + static struct agp_bridge_driver intel_7505_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, @@ -1373,9 +1640,17 @@ static int __devinit agp_intel_probe(str bridge->driver = &intel_845_driver; name = "i875"; break; + case PCI_DEVICE_ID_INTEL_82915G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82915G_IG)) { + bridge->driver = &intel_915_driver; + } else { + bridge->driver = &intel_845_driver; + } + name = "915G"; + break; case PCI_DEVICE_ID_INTEL_7505_0: bridge->driver = &intel_7505_driver; - name = "E7505"; + name = "E7505"; break; case PCI_DEVICE_ID_INTEL_7205_0: bridge->driver = &intel_7505_driver; @@ -1458,6 +1733,8 @@ static int agp_intel_resume(struct pci_d intel_845_configure(); else if (bridge->driver == &intel_830mp_driver) intel_830mp_configure(); + else if (bridge->driver == &intel_915_driver) + intel_i915_configure(); return 0; } --- linux-2.6.8-rc1/drivers/char/agp/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/agp/Kconfig 2004-07-13 17:09:18.000000000 -0700 @@ -82,7 +82,7 @@ config AGP_INTEL This option gives you AGP support for the GLX component of XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G, - 852GM, 855GM and 865G integrated graphics chipsets. + 852GM, 855GM, 865G and I915 integrated graphics chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI, or if you have any Intel integrated graphics --- linux-2.6.8-rc1/drivers/char/agp/via-agp.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/agp/via-agp.c 2004-07-13 17:09:18.000000000 -0700 @@ -348,6 +348,21 @@ static struct agp_device_ids via_agp_dev .device_id = PCI_DEVICE_ID_VIA_PX8X0_0, .chipset_name = "PM800/PN800/PM880/PN880", }, + /* KT880 */ + { + .device_id = PCI_DEVICE_ID_VIA_3269_0, + .chipset_name = "KT880", + }, + /* KTxxx/Px8xx */ + { + .device_id = PCI_DEVICE_ID_VIA_83_87XX_1, + .chipset_name = "VT83xx/VT87xx/KTxxx/Px8xx", + }, + /* P4M800 */ + { + .device_id = PCI_DEVICE_ID_VIA_3296_0, + .chipset_name = "P4M800", + }, { }, /* dummy final entry, always present */ }; @@ -457,7 +472,10 @@ static struct pci_device_id agp_via_pci_ ID(PCI_DEVICE_ID_VIA_8378_0), ID(PCI_DEVICE_ID_VIA_PT880), ID(PCI_DEVICE_ID_VIA_8783_0), - ID(PCI_DEVICE_ID_VIA_PX8X0_0), + ID(PCI_DEVICE_ID_VIA_PX8X0_0), + ID(PCI_DEVICE_ID_VIA_3269_0), + ID(PCI_DEVICE_ID_VIA_83_87XX_1), + ID(PCI_DEVICE_ID_VIA_3296_0), { } }; --- linux-2.6.8-rc1/drivers/char/cyclades.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/cyclades.c 2004-07-13 17:09:13.000000000 -0700 @@ -721,7 +721,7 @@ static unsigned char *cy_isa_addresses[] (unsigned char *) 0xDA000, (unsigned char *) 0xDC000, (unsigned char *) 0xDE000, - 0,0,0,0,0,0,0,0 + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }; #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*)) @@ -2236,7 +2236,7 @@ shutdown(struct cyclades_port * info) if (info->xmit_buf){ unsigned char * temp; temp = info->xmit_buf; - info->xmit_buf = 0; + info->xmit_buf = NULL; free_page((unsigned long) temp); } cy_writeb((u_long)base_addr+(CyCAR<xmit_buf){ unsigned char * temp; temp = info->xmit_buf; - info->xmit_buf = 0; + info->xmit_buf = NULL; free_page((unsigned long) temp); } @@ -2856,7 +2856,7 @@ cy_close(struct tty_struct *tty, struct tty->closing = 0; info->event = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { CY_UNLOCK(info, flags); if (info->close_delay) { @@ -4583,7 +4583,7 @@ cy_hangup(struct tty_struct *tty) #ifdef CY_DEBUG_COUNT printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); #endif - info->tty = 0; + info->tty = NULL; info->flags &= ~ASYNC_NORMAL_ACTIVE; wake_up_interruptible(&info->open_wait); } /* cy_hangup */ @@ -5471,7 +5471,7 @@ cy_init(void) info->line = port; info->chip_rev = 0; info->flags = STD_COM_FLAGS; - info->tty = 0; + info->tty = NULL; if (mailbox == ZO_V1) info->xmit_fifo_size = CYZ_FIFO_SIZE; else @@ -5533,7 +5533,7 @@ cy_init(void) info->card = board; info->line = port; info->flags = STD_COM_FLAGS; - info->tty = 0; + info->tty = NULL; info->xmit_fifo_size = CyMAX_CHAR_FIFO; info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS; info->cor2 = CyETC; --- linux-2.6.8-rc1/drivers/char/drm/drm_bufs.h 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/drm/drm_bufs.h 2004-07-13 17:09:13.000000000 -0700 @@ -125,7 +125,7 @@ int DRM(addmap)( struct inode *inode, st return -EINVAL; } map->mtrr = -1; - map->handle = 0; + map->handle = NULL; switch ( map->type ) { case _DRM_REGISTERS: @@ -468,7 +468,7 @@ int DRM(addbufs_agp)( struct inode *inod buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->filp = 0; + buf->filp = NULL; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), @@ -692,7 +692,7 @@ int DRM(addbufs_pci)( struct inode *inod buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->filp = 0; + buf->filp = NULL; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), --- linux-2.6.8-rc1/drivers/char/drm/drm_drv.h 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/drm/drm_drv.h 2004-07-13 17:09:21.000000000 -0700 @@ -103,10 +103,10 @@ #endif #ifndef DRIVER_PREINIT -#define DRIVER_PREINIT() +#define DRIVER_PREINIT() 0 #endif #ifndef DRIVER_POSTINIT -#define DRIVER_POSTINIT() +#define DRIVER_POSTINIT() 0 #endif #ifndef DRIVER_PRERELEASE #define DRIVER_PRERELEASE() @@ -144,6 +144,17 @@ static struct file_operations DRM(fops) } #endif +static void __exit drm_cleanup( drm_device_t *dev ); + +/** Stub information */ +struct drm_stub_info { + int (*info_register)(const char *name, struct file_operations *fops, + drm_device_t *dev); + int (*info_unregister)(int minor); + struct class_simple *drm_class; +}; +extern struct drm_stub_info DRM(stub_info); + #ifndef MODULE /** Use an additional macro to avoid preprocessor troubles */ #define DRM_OPTIONS_FUNC DRM(options) @@ -163,8 +174,9 @@ __setup( DRIVER_NAME "=", DRM_OPTIONS_FU #endif #define MAX_DEVICES 4 -static drm_device_t DRM(device)[MAX_DEVICES]; -static int DRM(numdevs) = 0; +drm_device_t DRM(device)[MAX_DEVICES]; +int DRM(numdevs) = 0; +int DRM(fb_loaded) = 0; DRIVER_FOPS; @@ -532,7 +544,7 @@ static int DRM(takedown)( drm_device_t * #endif if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.filp = 0; + dev->lock.filp = NULL; wake_up_interruptible( &dev->lock.lock_queue ); } up( &dev->struct_sem ); @@ -546,30 +558,19 @@ static struct pci_device_id DRM(pciidlis DRM(PCI_IDS) }; -static int DRM(probe)(struct pci_dev *pdev) +static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { drm_device_t *dev; -#if __HAVE_CTX_BITMAP int retcode; -#endif - int i; - int is_compat = 0; DRM_DEBUG( "\n" ); - for (i = 0; DRM(pciidlist)[i].vendor != 0; i++) { - if ((DRM(pciidlist)[i].vendor == pdev->vendor) && - (DRM(pciidlist)[i].device == pdev->device)) { - is_compat = 1; - } - } - if (is_compat == 0) - return -ENODEV; - if (DRM(numdevs) >= MAX_DEVICES) return -ENODEV; dev = &(DRM(device)[DRM(numdevs)]); + if (DRM(fb_loaded)==0) + pci_set_drvdata(pdev, dev); memset( (void *)dev, 0, sizeof(*dev) ); dev->count_lock = SPIN_LOCK_UNLOCKED; @@ -578,11 +579,16 @@ static int DRM(probe)(struct pci_dev *pd sema_init( &dev->ctxlist_sem, 1 ); if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) - return -EPERM; + { + retcode = -EPERM; + goto error_out; + } + dev->device = MKDEV(DRM_MAJOR, dev->minor ); dev->name = DRIVER_NAME; dev->pdev = pdev; + pci_enable_device(pdev); #ifdef __alpha__ dev->hose = pdev->sysdata; dev->pci_domain = dev->hose->bus->number; @@ -594,16 +600,16 @@ static int DRM(probe)(struct pci_dev *pd dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; - DRIVER_PREINIT(); + if ((retcode = DRIVER_PREINIT())) + goto error_out_unreg; #if __REALLY_HAVE_AGP dev->agp = DRM(agp_init)(); #if __MUST_HAVE_AGP if ( dev->agp == NULL ) { DRM_ERROR( "Cannot initialize the agpgart module.\n" ); - DRM(stub_unregister)(dev->minor); - DRM(takedown)( dev ); - return -EINVAL; + retcode = -EINVAL; + goto error_out_unreg; } #endif #if __REALLY_HAVE_MTRR @@ -619,13 +625,11 @@ static int DRM(probe)(struct pci_dev *pd retcode = DRM(ctxbitmap_init)( dev ); if( retcode ) { DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); - DRM(stub_unregister)(dev->minor); - DRM(takedown)( dev ); - return retcode; + goto error_out_unreg; } #endif DRM(numdevs)++; /* no errors, mark it reserved */ - + DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n", DRIVER_NAME, DRIVER_MAJOR, @@ -633,13 +637,43 @@ static int DRM(probe)(struct pci_dev *pd DRIVER_PATCHLEVEL, DRIVER_DATE, dev->minor, - pci_pretty_name(pdev)); + pci_pretty_name(pdev) + ); + + if ((retcode = DRIVER_POSTINIT())) + goto error_out_unreg; - DRIVER_POSTINIT(); + + /* + * don't move this earlier, for upcoming hotplugging support + */ + class_simple_device_add(DRM(stub_info).drm_class, + MKDEV(DRM_MAJOR, dev->minor), &pdev->dev, "card%d", dev->minor); return 0; + + error_out_unreg: + DRM(stub_unregister)(dev->minor); + DRM(takedown)(dev); + error_out: + return retcode; } +static void __exit drm_cleanup_pci(struct pci_dev *pdev) +{ + drm_device_t *dev = pci_get_drvdata(pdev); + + pci_set_drvdata(pdev, NULL); + drm_cleanup(dev); +} + +static struct pci_driver drm_driver = { + .name = DRIVER_NAME, + .id_table = DRM(pciidlist), + .probe = drm_probe, + .remove = __devexit_p(drm_cleanup_pci), +}; + /** * Module initialization. Called via init_module at module load time, or via * linux/init/main.c (this is not currently supported). @@ -656,7 +690,9 @@ static int DRM(probe)(struct pci_dev *pd static int __init drm_init( void ) { struct pci_dev *pdev = NULL; - + struct pci_driver *pdriver = NULL; + int i; + DRM_DEBUG( "\n" ); #ifdef MODULE @@ -664,10 +700,26 @@ static int __init drm_init( void ) #endif DRM(mem_init)(); - - while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - DRM(probe)(pdev); + + for (i=0; DRM(pciidlist)[i].vendor != 0; i++) { + pdev = pci_get_subsys(DRM(pciidlist[i]).vendor, DRM(pciidlist[i]).device, DRM(pciidlist[i]).subvendor, DRM(pciidlist[i]).subdevice, NULL); + if (pdev) + { + pdriver = pci_dev_driver(pdev); + if (pdriver) + { + DRM(fb_loaded)=1; + drm_probe(pdev, &DRM(pciidlist[i])); + } + else + pci_dev_put(pdev); + } } + + if (DRM(fb_loaded)==0) + pci_register_driver(&drm_driver); + else + DRM_INFO("Used old pci detect: framebuffer loaded\n"); return 0; } @@ -678,23 +730,25 @@ static int __init drm_init( void ) * * \sa drm_init(). */ -static void __exit drm_cleanup( void ) +static void __exit drm_cleanup( drm_device_t *dev ) { - drm_device_t *dev; - int i; - DRM_DEBUG( "\n" ); + if (!dev) { + DRM_ERROR("cleanup called no dev\n"); + return; + } - for (i = DRM(numdevs) - 1; i >= 0; i--) { - dev = &(DRM(device)[i]); - if ( DRM(stub_unregister)(dev->minor) ) { - DRM_ERROR( "Cannot unload module\n" ); - } else { - DRM_DEBUG("minor %d unregistered\n", dev->minor); - if (i == 0) { - DRM_INFO( "Module unloaded\n" ); - } - } + DRM(takedown)(dev); + + if (DRM(fb_loaded)==0) + pci_disable_device(dev->pdev); + + if ( DRM(stub_unregister)(dev->minor) ) { + DRM_ERROR( "Cannot unload module\n" ); + } else { + DRM_DEBUG( "minor %d unregistered\n", dev->minor); + } + #if __HAVE_CTX_BITMAP DRM(ctxbitmap_cleanup)( dev ); #endif @@ -709,22 +763,40 @@ static void __exit drm_cleanup( void ) } #endif - DRM(takedown)( dev ); #if __REALLY_HAVE_AGP - if ( dev->agp ) { - DRM(agp_uninit)(); - DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); - dev->agp = NULL; - } + if ( dev->agp ) { + DRM(agp_uninit)(); + DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); + dev->agp = NULL; + } #endif + + class_simple_device_remove(MKDEV(DRM_MAJOR, 0)); +} + +static void __exit drm_exit (void) +{ + if (DRM(fb_loaded)==1) + { + int i; + drm_device_t *dev; + + for (i = DRM(numdevs) - 1; i >= 0; i--) { + dev = &(DRM(device)[i]); + /* release the pci driver */ + if (dev->pdev) + pci_dev_put(dev->pdev); + drm_cleanup(dev); + } } - DRIVER_POSTCLEANUP(); - DRM(numdevs) = 0; + else + pci_unregister_driver(&drm_driver); + DRM_INFO( "Module unloaded\n" ); } module_init( drm_init ); -module_exit( drm_cleanup ); +module_exit( drm_exit ); /** --- linux-2.6.8-rc1/drivers/char/drm/drm_stub.h 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/drm/drm_stub.h 2004-07-13 17:09:21.000000000 -0700 @@ -35,8 +35,6 @@ #define DRM_STUB_MAXCARDS 16 /* Enough for one machine */ -static struct class_simple *drm_class; - /** Stub list. One for each minor. */ static struct drm_stub_list { const char *name; @@ -46,13 +44,6 @@ static struct drm_stub_list { static struct proc_dir_entry *DRM(stub_root); -/** Stub information */ -static struct drm_stub_info { - int (*info_register)(const char *name, struct file_operations *fops, - drm_device_t *dev); - int (*info_unregister)(int minor); -} DRM(stub_info); - /** * File \c open operation. * @@ -119,7 +110,6 @@ static int DRM(stub_getminor)(const char DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root), &DRM(stub_list)[i] .dev_root); - class_simple_device_add(drm_class, MKDEV(DRM_MAJOR, i), NULL, name); return i; } } @@ -144,16 +134,14 @@ static int DRM(stub_putminor)(int minor) DRM(proc_cleanup)(minor, DRM(stub_root), DRM(stub_list)[minor].dev_root); if (minor) { - class_simple_device_remove(MKDEV(DRM_MAJOR, minor)); inter_module_put("drm"); } else { inter_module_unregister("drm"); DRM(free)(DRM(stub_list), sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, DRM_MEM_STUB); + class_simple_destroy(DRM(stub_info).drm_class); unregister_chrdev(DRM_MAJOR, "drm"); - class_simple_device_remove(MKDEV(DRM_MAJOR, minor)); - class_simple_destroy(drm_class); } return 0; } @@ -181,27 +169,24 @@ int DRM(stub_register)(const char *name, DRM_DEBUG("\n"); ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops)); - if (!ret1) { - drm_class = class_simple_create(THIS_MODULE, "drm"); - if (IS_ERR(drm_class)) { - printk (KERN_ERR "Error creating drm class.\n"); - unregister_chrdev(DRM_MAJOR, "drm"); - return PTR_ERR(drm_class); - } - } - else if (ret1 == -EBUSY) + if (ret1 == -EBUSY) i = (struct drm_stub_info *)inter_module_get("drm"); - else + if (ret1 < 0) return -1; if (i) { /* Already registered */ DRM(stub_info).info_register = i->info_register; DRM(stub_info).info_unregister = i->info_unregister; + DRM(stub_info).drm_class = i->drm_class; DRM_DEBUG("already registered\n"); - } else if (DRM(stub_info).info_register != DRM(stub_getminor)) { - DRM(stub_info).info_register = DRM(stub_getminor); - DRM(stub_info).info_unregister = DRM(stub_putminor); + } else if (DRM(stub_info).drm_class == NULL) { + DRM(stub_info).drm_class = class_simple_create(THIS_MODULE, "drm"); + if (IS_ERR(DRM(stub_info).drm_class)) { + printk (KERN_ERR "Error creating drm class.\n"); + unregister_chrdev(DRM_MAJOR, "drm"); + return PTR_ERR(DRM(stub_info).drm_class); + } DRM_DEBUG("calling inter_module_register\n"); inter_module_register("drm", THIS_MODULE, &DRM(stub_info)); } @@ -210,7 +195,7 @@ int DRM(stub_register)(const char *name, if (ret2) { if (!ret1) { unregister_chrdev(DRM_MAJOR, "drm"); - class_simple_destroy(drm_class); + class_simple_destroy(DRM(stub_info).drm_class); } if (!i) inter_module_unregister("drm"); @@ -234,3 +219,10 @@ int DRM(stub_unregister)(int minor) return DRM(stub_info).info_unregister(minor); return -1; } + +/** Stub information */ +struct drm_stub_info DRM(stub_info) = { + .info_register = DRM(stub_getminor), + .info_unregister = DRM(stub_putminor), + .drm_class = NULL, +}; --- linux-2.6.8-rc1/drivers/char/drm/radeon_mem.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/drm/radeon_mem.c 2004-07-13 17:09:13.000000000 -0700 @@ -49,7 +49,7 @@ static struct mem_block *split_block(str goto out; newblock->start = start; newblock->size = p->size - (start - p->start); - newblock->filp = 0; + newblock->filp = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -65,7 +65,7 @@ static struct mem_block *split_block(str goto out; newblock->start = start + size; newblock->size = p->size - size; - newblock->filp = 0; + newblock->filp = NULL; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -108,7 +108,7 @@ static struct mem_block *find_block( str static void free_block( struct mem_block *p ) { - p->filp = 0; + p->filp = NULL; /* Assumes a single contiguous range. Needs a special filp in * 'heap' to stop it being subsumed. @@ -147,7 +147,7 @@ static int init_heap(struct mem_block ** blocks->start = start; blocks->size = size; - blocks->filp = 0; + blocks->filp = NULL; blocks->next = blocks->prev = *heap; memset( *heap, 0, sizeof(**heap) ); @@ -168,7 +168,7 @@ void radeon_mem_release( DRMFILE filp, s for (p = heap->next ; p != heap ; p = p->next) { if (p->filp == filp) - p->filp = 0; + p->filp = NULL; } /* Assumes a single contiguous range. Needs a special filp in @@ -201,7 +201,7 @@ void radeon_mem_takedown( struct mem_blo } DRM_FREE( *heap, sizeof(**heap) ); - *heap = 0; + *heap = NULL; } @@ -217,7 +217,7 @@ static struct mem_block **get_heap( drm_ case RADEON_MEM_REGION_FB: return &dev_priv->fb_heap; default: - return 0; + return NULL; } } --- linux-2.6.8-rc1/drivers/char/drm/radeon_state.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/drm/radeon_state.c 2004-07-13 17:09:13.000000000 -0700 @@ -2310,7 +2310,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) drm_radeon_private_t *dev_priv = dev->dev_private; drm_file_t *filp_priv; drm_device_dma_t *dma = dev->dma; - drm_buf_t *buf = 0; + drm_buf_t *buf = NULL; int idx; drm_radeon_cmd_buffer_t cmdbuf; drm_radeon_cmd_header_t header; --- linux-2.6.8-rc1/drivers/char/drm/sis_ds.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/char/drm/sis_ds.c 2004-07-13 17:09:13.000000000 -0700 @@ -165,7 +165,7 @@ memHeap_t *mmInit(int ofs, PMemBlock blocks; if (size <= 0) - return 0; + return NULL; blocks = (TMemBlock *)DRM(calloc)(1, sizeof(TMemBlock), DRM_MEM_DRIVER); if (blocks != NULL) { @@ -174,7 +174,7 @@ memHeap_t *mmInit(int ofs, blocks->free = 1; return (memHeap_t *)blocks; } else - return 0; + return NULL; } /* Checks if a pointer 'b' is part of the heap 'heap' */ --- linux-2.6.8-rc1/drivers/char/h8.c 2004-03-10 20:41:27.000000000 -0800 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,1180 +0,0 @@ -/* - * Hitachi H8/337 Microcontroller driver - * - * The H8 is used to deal with the power and thermal environment - * of a system. - * - * Fixes: - * June 1999, AV added releasing /proc/driver/h8 - * Feb 2000, Borislav Deianov - * changed queues to use list.h instead of lists.h - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "h8.h" - -#define DEBUG_H8 - -#ifdef DEBUG_H8 -#define Dprintk printk -#else -#define Dprintk -#endif - -#define XDprintk if(h8_debug==-1)printk - -/* - * The h8 device is one of the misc char devices. - */ -#define H8_MINOR_DEV 140 - -/* - * Forward declarations. - */ -static int h8_init(void); -static int h8_display_blank(void); -static int h8_display_unblank(void); - -static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); - -static int h8_get_info(char *, char **, off_t, int); - -/* - * Support Routines. - */ -static void h8_hw_init(void); -static void h8_start_new_cmd(void); -static void h8_send_next_cmd_byte(void); -static void h8_read_event_status(void); -static void h8_sync(void); -static void h8_q_cmd(u_char *, int, int); -static void h8_cmd_done(h8_cmd_q_t *qp); -static int h8_alloc_queues(void); - -static u_long h8_get_cpu_speed(void); -static int h8_get_curr_temp(u_char curr_temp[]); -static void h8_get_max_temp(void); -static void h8_get_upper_therm_thold(void); -static void h8_set_upper_therm_thold(int); -static int h8_get_ext_status(u_char stat_word[]); - -static int h8_monitor_thread(void *); - -static int h8_manage_therm(void); -static void h8_set_cpu_speed(int speed_divisor); - -static void h8_start_monitor_timer(unsigned long secs); -static void h8_activate_monitor(unsigned long unused); - -/* in arch/alpha/kernel/lca.c */ -extern void lca_clock_print(void); -extern int lca_get_clock(void); -extern void lca_clock_fiddle(int); - -static void h8_set_event_mask(int); -static void h8_clear_event_mask(int); - -/* - * Driver structures - */ - -static struct timer_list h8_monitor_timer; -static int h8_monitor_timer_active = 0; - -static char driver_version[] = "X0.0";/* no spaces */ - -static union intr_buf intrbuf; -static int intr_buf_ptr; -static union intr_buf xx; -static u_char last_temp; - -/* - * I/O Macros for register reads and writes. - */ -#define H8_READ(a) inb((a)) -#define H8_WRITE(d,a) outb((d),(a)) - -#define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF) -#define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF) -#define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF) -#define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF) - -static unsigned int h8_base = H8_BASE_ADDR; -static unsigned int h8_irq = H8_IRQ; -static unsigned int h8_state = H8_IDLE; -static unsigned int h8_index = -1; -static unsigned int h8_enabled = 0; - -static LIST_HEAD(h8_actq); -static LIST_HEAD(h8_cmdq); -static LIST_HEAD(h8_freeq); - -/* - * Globals used in thermal control of Alphabook1. - */ -static int cpu_speed_divisor = -1; -static int h8_event_mask = 0; -static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait); -static unsigned int h8_command_mask = 0; -static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; -static int h8_uthermal_window = UTH_HYSTERESIS; -static int h8_debug = 0xfffffdfc; -static int h8_ldamp = MHZ_115; -static int h8_udamp = MHZ_57; -static u_char h8_current_temp = 0; -static u_char h8_system_temp = 0; -static int h8_sync_channel = 0; -static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait); -static int h8_init_performed; - -/* CPU speeds and clock divisor values */ -static int speed_tab[6] = {230, 153, 115, 57, 28, 14}; - -/* - * H8 interrupt handler - */ -static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - u_char stat_reg, data_reg; - h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); - - stat_reg = H8_GET_STATUS; - data_reg = H8_READ_DATA; - - XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg); - - switch (h8_state) { - /* Response to an asynchronous event. */ - case H8_IDLE: { /* H8_IDLE */ - if (stat_reg & H8_OFULL) { - if (data_reg == H8_INTR) { - h8_state = H8_INTR_MODE; - /* Executing a command to determine what happened. */ - WRITE_CMD(H8_RD_EVENT_STATUS); - intr_buf_ptr = 1; - WRITE_CMD(H8_RD_EVENT_STATUS); - } else { - Dprintk("h8_intr: idle stat 0x%x data 0x%x\n", - stat_reg, data_reg); - } - } else { - Dprintk("h8_intr: bogus interrupt\n"); - } - break; - } - case H8_INTR_MODE: { /* H8_INTR_MODE */ - XDprintk("H8 intr/intr_mode\n"); - if (data_reg == H8_BYTE_LEVEL_ACK) { - return; - } else if (data_reg == H8_CMD_ACK) { - return; - } else { - intrbuf.byte[intr_buf_ptr] = data_reg; - if(!intr_buf_ptr) { - h8_state = H8_IDLE; - h8_read_event_status(); - } - intr_buf_ptr--; - } - break; - } - /* Placed in this state by h8_start_new_cmd(). */ - case H8_XMIT: { /* H8_XMIT */ - XDprintk("H8 intr/xmit\n"); - /* If a byte level acknowledgement has been received */ - if (data_reg == H8_BYTE_LEVEL_ACK) { - XDprintk("H8 intr/xmit BYTE ACK\n"); - qp->nacks++; - if (qp->nacks > qp->ncmd) - if(h8_debug & 0x1) - Dprintk("h8intr: bogus # of acks!\n"); - /* - * If the number of bytes sent is less than the total - * number of bytes in the command. - */ - if (qp->cnt < qp->ncmd) { - h8_send_next_cmd_byte(); - } - return; - /* If the complete command has produced an acknowledgement. */ - } else if (data_reg == H8_CMD_ACK) { - XDprintk("H8 intr/xmit CMD ACK\n"); - /* If there are response bytes */ - if (qp->nrsp) - h8_state = H8_RCV; - else - h8_state = H8_IDLE; - qp->cnt = 0; - return; - /* Error, need to start over with a clean slate. */ - } else if (data_reg == H8_NACK) { - XDprintk("h8_intr: NACK received restarting command\n"); - qp->nacks = 0; - qp->cnt = 0; - h8_state = H8_IDLE; - WRITE_CMD(H8_SYNC); - return; - } else { - Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg); - return; - } - break; - } - case H8_RESYNC: { /* H8_RESYNC */ - XDprintk("H8 intr/resync\n"); - if (data_reg == H8_BYTE_LEVEL_ACK) { - return; - } else if (data_reg == H8_SYNC_BYTE) { - h8_state = H8_IDLE; - if (!list_empty(&h8_actq)) - h8_send_next_cmd_byte(); - } else { - Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); - return; - } - break; - } - case H8_RCV: { /* H8_RCV */ - XDprintk("H8 intr/rcv\n"); - if (qp->cnt < qp->nrsp) { - qp->rcvbuf[qp->cnt] = data_reg; - qp->cnt++; - /* If command reception finished. */ - if (qp->cnt == qp->nrsp) { - h8_state = H8_IDLE; - list_del(&qp->link); - h8_cmd_done (qp); - /* More commands to send over? */ - if (!list_empty(&h8_cmdq)) - h8_start_new_cmd(); - } - return; - } else { - Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]); - } - break; - } - default: /* default */ - Dprintk("H8 intr/unknown\n"); - break; - } - return; -} - -static void __exit h8_cleanup (void) -{ - remove_proc_entry("driver/h8", NULL); - release_region(h8_base, 8); - free_irq(h8_irq, NULL); -} - -static int __init h8_init(void) -{ - if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL)) - { - printk(KERN_ERR "H8: error: IRQ %d is not free\n", h8_irq); - return -EIO; - } - printk(KERN_INFO "H8 at 0x%x IRQ %d\n", h8_base, h8_irq); - - if (!request_region(h8_base, 8, "h8")) - { - free_irq(h8_irq, NULL); - return -EIO; - } - - create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); - - h8_alloc_queues(); - - h8_hw_init(); - - kernel_thread(h8_monitor_thread, NULL, 0); - - return 0; -} - -module_init(h8_init); -module_exit(h8_cleanup); - -static void __init h8_hw_init(void) -{ - u_char buf[H8_MAX_CMD_SIZE]; - - /* set CPU speed to max for booting */ - h8_set_cpu_speed(MHZ_230); - - /* - * Initialize the H8 - */ - h8_sync(); /* activate interrupts */ - - /* To clear conditions left by console */ - h8_read_event_status(); - - /* Perform a conditioning read */ - buf[0] = H8_DEVICE_CONTROL; - buf[1] = 0xff; - buf[2] = 0x0; - h8_q_cmd(buf, 3, 1); - - /* Turn on built-in and external mice, capture power switch */ - buf[0] = H8_DEVICE_CONTROL; - buf[1] = 0x0; - buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR | - /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND; - h8_q_cmd(buf, 3, 1); - - h8_enabled = 1; - return; -} - -static int h8_get_info(char *buf, char **start, off_t fpos, int length) -{ -#ifdef CONFIG_PROC_FS - char *p; - - if (!h8_enabled) - return 0; - p = buf; - - - /* - 0) Linux driver version (this will change if format changes) - 1) - 2) - 3) - 4) - */ - - p += sprintf(p, "%s \n", - driver_version - ); - - return p - buf; -#else - return 0; -#endif -} - -/* Called from console driver -- must make sure h8_enabled. */ -static int h8_display_blank(void) -{ -#ifdef CONFIG_H8_DISPLAY_BLANK - int error; - - if (!h8_enabled) - return 0; - error = h8_set_display_power_state(H8_STATE_STANDBY); - if (error == H8_SUCCESS) - return 1; - h8_error("set display standby", error); -#endif - return 0; -} - -/* Called from console driver -- must make sure h8_enabled. */ -static int h8_display_unblank(void) -{ -#ifdef CONFIG_H8_DISPLAY_BLANK - int error; - - if (!h8_enabled) - return 0; - error = h8_set_display_power_state(H8_STATE_READY); - if (error == H8_SUCCESS) - return 1; - h8_error("set display ready", error); -#endif - return 0; -} - -static int h8_alloc_queues(void) -{ - h8_cmd_q_t *qp; - unsigned long flags; - int i; - - qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT), - GFP_KERNEL); - - if (!qp) { - printk(KERN_ERR "H8: could not allocate memory for command queue\n"); - return(0); - } - /* add to the free queue */ - save_flags(flags); cli(); - for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) { - /* place each at front of freeq */ - list_add(&qp[i].link, &h8_freeq); - } - restore_flags(flags); - return (1); -} - -/* - * Basic means by which commands are sent to the H8. - */ -void -h8_q_cmd(u_char *cmd, int cmd_size, int resp_size) -{ - h8_cmd_q_t *qp; - unsigned long flags; - int i; - - /* get cmd buf */ - save_flags(flags); cli(); - while (list_empty(&h8_freeq)) { - Dprintk("H8: need to allocate more cmd buffers\n"); - restore_flags(flags); - h8_alloc_queues(); - save_flags(flags); cli(); - } - /* get first element from queue */ - qp = list_entry(h8_freeq.next, h8_cmd_q_t, link); - list_del(&qp->link); - - restore_flags(flags); - - /* fill it in */ - for (i = 0; i < cmd_size; i++) - qp->cmdbuf[i] = cmd[i]; - qp->ncmd = cmd_size; - qp->nrsp = resp_size; - - /* queue it at the end of the cmd queue */ - save_flags(flags); cli(); - - /* XXX this actually puts it at the start of cmd queue, bug? */ - list_add(&qp->link, &h8_cmdq); - - restore_flags(flags); - - h8_start_new_cmd(); -} - -void -h8_start_new_cmd(void) -{ - unsigned long flags; - h8_cmd_q_t *qp; - - save_flags(flags); cli(); - if (h8_state != H8_IDLE) { - if (h8_debug & 0x1) - Dprintk("h8_start_new_cmd: not idle\n"); - restore_flags(flags); - return; - } - - if (!list_empty(&h8_actq)) { - Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); - restore_flags(flags); - return; - } - - if (list_empty(&h8_cmdq)) { - Dprintk("h8_start_new_cmd: no command to dequeue\n"); - restore_flags(flags); - return; - } - /* - * Take first command off of the command queue and put - * it on the active queue. - */ - qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link); - list_del(&qp->link); - /* XXX should this go to the end of the active queue? */ - list_add(&qp->link, &h8_actq); - h8_state = H8_XMIT; - if (h8_debug & 0x1) - Dprintk("h8_start_new_cmd: Starting a command\n"); - - qp->cnt = 1; - WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */ - - restore_flags(flags); - return; -} - -void -h8_send_next_cmd_byte(void) -{ - h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); - int cnt; - - cnt = qp->cnt; - qp->cnt++; - - if (h8_debug & 0x1) - Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n", - cnt, qp->cmdbuf[cnt]); - - if (cnt) { - WRITE_DATA(qp->cmdbuf[cnt]); - } else { - WRITE_CMD(qp->cmdbuf[cnt]); - } - return; -} - -/* - * Synchronize H8 communications channel for command transmission. - */ -void -h8_sync(void) -{ - u_char buf[H8_MAX_CMD_SIZE]; - - buf[0] = H8_SYNC; - buf[1] = H8_SYNC_BYTE; - h8_q_cmd(buf, 2, 1); -} - -/* - * Responds to external interrupt. Reads event status word and - * decodes type of interrupt. - */ -void -h8_read_event_status(void) -{ - - if(h8_debug & 0x200) - printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word); - - /* - * Power related items - */ - if (intrbuf.word & H8_DC_CHANGE) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n"); - /* see if dc added or removed, set batt/dc flag, send event */ - - h8_set_event_mask(H8_MANAGE_BATTERY); - wake_up(&h8_monitor_wait); - } - - if (intrbuf.word & H8_POWER_BUTTON) { - printk(KERN_CRIT "Power switch pressed - please wait - preparing to power -off\n"); - h8_set_event_mask(H8_POWER_BUTTON); - wake_up(&h8_monitor_wait); - } - - /* - * Thermal related items - */ - if (intrbuf.word & H8_THERMAL_THRESHOLD) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLD\n"); - h8_set_event_mask(H8_MANAGE_UTHERM); - wake_up(&h8_monitor_wait); - } - - /* - * nops -for now - */ - if (intrbuf.word & H8_DOCKING_STATION_STATUS) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n"); - /* read_ext_status */ - } - if (intrbuf.word & H8_EXT_BATT_STATUS) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n"); - - } - if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n"); - - } - if (intrbuf.word & H8_BATT_CHANGE_OVER) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n"); - - } - if (intrbuf.word & H8_WATCHDOG) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n"); - /* nop */ - } - if (intrbuf.word & H8_SHUTDOWN) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n"); - /* nop */ - } - if (intrbuf.word & H8_KEYBOARD) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n"); - /* nop */ - } - if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n"); - /* read_ext_status*/ - } - if (intrbuf.word & H8_INT_BATT_LOW) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post - /* event, warn user */ - } - if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n"); - /* nop - happens often */ - } - if (intrbuf.word & H8_INT_BATT_STATUS) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n"); - - } - if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n"); - /* nop - happens often */ - } - if (intrbuf.word & H8_EXT_BATT_LOW) { - if(h8_debug & 0x4) - printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n"); - /*if no internal, post event, warn user */ - /* else nop */ - } - - return; -} - -/* - * Function called when H8 has performed requested command. - */ -static void -h8_cmd_done(h8_cmd_q_t *qp) -{ - - /* what to do */ - switch (qp->cmdbuf[0]) { - case H8_SYNC: - if (h8_debug & 0x40000) - printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n", - qp->rcvbuf[0]); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_SN: - case H8_RD_ENET_ADDR: - printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", - qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], - qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_HW_VER: - case H8_RD_MIC_VER: - case H8_RD_MAX_TEMP: - printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %d\n", - qp->rcvbuf[0], qp->rcvbuf[1]); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_MIN_TEMP: - printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %d\n", - qp->rcvbuf[0], qp->rcvbuf[1]); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_CURR_TEMP: - h8_sync_channel |= H8_RD_CURR_TEMP; - xx.byte[0] = qp->rcvbuf[0]; - xx.byte[1] = qp->rcvbuf[1]; - wake_up(&h8_sync_wait); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_SYS_VARIENT: - case H8_RD_PWR_ON_CYCLES: - printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command done\n"); - break; - - case H8_RD_PWR_ON_SECS: - printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n"); - break; - - case H8_RD_RESET_STATUS: - case H8_RD_PWR_DN_STATUS: - case H8_RD_EVENT_STATUS: - case H8_RD_ROM_CKSM: - case H8_RD_EXT_STATUS: - xx.byte[1] = qp->rcvbuf[0]; - xx.byte[0] = qp->rcvbuf[1]; - h8_sync_channel |= H8_GET_EXT_STATUS; - wake_up(&h8_sync_wait); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_USER_CFG: - case H8_RD_INT_BATT_VOLT: - case H8_RD_DC_INPUT_VOLT: - case H8_RD_HORIZ_PTR_VOLT: - case H8_RD_VERT_PTR_VOLT: - case H8_RD_EEPROM_STATUS: - case H8_RD_ERR_STATUS: - case H8_RD_NEW_BUSY_SPEED: - case H8_RD_CONFIG_INTERFACE: - case H8_RD_INT_BATT_STATUS: - printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %x\n", - qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); - list_add(&qp->link, &h8_freeq); - break; - - case H8_RD_EXT_BATT_STATUS: - case H8_RD_PWR_UP_STATUS: - case H8_RD_EVENT_STATUS_MASK: - case H8_CTL_EMU_BITPORT: - case H8_DEVICE_CONTROL: - if(h8_debug & 0x20000) { - printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%x\n", - qp->rcvbuf[0]); - } - list_add(&qp->link, &h8_freeq); - break; - - case H8_CTL_TFT_BRT_DC: - case H8_CTL_WATCHDOG: - case H8_CTL_MIC_PROT: - case H8_CTL_INT_BATT_CHG: - case H8_CTL_EXT_BATT_CHG: - case H8_CTL_MARK_SPACE: - case H8_CTL_MOUSE_SENSITIVITY: - case H8_CTL_DIAG_MODE: - case H8_CTL_IDLE_AND_BUSY_SPDS: - printk(KERN_DEBUG "H8: Idle and busy speed command done\n"); - break; - - case H8_CTL_TFT_BRT_BATT: - case H8_CTL_UPPER_TEMP: - if(h8_debug & 0x10) { - XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n", - qp->rcvbuf[0]); - } - list_add(&qp->link, &h8_freeq); - break; - - case H8_CTL_LOWER_TEMP: - case H8_CTL_TEMP_CUTOUT: - case H8_CTL_WAKEUP: - case H8_CTL_CHG_THRESHOLD: - case H8_CTL_TURBO_MODE: - case H8_SET_DIAG_STATUS: - case H8_SOFTWARE_RESET: - case H8_RECAL_PTR: - case H8_SET_INT_BATT_PERCENT: - case H8_WRT_CFG_INTERFACE_REG: - case H8_WRT_EVENT_STATUS_MASK: - case H8_ENTER_POST_MODE: - case H8_EXIT_POST_MODE: - case H8_RD_EEPROM: - case H8_WRT_EEPROM: - case H8_WRT_TO_STATUS_DISP: - printk("H8: Write IO status display command done\n"); - break; - - case H8_DEFINE_SPC_CHAR: - case H8_DEFINE_TABLE_STRING_ENTRY: - case H8_PERFORM_EMU_CMD: - case H8_EMU_RD_REG: - case H8_EMU_WRT_REG: - case H8_EMU_RD_RAM: - case H8_EMU_WRT_RAM: - case H8_BQ_RD_REG: - case H8_BQ_WRT_REG: - case H8_PWR_OFF: - printk (KERN_DEBUG "H8: misc command completed\n"); - break; - } - return; -} - -/* - * Retrieve the current CPU temperature and case temperature. Provides - * the feedback for the thermal control algorithm. Synchcronized via - * sleep() for priority so that no other actions in the process will take - * place before the data becomes available. - */ -int -h8_get_curr_temp(u_char curr_temp[]) -{ - u_char buf[H8_MAX_CMD_SIZE]; - unsigned long flags; - - memset(buf, 0, H8_MAX_CMD_SIZE); - buf[0] = H8_RD_CURR_TEMP; - - h8_q_cmd(buf, 1, 2); - - save_flags(flags); cli(); - - while((h8_sync_channel & H8_RD_CURR_TEMP) == 0) - sleep_on(&h8_sync_wait); - - restore_flags(flags); - - h8_sync_channel &= ~H8_RD_CURR_TEMP; - curr_temp[0] = xx.byte[0]; - curr_temp[1] = xx.byte[1]; - xx.word = 0; - - if(h8_debug & 0x8) - printk("H8: curr CPU temp %d, Sys temp %d\n", - curr_temp[0], curr_temp[1]); - return 0; -} - -static void -h8_get_max_temp(void) -{ - u_char buf[H8_MAX_CMD_SIZE]; - - buf[0] = H8_RD_MAX_TEMP; - h8_q_cmd(buf, 1, 2); -} - -/* - * Assigns an upper limit to the value of the H8 thermal interrupt. - * As an example setting a value of 115 F here will cause the - * interrupt to trigger when the CPU temperature reaches 115 F. - */ -static void -h8_set_upper_therm_thold(int thold) -{ - u_char buf[H8_MAX_CMD_SIZE]; - - /* write 0 to reinitialize interrupt */ - buf[0] = H8_CTL_UPPER_TEMP; - buf[1] = 0x0; - buf[2] = 0x0; - h8_q_cmd(buf, 3, 1); - - /* Do it for real */ - buf[0] = H8_CTL_UPPER_TEMP; - buf[1] = 0x0; - buf[2] = thold; - h8_q_cmd(buf, 3, 1); -} - -static void -h8_get_upper_therm_thold(void) -{ - u_char buf[H8_MAX_CMD_SIZE]; - - buf[0] = H8_CTL_UPPER_TEMP; - buf[1] = 0xff; - buf[2] = 0; - h8_q_cmd(buf, 3, 1); -} - -/* - * The external status word contains information on keyboard controller, - * power button, changes in external batt status, change in DC state, - * docking station, etc. General purpose querying use. - */ -int -h8_get_ext_status(u_char stat_word[]) -{ - u_char buf[H8_MAX_CMD_SIZE]; - unsigned long flags; - - memset(buf, 0, H8_MAX_CMD_SIZE); - buf[0] = H8_RD_EXT_STATUS; - - h8_q_cmd(buf, 1, 2); - - save_flags(flags); cli(); - - while((h8_sync_channel & H8_GET_EXT_STATUS) == 0) - sleep_on(&h8_sync_wait); - - restore_flags(flags); - - h8_sync_channel &= ~H8_GET_EXT_STATUS; - stat_word[0] = xx.byte[0]; - stat_word[1] = xx.byte[1]; - xx.word = 0; - - if(h8_debug & 0x8) - printk("H8: curr ext status %x, %x\n", - stat_word[0], stat_word[1]); - - return 0; -} - -/* - * Thread attached to task 0 manages thermal/physcial state of Alphabook. - * When a condition is detected by the interrupt service routine, the - * isr does a wakeup() on h8_monitor_wait. The mask value is then - * screened for the appropriate action. - */ - -int -h8_monitor_thread(void * unused) -{ - u_char curr_temp[2]; - - /* - * Need a logic based safety valve here. During boot when this thread is - * started and the thermal interrupt is not yet initialized this logic - * checks the temperature and acts accordingly. When this path is acted - * upon system boot is painfully slow, however, the priority associated - * with overheating is high enough to warrant this action. - */ - h8_get_curr_temp(curr_temp); - - printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]); - - if(curr_temp[0] >= h8_uthermal_threshold) { - h8_set_event_mask(H8_MANAGE_UTHERM); - h8_manage_therm(); - } else { - /* - * Arm the upper thermal limit of the H8 so that any temp in - * excess will trigger the thermal control mechanism. - */ - h8_set_upper_therm_thold(h8_uthermal_threshold); - } - - for(;;) { - sleep_on(&h8_monitor_wait); - - if(h8_debug & 0x2) - printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n", - h8_event_mask); - - if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) { - h8_manage_therm(); - } - -#if 0 - if (h8_event_mask & H8_POWER_BUTTON) { - h8_system_down(); - } - - /* - * If an external DC supply is removed or added make - * appropriate CPU speed adjustments. - */ - if (h8_event_mask & H8_MANAGE_BATTERY) { - h8_run_level_3_manage(H8_RUN); - h8_clear_event_mask(H8_MANAGE_BATTERY); - } -#endif - } -} - -/* - * Function implements the following policy. When the machine is booted - * the system is set to run at full clock speed. When the upper thermal - * threshold is reached as a result of full clock a damping factor is - * applied to cool off the cpu. The default value is one quarter clock - * (57 Mhz). When as a result of this cooling a temperature lower by - * hmc_uthermal_window is reached, the machine is reset to a higher - * speed, one half clock (115 Mhz). One half clock is maintained until - * the upper thermal threshold is again reached restarting the cycle. - */ - -int -h8_manage_therm(void) -{ - u_char curr_temp[2]; - - if(h8_event_mask & H8_MANAGE_UTHERM) { - /* Upper thermal interrupt received, need to cool down. */ - if(h8_debug & 0x10) - printk(KERN_WARNING "H8: Thermal threshold %d F reached\n", - h8_uthermal_threshold); - h8_set_cpu_speed(h8_udamp); - h8_clear_event_mask(H8_MANAGE_UTHERM); - h8_set_event_mask(H8_MANAGE_LTHERM); - /* Check again in 30 seconds for CPU temperature */ - h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); - } else if (h8_event_mask & H8_MANAGE_LTHERM) { - /* See how cool the system has become as a result - of the reduction in speed. */ - h8_get_curr_temp(curr_temp); - last_temp = curr_temp[0]; - if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window)) - { - /* System cooling has progressed to a point - that the CPU may be sped up. */ - h8_set_upper_therm_thold(h8_uthermal_threshold); - h8_set_cpu_speed(h8_ldamp); /* adjustable */ - if(h8_debug & 0x10) - printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n", - h8_ldamp); - h8_clear_event_mask(H8_MANAGE_LTHERM); - } - else /* Not cool enough yet, check again in 30 seconds. */ - h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); - } else { - - } - return 0; -} - -/* - * Function conditions the value of global_rpb_counter before - * calling the primitive which causes the actual speed change. - */ -void -h8_set_cpu_speed(int speed_divisor) -{ - -#ifdef NOT_YET -/* - * global_rpb_counter is consumed by alpha_delay() in determining just - * how much time to delay. It is necessary that the number of microseconds - * in DELAY(n) be kept consistent over a variety of CPU clock speeds. - * To that end global_rpb_counter is here adjusted. - */ - - switch (speed_divisor) { - case 0: - global_rpb_counter = rpb->rpb_counter * 2L; - break; - case 1: - global_rpb_counter = rpb->rpb_counter * 4L / 3L ; - break; - case 3: - global_rpb_counter = rpb->rpb_counter / 2L; - break; - case 4: - global_rpb_counter = rpb->rpb_counter / 4L; - break; - case 5: - global_rpb_counter = rpb->rpb_counter / 8L; - break; - /* - * This case most commonly needed for cpu_speed_divisor - * of 2 which is the value assigned by the firmware. - */ - default: - global_rpb_counter = rpb->rpb_counter; - break; - } -#endif /* NOT_YET */ - - if(h8_debug & 0x8) - printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n", - speed_tab[speed_divisor]); - - /* Make the actual speed change */ - lca_clock_fiddle(speed_divisor); -} - -/* - * Gets value stored in rpb representing CPU clock speed and adjusts this - * value based on the current clock speed divisor. - */ -u_long -h8_get_cpu_speed(void) -{ - u_long speed = 0; - u_long counter; - -#ifdef NOT_YET - counter = rpb->rpb_counter / 1000000L; - - switch (alphabook_get_clock()) { - case 0: - speed = counter * 2L; - break; - case 1: - speed = counter * 4L / 3L ; - break; - case 2: - speed = counter; - break; - case 3: - speed = counter / 2L; - break; - case 4: - speed = counter / 4L; - break; - case 5: - speed = counter / 8L; - break; - default: - break; - } - if(h8_debug & 0x8) - printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed); -#endif /* NOT_YET */ - return speed; -} - -static void -h8_activate_monitor(unsigned long unused) -{ - unsigned long flags; - - save_flags(flags); cli(); - h8_monitor_timer_active = 0; - restore_flags(flags); - - wake_up(&h8_monitor_wait); -} - -static void -h8_start_monitor_timer(unsigned long secs) -{ - unsigned long flags; - - if (h8_monitor_timer_active) - return; - - save_flags(flags); cli(); - h8_monitor_timer_active = 1; - restore_flags(flags); - - init_timer(&h8_monitor_timer); - h8_monitor_timer.function = h8_activate_monitor; - h8_monitor_timer.expires = secs * HZ + jiffies; - add_timer(&h8_monitor_timer); -} - -static void h8_set_event_mask(int mask) -{ - unsigned long flags; - - save_flags(flags); cli(); - h8_event_mask |= mask; - restore_flags(flags); -} - -static void h8_clear_event_mask(int mask) -{ - unsigned long flags; - - save_flags(flags); cli(); - h8_event_mask &= (~mask); - restore_flags(flags); -} - -MODULE_LICENSE("GPL"); --- linux-2.6.8-rc1/drivers/char/h8.h 2003-06-14 12:18:06.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,246 +0,0 @@ -/* - */ - -#ifndef __H8_H__ -#define __H8_H__ - -/* - * Register address and offsets - */ -#define H8_BASE_ADDR 0x170 /* default */ -#define H8_IRQ 9 /* default */ -#define H8_STATUS_REG_OFF 0x4 -#define H8_CMD_REG_OFF 0x4 -#define H8_DATA_REG_OFF 0x0 - - -/* H8 register bit definitions */ -/* status register */ -#define H8_OFULL 0x1 /* output data register full */ -#define H8_IFULL 0x2 /* input data register full */ -#define H8_CMD 0x8 /* command / not data */ - -#define H8_INTR 0xfa -#define H8_NACK 0xfc -#define H8_BYTE_LEVEL_ACK 0xfd -#define H8_CMD_ACK 0xfe -#define H8_SYNC_BYTE 0x99 - -/* - * H8 command definitions - */ -/* System info commands */ -#define H8_SYNC 0x0 -#define H8_RD_SN 0x1 -#define H8_RD_ENET_ADDR 0x2 -#define H8_RD_HW_VER 0x3 -#define H8_RD_MIC_VER 0x4 -#define H8_RD_MAX_TEMP 0x5 -#define H8_RD_MIN_TEMP 0x6 -#define H8_RD_CURR_TEMP 0x7 -#define H8_RD_SYS_VARIENT 0x8 -#define H8_RD_PWR_ON_CYCLES 0x9 -#define H8_RD_PWR_ON_SECS 0xa -#define H8_RD_RESET_STATUS 0xb -#define H8_RD_PWR_DN_STATUS 0xc -#define H8_RD_EVENT_STATUS 0xd -#define H8_RD_ROM_CKSM 0xe -#define H8_RD_EXT_STATUS 0xf -#define H8_RD_USER_CFG 0x10 -#define H8_RD_INT_BATT_VOLT 0x11 -#define H8_RD_DC_INPUT_VOLT 0x12 -#define H8_RD_HORIZ_PTR_VOLT 0x13 -#define H8_RD_VERT_PTR_VOLT 0x14 -#define H8_RD_EEPROM_STATUS 0x15 -#define H8_RD_ERR_STATUS 0x16 -#define H8_RD_NEW_BUSY_SPEED 0x17 -#define H8_RD_CONFIG_INTERFACE 0x18 -#define H8_RD_INT_BATT_STATUS 0x19 -#define H8_RD_EXT_BATT_STATUS 0x1a -#define H8_RD_PWR_UP_STATUS 0x1b -#define H8_RD_EVENT_STATUS_MASK 0x56 - -/* Read/write/modify commands */ -#define H8_CTL_EMU_BITPORT 0x32 -#define H8_DEVICE_CONTROL 0x21 -#define H8_CTL_TFT_BRT_DC 0x22 -#define H8_CTL_WATCHDOG 0x23 -#define H8_CTL_MIC_PROT 0x24 -#define H8_CTL_INT_BATT_CHG 0x25 -#define H8_CTL_EXT_BATT_CHG 0x26 -#define H8_CTL_MARK_SPACE 0x27 -#define H8_CTL_MOUSE_SENSITIVITY 0x28 -#define H8_CTL_DIAG_MODE 0x29 -#define H8_CTL_IDLE_AND_BUSY_SPDS 0x2a -#define H8_CTL_TFT_BRT_BATT 0x2b -#define H8_CTL_UPPER_TEMP 0x2c -#define H8_CTL_LOWER_TEMP 0x2d -#define H8_CTL_TEMP_CUTOUT 0x2e -#define H8_CTL_WAKEUP 0x2f -#define H8_CTL_CHG_THRESHOLD 0x30 -#define H8_CTL_TURBO_MODE 0x31 -#define H8_SET_DIAG_STATUS 0x40 -#define H8_SOFTWARE_RESET 0x41 -#define H8_RECAL_PTR 0x42 -#define H8_SET_INT_BATT_PERCENT 0x43 -#define H8_WRT_CFG_INTERFACE_REG 0x45 -#define H8_WRT_EVENT_STATUS_MASK 0x57 -#define H8_ENTER_POST_MODE 0x46 -#define H8_EXIT_POST_MODE 0x47 - -/* Block transfer commands */ -#define H8_RD_EEPROM 0x50 -#define H8_WRT_EEPROM 0x51 -#define H8_WRT_TO_STATUS_DISP 0x52 -#define H8_DEFINE_SPC_CHAR 0x53 - -/* Generic commands */ -#define H8_DEFINE_TABLE_STRING_ENTRY 0x60 - -/* Battery control commands */ -#define H8_PERFORM_EMU_CMD 0x70 -#define H8_EMU_RD_REG 0x71 -#define H8_EMU_WRT_REG 0x72 -#define H8_EMU_RD_RAM 0x73 -#define H8_EMU_WRT_RAM 0x74 -#define H8_BQ_RD_REG 0x75 -#define H8_BQ_WRT_REG 0x76 - -/* System admin commands */ -#define H8_PWR_OFF 0x80 - -/* - * H8 command related definitions - */ - -/* device control argument bits */ -#define H8_ENAB_EXTSMI 0x1 -#define H8_DISAB_IRQ 0x2 -#define H8_ENAB_FLASH_WRT 0x4 -#define H8_ENAB_THERM 0x8 -#define H8_ENAB_INT_PTR 0x10 -#define H8_ENAB_LOW_SPD_IND 0x20 -#define H8_ENAB_EXT_PTR 0x40 -#define H8_DISAB_PWR_OFF_SW 0x80 -#define H8_POWER_OFF 0x80 - -/* H8 read event status bits */ -#define H8_DC_CHANGE 0x1 -#define H8_INT_BATT_LOW 0x2 -#define H8_INT_BATT_CHARGE_THRESHOLD 0x4 -#define H8_INT_BATT_CHARGE_STATE 0x8 -#define H8_INT_BATT_STATUS 0x10 -#define H8_EXT_BATT_CHARGE_STATE 0x20 -#define H8_EXT_BATT_LOW 0x40 -#define H8_EXT_BATT_STATUS 0x80 -#define H8_THERMAL_THRESHOLD 0x100 -#define H8_WATCHDOG 0x200 -#define H8_DOCKING_STATION_STATUS 0x400 -#define H8_EXT_MOUSE_OR_CASE_SWITCH 0x800 -#define H8_KEYBOARD 0x1000 -#define H8_BATT_CHANGE_OVER 0x2000 -#define H8_POWER_BUTTON 0x4000 -#define H8_SHUTDOWN 0x8000 - -/* H8 control idle and busy speeds */ -#define H8_SPEED_LOW 0x1 -#define H8_SPEED_MED 0x2 -#define H8_SPEED_HI 0x3 -#define H8_SPEED_LOCKED 0x80 - -#define H8_MAX_CMD_SIZE 18 -#define H8_Q_ALLOC_AMOUNT 10 - -/* H8 state field values */ -#define H8_IDLE 1 -#define H8_XMIT 2 -#define H8_RCV 3 -#define H8_RESYNC 4 -#define H8_INTR_MODE 5 - -/* Mask values for control functions */ -#define UTH_HYSTERESIS 5 -#define DEFAULT_UTHERMAL_THRESHOLD 115 -#define H8_TIMEOUT_INTERVAL 30 -#define H8_RUN 4 - -#define H8_GET_MAX_TEMP 0x1 -#define H8_GET_CURR_TEMP 0x2 -#define H8_GET_UPPR_THRMAL_THOLD 0x4 -#define H8_GET_ETHERNET_ADDR 0x8 -#define H8_SYNC_OP 0x10 -#define H8_SET_UPPR_THRMAL_THOLD 0x20 -#define H8_GET_INT_BATT_STAT 0x40 -#define H8_GET_CPU_SPD 0x80 -#define H8_MANAGE_UTHERM 0x100 -#define H8_MANAGE_LTHERM 0x200 -#define H8_HALT 0x400 -#define H8_CRASH 0x800 -#define H8_GET_EXT_STATUS 0x10000 -#define H8_MANAGE_QUIET 0x20000 -#define H8_MANAGE_SPEEDUP 0x40000 -#define H8_MANAGE_BATTERY 0x80000 -#define H8_SYSTEM_DELAY_TEST 0x100000 -#define H8_POWER_SWITCH_TEST 0x200000 - -/* CPU speeds and clock divisor values */ -#define MHZ_14 5 -#define MHZ_28 4 -#define MHZ_57 3 -#define MHZ_115 2 -#define MHZ_230 0 - -/* - * H8 data - */ -struct h8_data { - u_int ser_num; - u_char ether_add[6]; - u_short hw_ver; - u_short mic_ver; - u_short max_tmp; - u_short min_tmp; - u_short cur_tmp; - u_int sys_var; - u_int pow_on; - u_int pow_on_secs; - u_char reset_status; - u_char pwr_dn_status; - u_short event_status; - u_short rom_cksm; - u_short ext_status; - u_short u_cfg; - u_char ibatt_volt; - u_char dc_volt; - u_char ptr_horiz; - u_char ptr_vert; - u_char eeprom_status; - u_char error_status; - u_char new_busy_speed; - u_char cfg_interface; - u_short int_batt_status; - u_short ext_batt_status; - u_char pow_up_status; - u_char event_status_mask; -}; - - -/* - * H8 command buffers - */ -typedef struct h8_cmd_q { - struct list_head link; /* double linked list */ - int ncmd; /* number of bytes in command */ - int nrsp; /* number of bytes in response */ - int cnt; /* number of bytes sent/received */ - int nacks; /* number of byte level acks */ - u_char cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */ - u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */ -} h8_cmd_q_t; - -union intr_buf { - u_char byte[2]; - u_int word; -}; - -#endif /* __H8_H_ */ --- linux-2.6.8-rc1/drivers/char/ipmi/ipmi_msghandler.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/ipmi/ipmi_msghandler.c 2004-07-13 17:09:13.000000000 -0700 @@ -3112,7 +3112,7 @@ static __init int ipmi_init_msghandler(v ipmi_interfaces[i] = NULL; } - proc_ipmi_root = proc_mkdir("ipmi", 0); + proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { printk("Unable to create IPMI proc dir"); return -ENOMEM; --- linux-2.6.8-rc1/drivers/char/ipmi/ipmi_si_intf.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/ipmi/ipmi_si_intf.c 2004-07-13 17:09:13.000000000 -0700 @@ -1781,7 +1781,7 @@ static int init_one_smi(int intf_num, st /* So we know not to free it unless we have allocated one. */ new_smi->intf = NULL; new_smi->si_sm = NULL; - new_smi->handlers = 0; + new_smi->handlers = NULL; if (!new_smi->irq_setup) { new_smi->irq = irqs[intf_num]; --- linux-2.6.8-rc1/drivers/char/istallion.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/istallion.c 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * istallion.c -- stallion intelligent multiport serial driver. * - * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1999 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This code is loosely based on the Linux serial driver, written by --- linux-2.6.8-rc1/drivers/char/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/Kconfig 2004-07-13 17:09:36.000000000 -0700 @@ -371,22 +371,6 @@ config AU1000_UART If you have an Alchemy AU1000 processor (MIPS based) and you want to use serial ports, say Y. Otherwise, say N. -config SGI_L1_SERIAL - bool "SGI Altix L1 serial support" - depends on SERIAL_NONSTANDARD && IA64 - help - If you have an SGI Altix and you want to use the serial port - connected to the system controller (you want this!), say Y. - Otherwise, say N. - -config SGI_L1_SERIAL_CONSOLE - bool "SGI Altix L1 serial console support" - depends on SGI_L1_SERIAL - help - If you have an SGI Altix and you would like to use the system - controller serial port as your console (you want this!), - say Y. Otherwise, say N. - config AU1000_SERIAL_CONSOLE bool "Enable Au1000 serial console" depends on AU1000_UART --- linux-2.6.8-rc1/drivers/char/keyboard.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/keyboard.c 2004-07-13 17:09:25.000000000 -0700 @@ -123,7 +123,7 @@ int shift_state = 0; */ static struct input_handler kbd_handler; -static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ @@ -142,7 +142,7 @@ static struct ledptr { /* Simple translation table for the SysRq keys */ #ifdef CONFIG_MAGIC_SYSRQ -unsigned char kbd_sysrq_xlate[128] = +unsigned char kbd_sysrq_xlate[KEY_MAX] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -941,6 +941,9 @@ void kbd_refresh_leds(struct input_handl #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) +#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) + static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -1007,6 +1010,8 @@ static int emulate_raw(struct vc_data *v #else +#define HW_RAW(dev) 0 + #warning "Cannot generate rawmode keyboard for your architecture yet." static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) @@ -1019,7 +1024,15 @@ static int emulate_raw(struct vc_data *v } #endif -void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) +void kbd_rawcode(unsigned char data) +{ + struct vc_data *vc = vc_cons[fg_console].d; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) + put_queue(vc, data); +} + +void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1053,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, i return; #endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW))) + if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); @@ -1065,6 +1078,9 @@ void kbd_keycode(unsigned int keycode, i } if (sysrq_down && down && !rep) { handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); +#ifdef CONFIG_KGDB_SYSRQ + sysrq_down = 0; /* in case we miss the "up" event */ +#endif return; } #endif @@ -1119,6 +1135,9 @@ void kbd_keycode(unsigned int keycode, i return; } + if (keycode > NR_KEYS) + return; + keysym = key_map[keycode]; type = KTYP(keysym); @@ -1148,11 +1167,12 @@ void kbd_keycode(unsigned int keycode, i } static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int keycode, int down) + unsigned int event_code, int value) { - if (event_type != EV_KEY) - return; - kbd_keycode(keycode, down, handle->dev->regs); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY) + kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); --- linux-2.6.8-rc1/drivers/char/Makefile 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/Makefile 2004-07-13 17:09:36.000000000 -0700 @@ -41,7 +41,6 @@ obj-$(CONFIG_SX) += sx.o generic_serial obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o -obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o --- linux-2.6.8-rc1/drivers/char/mem.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/mem.c 2004-07-13 17:35:08.000000000 -0700 @@ -38,6 +38,7 @@ extern void fbmem_init(void); extern void tapechar_init(void); #endif +#ifdef pgprot_noncached /* * Architectures vary in how they handle caching for addresses * outside of main memory. @@ -76,7 +77,8 @@ static inline int uncached_access(struct return 0; #elif defined(CONFIG_IA64) /* - * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. + * On ia64, we ignore O_SYNC because we cannot tolerate memory + * attribute aliases. */ return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); #elif defined(CONFIG_PPC64) @@ -89,14 +91,15 @@ static inline int uncached_access(struct return !page_is_ram(addr); #else /* - * Accessing memory above the top the kernel knows about or through a file pointer - * that was marked O_SYNC will be done non-cached. + * Accessing memory above the top the kernel knows about or through a + * file pointer that was marked O_SYNC will be done non-cached. */ if (file->f_flags & O_SYNC) return 1; return addr >= __pa(high_memory); #endif } +#endif #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE static inline int valid_phys_addr_range(unsigned long addr, size_t *count) @@ -193,28 +196,24 @@ static ssize_t write_mem(struct file * f return do_write_mem(__va(p), p, buf, count, ppos); } -static int mmap_mem(struct file * file, struct vm_area_struct * vma) +static int mmap_mem(struct file *file, struct vm_area_struct *vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int uncached; - uncached = uncached_access(file, offset); #ifdef pgprot_noncached - if (uncached) + if (uncached_access(file, offset)) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #endif - /* Don't try to swap out physical pages.. */ - vma->vm_flags |= VM_RESERVED; - /* - * Don't dump addresses that are not real memory to a core file. + * Don't try to swap out physical pages.. + * And treat /dev/mem mappings as "IO" regions: they may not + * describe valid pageframes. */ - if (uncached) - vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED|VM_IO; - if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start, - vma->vm_page_prot)) + if (remap_page_range(vma, vma->vm_start, offset, + vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; } @@ -416,7 +415,7 @@ static inline size_t read_zero_pagealign if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) goto out_up; - if (vma->vm_flags & VM_SHARED) + if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) break; count = vma->vm_end - addr; if (count > size) --- linux-2.6.8-rc1/drivers/char/mwave/mwavedd.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/mwave/mwavedd.c 2004-07-13 17:09:13.000000000 -0700 @@ -179,7 +179,7 @@ static int mwave_ioctl(struct inode *ino case IOCTL_MW_READ_DATA: case IOCTL_MW_READCLEAR_DATA: { MW_READWRITE rReadData; - unsigned short __user *pusBuffer = 0; + unsigned short __user *pusBuffer = NULL; if( copy_from_user(&rReadData, arg, sizeof(MW_READWRITE)) ) @@ -200,7 +200,7 @@ static int mwave_ioctl(struct inode *ino case IOCTL_MW_READ_INST: { MW_READWRITE rReadData; - unsigned short __user *pusBuffer = 0; + unsigned short __user *pusBuffer = NULL; if( copy_from_user(&rReadData, arg, sizeof(MW_READWRITE)) ) @@ -221,7 +221,7 @@ static int mwave_ioctl(struct inode *ino case IOCTL_MW_WRITE_DATA: { MW_READWRITE rWriteData; - unsigned short __user *pusBuffer = 0; + unsigned short __user *pusBuffer = NULL; if( copy_from_user(&rWriteData, arg, sizeof(MW_READWRITE)) ) @@ -242,7 +242,7 @@ static int mwave_ioctl(struct inode *ino case IOCTL_MW_WRITE_INST: { MW_READWRITE rWriteData; - unsigned short __user *pusBuffer = 0; + unsigned short __user *pusBuffer = NULL; if( copy_from_user(&rWriteData, arg, sizeof(MW_READWRITE)) ) --- linux-2.6.8-rc1/drivers/char/mwave/tp3780i.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/mwave/tp3780i.c 2004-07-13 17:09:13.000000000 -0700 @@ -277,7 +277,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD release_region(pSettings->usDspBaseIO & (~3), 16); if (pSettings->bInterruptClaimed) { - free_irq(pSettings->usDspIrq, 0); + free_irq(pSettings->usDspIrq, NULL); pSettings->bInterruptClaimed = FALSE; } @@ -372,7 +372,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq); goto exit_cleanup; } else { /* no conflict just release */ - free_irq(pSettings->usUartIrq, 0); + free_irq(pSettings->usUartIrq, NULL); } if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", 0)) { @@ -416,7 +416,7 @@ exit_cleanup: if (bDSPPoweredUp) smapi_set_DSP_power_state(FALSE); if (bInterruptAllocated) { - free_irq(pSettings->usDspIrq, 0); + free_irq(pSettings->usDspIrq, NULL); pSettings->bInterruptClaimed = FALSE; } return -EIO; @@ -433,7 +433,7 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA if (pBDData->bDSPEnabled) { dsp3780I_DisableDSP(&pBDData->rDspSettings); if (pSettings->bInterruptClaimed) { - free_irq(pSettings->usDspIrq, 0); + free_irq(pSettings->usDspIrq, NULL); pSettings->bInterruptClaimed = FALSE; } smapi_set_DSP_power_state(FALSE); --- linux-2.6.8-rc1/drivers/char/pcmcia/synclink_cs.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/pcmcia/synclink_cs.c 2004-07-13 17:09:13.000000000 -0700 @@ -1513,7 +1513,7 @@ static void shutdown(MGSLPC_INFO * info) if (info->tx_buf) { free_page((unsigned long) info->tx_buf); - info->tx_buf = 0; + info->tx_buf = NULL; } spin_lock_irqsave(&info->lock,flags); @@ -2591,7 +2591,7 @@ static void mgslpc_close(struct tty_stru shutdown(info); tty->closing = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { @@ -2695,7 +2695,7 @@ static void mgslpc_hangup(struct tty_str info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -2872,7 +2872,7 @@ static int mgslpc_open(struct tty_struct cleanup: if (retval) { if (tty->count == 1) - info->tty = 0; /* tty layer will release tty struct */ + info->tty = NULL;/* tty layer will release tty struct */ if(info->count) info->count--; } --- linux-2.6.8-rc1/drivers/char/raw.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/raw.c 2004-07-13 17:09:21.406018664 -0700 @@ -125,11 +125,11 @@ raw_ioctl(struct inode *inode, struct fi return ioctl_by_bdev(bdev, command, arg); } -static void bind_device(struct raw_config_request rq) +static void bind_device(struct raw_config_request *rq) { - class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); - class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor), - NULL, "raw%d", rq.raw_minor); + class_simple_device_remove(MKDEV(RAW_MAJOR, rq->raw_minor)); + class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), + NULL, "raw%d", rq->raw_minor); } /* @@ -200,15 +200,16 @@ static int raw_ctl_ioctl(struct inode *i if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; - class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); + class_simple_device_remove(MKDEV(RAW_MAJOR, + rq.raw_minor)); } else { rawdev->binding = bdget(dev); if (rawdev->binding == NULL) err = -ENOMEM; else { __module_get(THIS_MODULE); - bind_device(rq); - } + bind_device(&rq); + } } up(&raw_mutex); } else { --- linux-2.6.8-rc1/drivers/char/rocket.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/rocket.c 2004-07-13 17:09:13.000000000 -0700 @@ -1115,7 +1115,7 @@ static void rp_close(struct tty_struct * } else { if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; + info->xmit_buf = NULL; } } info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE); @@ -1292,7 +1292,7 @@ static int set_config(struct r_port *inf if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); - configure_r_port(info, 0); + configure_r_port(info, NULL); return 0; } @@ -1309,7 +1309,7 @@ static int set_config(struct r_port *inf if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) info->tty->alt_speed = 460800; - configure_r_port(info, 0); + configure_r_port(info, NULL); return 0; } @@ -1572,7 +1572,7 @@ static void rp_hangup(struct tty_struct info->count = 0; info->flags &= ~ROCKET_NORMAL_ACTIVE; - info->tty = 0; + info->tty = NULL; cp = &info->channel; sDisRxFIFO(cp); --- linux-2.6.8-rc1/drivers/char/rtc.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/rtc.c 2004-07-13 17:09:13.289252600 -0700 @@ -974,7 +974,7 @@ no_irq: release_region(RTC_PORT(0), RTC_IO_EXTENT); return -ENODEV; } - if (create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL) == NULL) { + if (!create_proc_read_entry ("driver/rtc", 0, NULL, rtc_read_proc, NULL)) { #ifdef RTC_IRQ free_irq(RTC_IRQ, NULL); #endif --- linux-2.6.8-rc1/drivers/char/sn_serial.c 2004-06-15 23:29:41.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,1028 +0,0 @@ -/* - * C-Brick Serial Port (and console) driver for SGI Altix machines. - * - * This driver is NOT suitable for talking to the l1-controller for - * anything other than 'console activities' --- please use the l1 - * driver for that. - * - * 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. - * - * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -static char sysrq_serial_str[] = "\eSYS"; -static char *sysrq_serial_ptr = sysrq_serial_str; -static unsigned long sysrq_requested; -#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ - -/* minor device number */ -#define SN_SAL_MINOR 64 - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 128 - -/* number of characters we can transmit to the SAL console at a time */ -#define SN_SAL_MAX_CHARS 120 - -#define SN_SAL_EVENT_WRITE_WAKEUP 0 - -/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to - * avoid losing chars, (always has to be a power of 2) */ -#define SN_SAL_BUFFER_SIZE (64 * (1 << 10)) - -#define SN_SAL_UART_FIFO_DEPTH 16 -#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10 - -/* we don't kmalloc/get_free_page these as we want them available - * before either of those are initialized */ -static char sn_xmit_buff_mem[SN_SAL_BUFFER_SIZE]; - -struct volatile_circ_buf { - char *cb_buf; - int cb_head; - int cb_tail; -}; - -static struct volatile_circ_buf xmit = { .cb_buf = sn_xmit_buff_mem }; -static char sn_tmp_buffer[SN_SAL_BUFFER_SIZE]; - -static struct tty_struct *sn_sal_tty; - -static struct timer_list sn_sal_timer; -static int sn_sal_event; /* event type for task queue */ - -static int sn_sal_is_asynch; -static int sn_sal_irq; -static spinlock_t sn_sal_lock = SPIN_LOCK_UNLOCKED; -static int sn_total_tx_count; -static int sn_total_rx_count; - -static void sn_sal_tasklet_action(unsigned long data); -static DECLARE_TASKLET(sn_sal_tasklet, sn_sal_tasklet_action, 0); - -static unsigned long sn_interrupt_timeout; - -extern u64 master_node_bedrock_address; - -#undef DEBUG -#ifdef DEBUG -static int sn_debug_printf(const char *fmt, ...); -#define DPRINTF(x...) sn_debug_printf(x) -#else -#define DPRINTF(x...) do { } while (0) -#endif - -struct sn_sal_ops { - int (*sal_puts)(const char *s, int len); - int (*sal_getc)(void); - int (*sal_input_pending)(void); - void (*sal_wakeup_transmit)(void); -}; - -/* This is the pointer used. It is assigned to point to one of - * the tables below. - */ -static struct sn_sal_ops *sn_func; - -/* Prototypes */ -static int snt_hw_puts(const char *, int); -static int snt_poll_getc(void); -static int snt_poll_input_pending(void); -static int snt_sim_puts(const char *, int); -static int snt_sim_getc(void); -static int snt_sim_input_pending(void); -static int snt_intr_getc(void); -static int snt_intr_input_pending(void); -static void sn_intr_transmit_chars(void); - -/* A table for polling */ -static struct sn_sal_ops poll_ops = { - .sal_puts = snt_hw_puts, - .sal_getc = snt_poll_getc, - .sal_input_pending = snt_poll_input_pending -}; - -/* A table for the simulator */ -static struct sn_sal_ops sim_ops = { - .sal_puts = snt_sim_puts, - .sal_getc = snt_sim_getc, - .sal_input_pending = snt_sim_input_pending -}; - -/* A table for interrupts enabled */ -static struct sn_sal_ops intr_ops = { - .sal_puts = snt_hw_puts, - .sal_getc = snt_intr_getc, - .sal_input_pending = snt_intr_input_pending, - .sal_wakeup_transmit = sn_intr_transmit_chars -}; - - -/* the console does output in two distinctly different ways: - * synchronous and asynchronous (buffered). initally, early_printk - * does synchronous output. any data written goes directly to the SAL - * to be output (incidentally, it is internally buffered by the SAL) - * after interrupts and timers are initialized and available for use, - * the console init code switches to asynchronous output. this is - * also the earliest opportunity to begin polling for console input. - * after console initialization, console output and tty (serial port) - * output is buffered and sent to the SAL asynchronously (either by - * timer callback or by UART interrupt) */ - - -/* routines for running the console in polling mode */ - -static int -snt_hw_puts(const char *s, int len) -{ - /* looking at the PROM source code, putb calls the flush - * routine, so if we send characters in FIFO sized chunks, it - * should go out by the next time the timer gets called */ - return ia64_sn_console_putb(s, len); -} - -static int -snt_poll_getc(void) -{ - int ch; - ia64_sn_console_getc(&ch); - return ch; -} - -static int -snt_poll_input_pending(void) -{ - int status, input; - - status = ia64_sn_console_check(&input); - return !status && input; -} - - -/* routines for running the console on the simulator */ - -static int -snt_sim_puts(const char *str, int count) -{ - int counter = count; - -#ifdef FLAG_DIRECT_CONSOLE_WRITES - /* This is an easy way to pre-pend the output to know whether the output - * was done via sal or directly */ - writeb('[', master_node_bedrock_address + (UART_TX << 3)); - writeb('+', master_node_bedrock_address + (UART_TX << 3)); - writeb(']', master_node_bedrock_address + (UART_TX << 3)); - writeb(' ', master_node_bedrock_address + (UART_TX << 3)); -#endif /* FLAG_DIRECT_CONSOLE_WRITES */ - while (counter > 0) { - writeb(*str, master_node_bedrock_address + (UART_TX << 3)); - counter--; - str++; - } - - return count; -} - -static int -snt_sim_getc(void) -{ - return readb(master_node_bedrock_address + (UART_RX << 3)); -} - -static int -snt_sim_input_pending(void) -{ - return readb(master_node_bedrock_address + (UART_LSR << 3)) & UART_LSR_DR; -} - - -/* routines for an interrupt driven console (normal) */ - -static int -snt_intr_getc(void) -{ - return ia64_sn_console_readc(); -} - -static int -snt_intr_input_pending(void) -{ - return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV; -} - -/* The early printk (possible setup) and function call */ - -void -early_printk_sn_sal(const char *s, unsigned count) -{ - extern void early_sn_setup(void); - - if (!sn_func) { - if (IS_RUNNING_ON_SIMULATOR()) - sn_func = &sim_ops; - else - sn_func = &poll_ops; - - early_sn_setup(); - } - sn_func->sal_puts(s, count); -} - -#ifdef DEBUG -/* this is as "close to the metal" as we can get, used when the driver - * itself may be broken */ -static int -sn_debug_printf(const char *fmt, ...) -{ - static char printk_buf[1024]; - int printed_len; - va_list args; - - va_start(args, fmt); - printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); - early_printk_sn_sal(printk_buf, printed_len); - va_end(args); - return printed_len; -} -#endif /* DEBUG */ - -/* - * Interrupt handling routines. - */ - -static void -sn_sal_sched_event(int event) -{ - sn_sal_event |= (1 << event); - tasklet_schedule(&sn_sal_tasklet); -} - -/* sn_receive_chars can be called before sn_sal_tty is initialized. in - * that case, its only use is to trigger sysrq and kdb */ -static void -sn_receive_chars(struct pt_regs *regs, unsigned long *flags) -{ - int ch; - - while (sn_func->sal_input_pending()) { - ch = sn_func->sal_getc(); - if (ch < 0) { - printk(KERN_ERR "sn_serial: An error occured while " - "obtaining data from the console (0x%0x)\n", ch); - break; - } -#if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (sysrq_requested) { - unsigned long sysrq_timeout = sysrq_requested + HZ*5; - - sysrq_requested = 0; - if (ch && time_before(jiffies, sysrq_timeout)) { - spin_unlock_irqrestore(&sn_sal_lock, *flags); - handle_sysrq(ch, regs, NULL); - spin_lock_irqsave(&sn_sal_lock, *flags); - /* don't record this char */ - continue; - } - } - if (ch == *sysrq_serial_ptr) { - if (!(*++sysrq_serial_ptr)) { - sysrq_requested = jiffies; - sysrq_serial_ptr = sysrq_serial_str; - } - } - else - sysrq_serial_ptr = sysrq_serial_str; -#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE && CONFIG_MAGIC_SYSRQ */ - - /* record the character to pass up to the tty layer */ - if (sn_sal_tty) { - *sn_sal_tty->flip.char_buf_ptr = ch; - sn_sal_tty->flip.char_buf_ptr++; - sn_sal_tty->flip.count++; - if (sn_sal_tty->flip.count == TTY_FLIPBUF_SIZE) - break; - } - sn_total_rx_count++; - } - - if (sn_sal_tty) - tty_flip_buffer_push((struct tty_struct *)sn_sal_tty); -} - - -/* synch_flush_xmit must be called with sn_sal_lock */ -static void -synch_flush_xmit(void) -{ - int xmit_count, tail, head, loops, ii; - int result; - char *start; - - if (xmit.cb_head == xmit.cb_tail) - return; /* Nothing to do. */ - - head = xmit.cb_head; - tail = xmit.cb_tail; - start = &xmit.cb_buf[tail]; - - /* twice around gets the tail to the end of the buffer and - * then to the head, if needed */ - loops = (head < tail) ? 2 : 1; - - for (ii = 0; ii < loops; ii++) { - xmit_count = (head < tail) ? (SN_SAL_BUFFER_SIZE - tail) : (head - tail); - - if (xmit_count > 0) { - result = sn_func->sal_puts((char *)start, xmit_count); - if (!result) - DPRINTF("\n*** synch_flush_xmit failed to flush\n"); - if (result > 0) { - xmit_count -= result; - sn_total_tx_count += result; - tail += result; - tail &= SN_SAL_BUFFER_SIZE - 1; - xmit.cb_tail = tail; - start = (char *)&xmit.cb_buf[tail]; - } - } - } -} - -/* must be called with a lock protecting the circular buffer and - * sn_sal_tty */ -static void -sn_poll_transmit_chars(void) -{ - int xmit_count, tail, head; - int result; - char *start; - - BUG_ON(!sn_sal_is_asynch); - - if (xmit.cb_head == xmit.cb_tail || - (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) { - /* Nothing to do. */ - return; - } - - head = xmit.cb_head; - tail = xmit.cb_tail; - start = &xmit.cb_buf[tail]; - - xmit_count = (head < tail) ? (SN_SAL_BUFFER_SIZE - tail) : (head - tail); - - if (xmit_count == 0) - DPRINTF("\n*** empty xmit_count\n"); - - /* use the ops, as we could be on the simulator */ - result = sn_func->sal_puts((char *)start, xmit_count); - if (!result) - DPRINTF("\n*** error in synchronous sal_puts\n"); - /* XXX chadt clean this up */ - if (result > 0) { - xmit_count -= result; - sn_total_tx_count += result; - tail += result; - tail &= SN_SAL_BUFFER_SIZE - 1; - xmit.cb_tail = tail; - start = &xmit.cb_buf[tail]; - } - - /* if there's few enough characters left in the xmit buffer - * that we could stand for the upper layer to send us some - * more, ask for it. */ - if (sn_sal_tty) - if (CIRC_CNT(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS) - sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP); -} - - -/* must be called with a lock protecting the circular buffer and - * sn_sal_tty */ -static void -sn_intr_transmit_chars(void) -{ - int xmit_count, tail, head, loops, ii; - int result; - char *start; - - BUG_ON(!sn_sal_is_asynch); - - if (xmit.cb_head == xmit.cb_tail || - (sn_sal_tty && (sn_sal_tty->stopped || sn_sal_tty->hw_stopped))) { - /* Nothing to do. */ - return; - } - - head = xmit.cb_head; - tail = xmit.cb_tail; - start = &xmit.cb_buf[tail]; - - /* twice around gets the tail to the end of the buffer and - * then to the head, if needed */ - loops = (head < tail) ? 2 : 1; - - for (ii = 0; ii < loops; ii++) { - xmit_count = (head < tail) ? - (SN_SAL_BUFFER_SIZE - tail) : (head - tail); - - if (xmit_count > 0) { - result = ia64_sn_console_xmit_chars((char *)start, xmit_count); -#ifdef DEBUG - if (!result) - DPRINTF("`"); -#endif - if (result > 0) { - xmit_count -= result; - sn_total_tx_count += result; - tail += result; - tail &= SN_SAL_BUFFER_SIZE - 1; - xmit.cb_tail = tail; - start = &xmit.cb_buf[tail]; - } - } - } - - /* if there's few enough characters left in the xmit buffer - * that we could stand for the upper layer to send us some - * more, ask for it. */ - if (sn_sal_tty) - if (CIRC_CNT(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE) < WAKEUP_CHARS) - sn_sal_sched_event(SN_SAL_EVENT_WRITE_WAKEUP); -} - - -static irqreturn_t -sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* this call is necessary to pass the interrupt back to the - * SAL, since it doesn't intercept the UART interrupts - * itself */ - int status = ia64_sn_console_intr_status(); - unsigned long flags; - - spin_lock_irqsave(&sn_sal_lock, flags); - if (status & SAL_CONSOLE_INTR_RECV) - sn_receive_chars(regs, &flags); - if (status & SAL_CONSOLE_INTR_XMIT) - sn_intr_transmit_chars(); - spin_unlock_irqrestore(&sn_sal_lock, flags); - return IRQ_HANDLED; -} - - -/* returns the console irq if interrupt is successfully registered, - * else 0 */ -static int -sn_sal_connect_interrupt(void) -{ - cpuid_t intr_cpuid; - unsigned int intr_cpuloc; - nasid_t console_nasid; - unsigned int console_irq; - int result; - - console_nasid = ia64_sn_get_console_nasid(); - intr_cpuid = first_cpu(node_to_cpumask(nasid_to_cnodeid(console_nasid))); - intr_cpuloc = cpu_physical_id(intr_cpuid); - console_irq = CPU_VECTOR_TO_IRQ(intr_cpuloc, SGI_UART_VECTOR); - - result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR); - BUG_ON(result != SGI_UART_VECTOR); - - result = request_irq(console_irq, sn_sal_interrupt, SA_INTERRUPT, "SAL console driver", &sn_sal_tty); - if (result >= 0) - return console_irq; - - printk(KERN_WARNING "sn_serial: console proceeding in polled mode\n"); - return 0; -} - -static void -sn_sal_tasklet_action(unsigned long data) -{ - unsigned long flags; - - if (sn_sal_tty) { - spin_lock_irqsave(&sn_sal_lock, flags); - if (sn_sal_tty) { - if (test_and_clear_bit(SN_SAL_EVENT_WRITE_WAKEUP, &sn_sal_event)) { - if ((sn_sal_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && sn_sal_tty->ldisc.write_wakeup) - (sn_sal_tty->ldisc.write_wakeup)((struct tty_struct *)sn_sal_tty); - wake_up_interruptible((wait_queue_head_t *)&sn_sal_tty->write_wait); - } - } - spin_unlock_irqrestore(&sn_sal_lock, flags); - } -} - - -/* - * This function handles polled mode. - */ -static void -sn_sal_timer_poll(unsigned long dummy) -{ - unsigned long flags; - - if (!sn_sal_irq) { - spin_lock_irqsave(&sn_sal_lock, flags); - sn_receive_chars(NULL, &flags); - sn_poll_transmit_chars(); - spin_unlock_irqrestore(&sn_sal_lock, flags); - mod_timer(&sn_sal_timer, jiffies + sn_interrupt_timeout); - } -} - - -/* - * User-level console routines - */ - -static int -sn_sal_open(struct tty_struct *tty, struct file *filp) -{ - unsigned long flags; - - DPRINTF("sn_sal_open: sn_sal_tty = %p, tty = %p, filp = %p\n", - sn_sal_tty, tty, filp); - - spin_lock_irqsave(&sn_sal_lock, flags); - if (!sn_sal_tty) - sn_sal_tty = tty; - spin_unlock_irqrestore(&sn_sal_lock, flags); - - return 0; -} - - -/* We're keeping all our resources. We're keeping interrupts turned - * on. Maybe just let the tty layer finish its stuff...? GMSH - */ -static void -sn_sal_close(struct tty_struct *tty, struct file * filp) -{ - if (tty->count == 1) { - unsigned long flags; - tty->closing = 1; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - spin_lock_irqsave(&sn_sal_lock, flags); - sn_sal_tty = NULL; - spin_unlock_irqrestore(&sn_sal_lock, flags); - } -} - - -static int -sn_sal_write(struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) -{ - int c, ret = 0; - unsigned long flags; - - if (from_user) { - while (1) { - int c1; - c = CIRC_SPACE_TO_END(xmit.cb_head, xmit.cb_tail, - SN_SAL_BUFFER_SIZE); - - if (count < c) - c = count; - if (c <= 0) - break; - - c -= copy_from_user(sn_tmp_buffer, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - - /* Turn off interrupts and see if the xmit buffer has - * moved since the last time we looked. - */ - spin_lock_irqsave(&sn_sal_lock, flags); - c1 = CIRC_SPACE_TO_END(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE); - - if (c1 < c) - c = c1; - - memcpy(xmit.cb_buf + xmit.cb_head, sn_tmp_buffer, c); - xmit.cb_head = ((xmit.cb_head + c) & (SN_SAL_BUFFER_SIZE - 1)); - spin_unlock_irqrestore(&sn_sal_lock, flags); - - buf += c; - count -= c; - ret += c; - } - } - else { - /* The buffer passed in isn't coming from userland, - * so cut out the middleman (sn_tmp_buffer). - */ - spin_lock_irqsave(&sn_sal_lock, flags); - while (1) { - c = CIRC_SPACE_TO_END(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE); - - if (count < c) - c = count; - if (c <= 0) { - break; - } - memcpy(xmit.cb_buf + xmit.cb_head, buf, c); - xmit.cb_head = ((xmit.cb_head + c) & (SN_SAL_BUFFER_SIZE - 1)); - buf += c; - count -= c; - ret += c; - } - spin_unlock_irqrestore(&sn_sal_lock, flags); - } - - spin_lock_irqsave(&sn_sal_lock, flags); - if (xmit.cb_head != xmit.cb_tail && !(tty && (tty->stopped || tty->hw_stopped))) - if (sn_func->sal_wakeup_transmit) - sn_func->sal_wakeup_transmit(); - spin_unlock_irqrestore(&sn_sal_lock, flags); - - return ret; -} - - -static void -sn_sal_put_char(struct tty_struct *tty, unsigned char ch) -{ - unsigned long flags; - - spin_lock_irqsave(&sn_sal_lock, flags); - if (CIRC_SPACE(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE) != 0) { - xmit.cb_buf[xmit.cb_head] = ch; - xmit.cb_head = (xmit.cb_head + 1) & (SN_SAL_BUFFER_SIZE-1); - if ( sn_func->sal_wakeup_transmit ) - sn_func->sal_wakeup_transmit(); - } - spin_unlock_irqrestore(&sn_sal_lock, flags); -} - - -static void -sn_sal_flush_chars(struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&sn_sal_lock, flags); - if (CIRC_CNT(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE)) - if (sn_func->sal_wakeup_transmit) - sn_func->sal_wakeup_transmit(); - spin_unlock_irqrestore(&sn_sal_lock, flags); -} - - -static int -sn_sal_write_room(struct tty_struct *tty) -{ - unsigned long flags; - int space; - - spin_lock_irqsave(&sn_sal_lock, flags); - space = CIRC_SPACE(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE); - spin_unlock_irqrestore(&sn_sal_lock, flags); - return space; -} - - -static int -sn_sal_chars_in_buffer(struct tty_struct *tty) -{ - unsigned long flags; - int space; - - spin_lock_irqsave(&sn_sal_lock, flags); - space = CIRC_CNT(xmit.cb_head, xmit.cb_tail, SN_SAL_BUFFER_SIZE); - DPRINTF("<%d>", space); - spin_unlock_irqrestore(&sn_sal_lock, flags); - return space; -} - - -static void -sn_sal_flush_buffer(struct tty_struct *tty) -{ - unsigned long flags; - - /* drop everything */ - spin_lock_irqsave(&sn_sal_lock, flags); - xmit.cb_head = xmit.cb_tail = 0; - spin_unlock_irqrestore(&sn_sal_lock, flags); - - /* wake up tty level */ - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - - -static void -sn_sal_hangup(struct tty_struct *tty) -{ - sn_sal_flush_buffer(tty); -} - - -static void -sn_sal_wait_until_sent(struct tty_struct *tty, int timeout) -{ - /* this is SAL's problem */ - DPRINTF(""); -} - - -/* - * sn_sal_read_proc - * - * Console /proc interface - */ - -static int -sn_sal_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int len = 0; - off_t begin = 0; - - len += sprintf(page, "sn_serial: nasid:%ld irq:%d tx:%d rx:%d\n", - ia64_sn_get_console_nasid(), sn_sal_irq, - sn_total_tx_count, sn_total_rx_count); - *eof = 1; - - if (off >= len+begin) - return 0; - *start = page + (off-begin); - - return count < begin+len-off ? count : begin+len-off; -} - - -static struct tty_operations sn_sal_driver_ops = { - .open = sn_sal_open, - .close = sn_sal_close, - .write = sn_sal_write, - .put_char = sn_sal_put_char, - .flush_chars = sn_sal_flush_chars, - .write_room = sn_sal_write_room, - .chars_in_buffer = sn_sal_chars_in_buffer, - .hangup = sn_sal_hangup, - .wait_until_sent = sn_sal_wait_until_sent, - .read_proc = sn_sal_read_proc, -}; -static struct tty_driver *sn_sal_driver; - -/* sn_sal_init wishlist: - * - allocate sn_tmp_buffer - * - fix up the tty_driver struct - * - turn on receive interrupts - * - do any termios twiddling once and for all - */ - -/* - * Boot-time initialization code - */ - -static void __init -sn_sal_switch_to_asynch(void) -{ - unsigned long flags; - - /* without early_printk, we may be invoked late enough to race - * with other cpus doing console IO at this point, however - * console interrupts will never be enabled */ - spin_lock_irqsave(&sn_sal_lock, flags); - - if (sn_sal_is_asynch) { - spin_unlock_irqrestore(&sn_sal_lock, flags); - return; - } - - DPRINTF("sn_serial: switch to asynchronous console\n"); - - /* early_printk invocation may have done this for us */ - if (!sn_func) { - if (IS_RUNNING_ON_SIMULATOR()) - sn_func = &sim_ops; - else - sn_func = &poll_ops; - } - - /* we can't turn on the console interrupt (as request_irq - * calls kmalloc, which isn't set up yet), so we rely on a - * timer to poll for input and push data from the console - * buffer. - */ - init_timer(&sn_sal_timer); - sn_sal_timer.function = sn_sal_timer_poll; - - if (IS_RUNNING_ON_SIMULATOR()) - sn_interrupt_timeout = 6; - else { - /* 960cps / 16 char FIFO = 60HZ - * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */ - sn_interrupt_timeout = HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS; - } - mod_timer(&sn_sal_timer, jiffies + sn_interrupt_timeout); - - sn_sal_is_asynch = 1; - spin_unlock_irqrestore(&sn_sal_lock, flags); -} - -static void __init -sn_sal_switch_to_interrupts(void) -{ - int irq; - - DPRINTF("sn_serial: switching to interrupt driven console\n"); - - irq = sn_sal_connect_interrupt(); - if (irq) { - unsigned long flags; - spin_lock_irqsave(&sn_sal_lock, flags); - - /* sn_sal_irq is a global variable. When it's set to - * a non-zero value, we stop polling for input (since - * interrupts should now be enabled). */ - sn_sal_irq = irq; - sn_func = &intr_ops; - - /* turn on receive interrupts */ - ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); - spin_unlock_irqrestore(&sn_sal_lock, flags); - } -} - -static int __init -sn_sal_module_init(void) -{ - int retval; - - DPRINTF("sn_serial: sn_sal_module_init\n"); - - if (!ia64_platform_is("sn2")) - return -ENODEV; - - sn_sal_driver = alloc_tty_driver(1); - if ( !sn_sal_driver ) - return -ENOMEM; - - sn_sal_driver->owner = THIS_MODULE; - sn_sal_driver->driver_name = "sn_serial"; - sn_sal_driver->name = "ttyS"; - sn_sal_driver->major = TTY_MAJOR; - sn_sal_driver->minor_start = SN_SAL_MINOR; - sn_sal_driver->type = TTY_DRIVER_TYPE_SERIAL; - sn_sal_driver->subtype = SERIAL_TYPE_NORMAL; - sn_sal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - - tty_set_operations(sn_sal_driver, &sn_sal_driver_ops); - - /* when this driver is compiled in, the console initialization - * will have already switched us into asynchronous operation - * before we get here through the module initcalls */ - sn_sal_switch_to_asynch(); - - /* at this point (module_init) we can try to turn on interrupts */ - if (!IS_RUNNING_ON_SIMULATOR()) - sn_sal_switch_to_interrupts(); - - sn_sal_driver->init_termios = tty_std_termios; - sn_sal_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - - if ((retval = tty_register_driver(sn_sal_driver))) { - printk(KERN_ERR "sn_serial: Unable to register tty driver\n"); - return retval; - } - return 0; -} - - -static void __exit -sn_sal_module_exit(void) -{ - del_timer_sync(&sn_sal_timer); - tty_unregister_driver(sn_sal_driver); - put_tty_driver(sn_sal_driver); -} - -module_init(sn_sal_module_init); -module_exit(sn_sal_module_exit); - -/* - * Kernel console definitions - */ - -#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE -/* - * Print a string to the SAL console. The console_lock must be held - * when we get here. - */ -static void -sn_sal_console_write(struct console *co, const char *s, unsigned count) -{ - unsigned long flags; - const char *s1; - - BUG_ON(!sn_sal_is_asynch); - - /* somebody really wants this output, might be an - * oops, kdb, panic, etc. make sure they get it. */ - if (spin_is_locked(&sn_sal_lock)) { - synch_flush_xmit(); - /* Output '\r' before each '\n' */ - while ((s1 = memchr(s, '\n', count)) != NULL) { - sn_func->sal_puts(s, s1 - s); - sn_func->sal_puts("\r\n", 2); - count -= s1 + 1 - s; - s = s1 + 1; - } - sn_func->sal_puts(s, count); - } - else if (in_interrupt()) { - spin_lock_irqsave(&sn_sal_lock, flags); - synch_flush_xmit(); - spin_unlock_irqrestore(&sn_sal_lock, flags); - /* Output '\r' before each '\n' */ - while ((s1 = memchr(s, '\n', count)) != NULL) { - sn_func->sal_puts(s, s1 - s); - sn_func->sal_puts("\r\n", 2); - count -= s1 + 1 - s; - s = s1 + 1; - } - sn_func->sal_puts(s, count); - } - else { - /* Output '\r' before each '\n' */ - while ((s1 = memchr(s, '\n', count)) != NULL) { - sn_sal_write(NULL, 0, s, s1 - s); - sn_sal_write(NULL, 0, "\r\n", 2); - count -= s1 + 1 - s; - s = s1 + 1; - } - sn_sal_write(NULL, 0, s, count); - } -} - -static struct tty_driver * -sn_sal_console_device(struct console *c, int *index) -{ - *index = c->index; - return sn_sal_driver; -} - -static int __init -sn_sal_console_setup(struct console *co, char *options) -{ - return 0; -} - - -static struct console sal_console = { - .name = "ttyS", - .write = sn_sal_console_write, - .device = sn_sal_console_device, - .setup = sn_sal_console_setup, - .index = -1 -}; - -static int __init -sn_sal_serial_console_init(void) -{ - if (ia64_platform_is("sn2")) { - sn_sal_switch_to_asynch(); - DPRINTF("sn_sal_serial_console_init : register console\n"); - register_console(&sal_console); - } - return 0; -} -console_initcall(sn_sal_serial_console_init); - -#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */ --- linux-2.6.8-rc1/drivers/char/sonypi.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/sonypi.c 2004-07-13 17:09:54.000000000 -0700 @@ -50,12 +50,13 @@ #include #include +static int verbose; /* = 0 */ + #include "sonypi.h" #include static struct sonypi_device sonypi_device; static int minor = -1; -static int verbose; /* = 0 */ static int fnkeyinit; /* = 0 */ static int camera; /* = 0 */ static int compat; /* = 0 */ --- linux-2.6.8-rc1/drivers/char/sonypi.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/sonypi.h 2004-07-13 17:09:54.000000000 -0700 @@ -401,8 +401,6 @@ struct sonypi_device { #define SONYPI_ACPI_ACTIVE 0 #endif /* CONFIG_ACPI */ -extern int verbose; - static inline int sonypi_ec_write(u8 addr, u8 value) { #ifdef CONFIG_ACPI_EC if (SONYPI_ACPI_ACTIVE) --- linux-2.6.8-rc1/drivers/char/stallion.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/char/stallion.c 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * stallion.c -- stallion multiport serial driver. * - * Copyright (C) 1996-1999 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1999 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This code is loosely based on the Linux serial driver, written by --- linux-2.6.8-rc1/drivers/char/sysrq.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/char/sysrq.c 2004-07-13 17:09:25.000000000 -0700 @@ -35,6 +35,25 @@ #include #include +#ifdef CONFIG_KGDB_SYSRQ + +#define GDB_OP &kgdb_op +static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) +{ + printk("kgdb sysrq\n"); + breakpoint(); +} + +static struct sysrq_key_op kgdb_op = { + .handler = kgdb_sysrq, + .help_msg = "kGdb|Fgdb", + .action_msg = "Debug breakpoint\n", +}; + +#else +#define GDB_OP NULL +#endif + extern void reset_vc(unsigned int); @@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta /* c */ NULL, /* d */ NULL, /* e */ &sysrq_term_op, -/* f */ NULL, -/* g */ NULL, +/* f */ GDB_OP, +/* g */ GDB_OP, /* h */ NULL, /* i */ &sysrq_kill_op, /* j */ NULL, --- linux-2.6.8-rc1/drivers/char/tty_io.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/char/tty_io.c 2004-07-13 17:09:33.000000000 -0700 @@ -445,21 +445,13 @@ void do_tty_hangup(void *data) } file_list_unlock(); - /* FIXME! What are the locking issues here? This may me overdoing things.. - * this question is especially important now that we've removed the irqlock. */ - { - unsigned long flags; - - local_irq_save(flags); // FIXME: is this safe? - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - local_irq_restore(flags); // FIXME: is this safe? - } + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); --- linux-2.6.8-rc1/drivers/cpufreq/cpufreq.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/cpufreq/cpufreq.c 2004-07-13 17:09:21.000000000 -0700 @@ -100,6 +100,86 @@ static void cpufreq_cpu_put(struct cpufr } /********************************************************************* + * EXTERNALLY AFFECTING FREQUENCY CHANGES * + *********************************************************************/ + +/** + * adjust_jiffies - adjust the system "loops_per_jiffy" + * + * This function alters the system "loops_per_jiffy" for the clock + * speed change. Note that loops_per_jiffy cannot be updated on SMP + * systems as each CPU might be scaled differently. So, use the arch + * per-CPU loops_per_jiffy value wherever possible. + */ +#ifndef CONFIG_SMP +static unsigned long l_p_j_ref; +static unsigned int l_p_j_ref_freq; + +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) +{ + if (ci->flags & CPUFREQ_CONST_LOOPS) + return; + + if (!l_p_j_ref_freq) { + l_p_j_ref = loops_per_jiffy; + l_p_j_ref_freq = ci->old; + } + if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || + (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || + (val == CPUFREQ_RESUMECHANGE)) + loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); +} +#else +static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } +#endif + + +/** + * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition + * + * This function calls the transition notifiers and the "adjust_jiffies" function. It is called + * twice on all CPU frequency changes that have external effects. + */ +void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) +{ + BUG_ON(irqs_disabled()); + + freqs->flags = cpufreq_driver->flags; + + down_read(&cpufreq_notifier_rwsem); + switch (state) { + case CPUFREQ_PRECHANGE: + /* detect if the driver reported a value as "old frequency" which + * is not equal to what the cpufreq core thinks is "old frequency". + */ + if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { + if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) && + (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) + { + if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) + panic("CPU Frequency is out of sync."); + + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); + freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; + } + } + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); + break; + case CPUFREQ_POSTCHANGE: + adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); + notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); + cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; + break; + } + up_read(&cpufreq_notifier_rwsem); +} +EXPORT_SYMBOL_GPL(cpufreq_notify_transition); + + + +/********************************************************************* * SYSFS INTERFACE * *********************************************************************/ @@ -617,8 +697,8 @@ static int cpufreq_resume(struct sys_dev if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC) panic("CPU Frequency is out of sync."); - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing" - "core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq); + printk(KERN_WARNING "Warning: CPU frequency is %u, " + "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; @@ -626,6 +706,8 @@ static int cpufreq_resume(struct sys_dev notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); + + cpu_policy->cur = cur_freq; } } @@ -1006,87 +1088,6 @@ EXPORT_SYMBOL(cpufreq_update_policy); /********************************************************************* - * EXTERNALLY AFFECTING FREQUENCY CHANGES * - *********************************************************************/ - -/** - * adjust_jiffies - adjust the system "loops_per_jiffy" - * - * This function alters the system "loops_per_jiffy" for the clock - * speed change. Note that loops_per_jiffy cannot be updated on SMP - * systems as each CPU might be scaled differently. So, use the arch - * per-CPU loops_per_jiffy value wherever possible. - */ -#ifndef CONFIG_SMP -static unsigned long l_p_j_ref; -static unsigned int l_p_j_ref_freq; - -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -{ - if (ci->flags & CPUFREQ_CONST_LOOPS) - return; - - if (!l_p_j_ref_freq) { - l_p_j_ref = loops_per_jiffy; - l_p_j_ref_freq = ci->old; - } - if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || - (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) || - (val == CPUFREQ_RESUMECHANGE)) - loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); -} -#else -static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } -#endif - - -/** - * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition - * - * This function calls the transition notifiers and the "adjust_jiffies" function. It is called - * twice on all CPU frequency changes that have external effects. - */ -void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) -{ - BUG_ON(irqs_disabled()); - - freqs->flags = cpufreq_driver->flags; - - down_read(&cpufreq_notifier_rwsem); - switch (state) { - case CPUFREQ_PRECHANGE: - /* detect if the driver reported a value as "old frequency" which - * is not equal to what the cpufreq core thinks is "old frequency". - */ - if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { - if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) && - (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) - { - if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC) - panic("CPU Frequency is out of sync."); - - printk(KERN_WARNING "Warning: CPU frequency out of sync: " - "cpufreq and timing core thinks of %u, is %u kHz.\n", - cpufreq_cpu_data[freqs->cpu]->cur, freqs->old); - freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; - } - } - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); - adjust_jiffies(CPUFREQ_PRECHANGE, freqs); - break; - case CPUFREQ_POSTCHANGE: - adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); - notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); - cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; - break; - } - up_read(&cpufreq_notifier_rwsem); -} -EXPORT_SYMBOL_GPL(cpufreq_notify_transition); - - - -/********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************/ --- linux-2.6.8-rc1/drivers/cpufreq/cpufreq_userspace.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/cpufreq/cpufreq_userspace.c 2004-07-13 17:09:21.000000000 -0700 @@ -82,6 +82,13 @@ userspace_cpufreq_notifier(struct notifi { struct cpufreq_freqs *freq = data; + /* Don't update cur_freq if CPU is managed and we're + * waking up: else we won't remember what frequency + * we need to set the CPU to. + */ + if (cpu_is_managed[freq->cpu] && (val == CPUFREQ_RESUMECHANGE)) + return 0; + cpu_cur_freq[freq->cpu] = freq->new; return 0; @@ -522,6 +529,9 @@ static int cpufreq_governor_userspace(st else if (policy->min > cpu_cur_freq[cpu]) __cpufreq_driver_target(¤t_policy[cpu], policy->min, CPUFREQ_RELATION_L); + else + __cpufreq_driver_target(¤t_policy[cpu], cpu_cur_freq[cpu], + CPUFREQ_RELATION_L); memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); up(&userspace_sem); break; --- linux-2.6.8-rc1/drivers/firmware/pcdp.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/firmware/pcdp.c 2004-07-13 17:35:42.000000000 -0700 @@ -52,7 +52,11 @@ uart_edge_level(int rev, struct pcdp_uar } static void __init +#ifndef CONFIG_KGDB_EARLY setup_serial_console(int rev, struct pcdp_uart *uart) +#else +setup_serial_console(int rev, struct pcdp_uart *uart, int line) +#endif { #ifdef CONFIG_SERIAL_8250_CONSOLE struct uart_port port; @@ -60,6 +64,9 @@ setup_serial_console(int rev, struct pcd int mapsize = 64; memset(&port, 0, sizeof(port)); +#ifdef CONFIG_KGDB_EARLY + port.line = line; +#endif port.uartclk = uart->clock_rate; if (!port.uartclk) /* some FW doesn't supply this */ port.uartclk = BASE_BAUD * 16; @@ -106,6 +113,9 @@ setup_serial_console(int rev, struct pcd snprintf(options, sizeof(options), "%lun%d", uart->baud, uart->bits ? uart->bits : 8); +#ifdef CONFIG_KGDB_EARLY + if (!line) +#endif add_preferred_console("ttyS", port.line, options); printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n", @@ -152,10 +162,19 @@ efi_setup_pcdp_console(char *cmdline) for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) { if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) { if (uart->type == PCDP_CONSOLE_UART) { +#ifndef CONFIG_KGDB_EARLY setup_serial_console(pcdp->rev, uart); return; +#else + setup_serial_console(pcdp->rev, uart, 0); + serial = 0; +#endif } } +#ifdef CONFIG_KGDB_EARLY + else if (uart->type == PCDP_DEBUG_UART) + setup_serial_console(pcdp->rev, uart, 1); +#endif } end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length); @@ -193,7 +212,7 @@ hcdp_early_uart (void) config_tables = __va(config_tables); for (i = 0; i < systab->nr_tables; i++) { - if (efi_guidcmp(config_tables[i].guid, PCDP_TABLE_GUID) == 0) { + if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { pcdp = (struct pcdp *) config_tables[i].table; break; } --- linux-2.6.8-rc1/drivers/i2c/i2c-dev.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/i2c/i2c-dev.c 2004-07-13 17:09:44.000000000 -0700 @@ -518,20 +518,29 @@ static int __init i2c_dev_init(void) printk(KERN_INFO "i2c /dev entries driver\n"); - if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { - printk(KERN_ERR "i2c-dev.o: unable to get major %d for i2c bus\n", - I2C_MAJOR); - return -EIO; - } + res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); + if (res) + goto out; + + res = class_register(&i2c_dev_class); + if (res) + goto out_unreg_chrdev; + + res = i2c_add_driver(&i2cdev_driver); + if (res) + goto out_unreg_class; + devfs_mk_dir("i2c"); - class_register(&i2c_dev_class); - if ((res = i2c_add_driver(&i2cdev_driver))) { - printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n"); - devfs_remove("i2c"); - unregister_chrdev(I2C_MAJOR,"i2c"); - return res; - } + return 0; + +out_unreg_class: + class_unregister(&i2c_dev_class); +out_unreg_chrdev: + unregister_chrdev(I2C_MAJOR,"i2c"); +out: + printk(KERN_ERR "%s: Driver Initialisation failed", __FILE__); + return res; } static void __exit i2c_dev_exit(void) --- linux-2.6.8-rc1/drivers/ide/ide.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/ide.c 2004-07-13 17:09:44.000000000 -0700 @@ -437,6 +437,30 @@ u8 ide_dump_status (ide_drive_t *drive, #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } + { + struct request *rq; + int opcode = 0x100; + + spin_lock(&ide_lock); + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) + opcode = args[0]; + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + } + } + + printk("ide: failed opcode was %x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -2003,7 +2027,7 @@ done: return 1; } -extern void pnpide_init(void); +extern int pnpide_init(void); extern void h8300_ide_init(void); /* --- linux-2.6.8-rc1/drivers/ide/ide-cd.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/ide-cd.c 2004-07-13 17:09:50.000000000 -0700 @@ -1940,6 +1940,8 @@ static ide_startstop_t cdrom_start_write info->dma = drive->using_dma ? 1 : 0; info->cmd = WRITE; + info->devinfo.media_written = 1; + /* Start sending the write request to the drive. */ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); } @@ -1967,13 +1969,17 @@ static ide_startstop_t cdrom_do_block_pc * sg request */ if (rq->bio) { - if (rq->data_len & 3) { - printk("%s: block pc not aligned, len=%d\n", drive->name, rq->data_len); - cdrom_end_request(drive, 0); - return ide_stopped; - } - info->dma = drive->using_dma; + int mask = drive->queue->dma_alignment; + unsigned long addr = (unsigned long) page_address(bio_page(rq->bio)); + info->cmd = rq_data_dir(rq); + info->dma = drive->using_dma; + + /* + * check if dma is safe + */ + if ((rq->data_len & mask) || (addr & mask)) + info->dma = 0; } /* Start sending the command to the drive. */ @@ -2003,7 +2009,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, str } CDROM_CONFIG_FLAGS(drive)->seeking = 0; } - if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) { + if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) { action = cdrom_start_seek(drive, block); } else { if (rq_data_dir(rq) == READ) @@ -2960,8 +2966,10 @@ int ide_cdrom_probe_capabilities (ide_dr CDROM_CONFIG_FLAGS(drive)->no_eject = 0; if (cap.cd_r_write) CDROM_CONFIG_FLAGS(drive)->cd_r = 1; - if (cap.cd_rw_write) + if (cap.cd_rw_write) { CDROM_CONFIG_FLAGS(drive)->cd_rw = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; + } if (cap.test_write) CDROM_CONFIG_FLAGS(drive)->test_write = 1; if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) @@ -3141,7 +3149,7 @@ int ide_cdrom_setup (ide_drive_t *drive) int nslots; blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn); - blk_queue_dma_alignment(drive->queue, 3); + blk_queue_dma_alignment(drive->queue, 31); drive->queue->unplug_delay = (1 * HZ) / 1000; if (!drive->queue->unplug_delay) drive->queue->unplug_delay = 1; --- linux-2.6.8-rc1/drivers/ide/ide-disk.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/ide-disk.c 2004-07-13 17:09:32.670306232 -0700 @@ -702,6 +702,37 @@ static u8 idedisk_dump_status (ide_drive } #endif /* FANCY_STATUS_DUMPS */ printk("\n"); + { + struct request *rq; + unsigned char opcode = 0; + int found = 0; + + spin_lock(&ide_lock); + rq = HWGROUP(drive)->rq; + spin_unlock(&ide_lock); + if (!rq) + goto out; + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + char *args = rq->buffer; + if (args) { + opcode = args[0]; + found = 1; + } + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + if (args) { + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; + found = 1; + } + } + printk("ide: failed opcode was: "); + if (!found) + printk("unknown\n"); + else + printk("0x%02x\n", opcode); + } +out: local_irq_restore(flags); return err; } @@ -1203,6 +1234,41 @@ static ide_proc_entry_t idedisk_proc[] = #endif /* CONFIG_PROC_FS */ +static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + ide_drive_t *drive = q->queuedata; + struct request *rq; + int ret; + + if (!drive->wcache) + return 0; + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + + memset(rq->cmd, 0, sizeof(rq->cmd)); + + if ((drive->id->cfs_enable_2 & 0x2400) == 0x2400) + rq->cmd[0] = WIN_FLUSH_CACHE_EXT; + else + rq->cmd[0] = WIN_FLUSH_CACHE; + + + rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER; + rq->buffer = rq->cmd; + + ret = blk_execute_rq(q, disk, rq); + + /* + * if we failed and caller wants error offset, get it + */ + if (ret && error_sector) + *error_sector = ide_get_error_location(drive, rq->cmd); + + blk_put_request(rq); + return ret; +} + /* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. @@ -1231,16 +1297,10 @@ static int set_nowerr(ide_drive_t *drive return 0; } -/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ -#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) - -/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */ -#define ide_id_has_flush_cache_ext(id) \ - (((id)->cfs_enable_2 & 0x2400) == 0x2400) - static int write_cache (ide_drive_t *drive, int arg) { ide_task_t args; + int err; if (!ide_id_has_flush_cache(drive->id)) return 1; @@ -1251,7 +1311,10 @@ static int write_cache (ide_drive_t *dri args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; args.command_type = IDE_DRIVE_TASK_NO_DATA; args.handler = &task_no_data_intr; - (void) ide_raw_taskfile(drive, &args, NULL); + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + return err; drive->wcache = arg; return 0; @@ -1412,6 +1475,7 @@ static void idedisk_setup (ide_drive_t * { struct hd_driveid *id = drive->id; unsigned long long capacity; + int barrier; idedisk_add_settings(drive); @@ -1543,6 +1607,28 @@ static void idedisk_setup (ide_drive_t * drive->wcache = 1; write_cache(drive, 1); + + /* + * decide if we can sanely support flushes and barriers on + * this drive. unfortunately not all drives advertise FLUSH_CACHE + * support even if they support it. So assume FLUSH_CACHE is there + * always. LBA48 drives are newer, so expect it to flag support + * properly. We can safely support FLUSH_CACHE on lba48, if capacity + * doesn't exceed lba28 + */ + barrier = 1; + if (drive->addressing == 1) { + barrier = ide_id_has_flush_cache(id); + if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id)) + barrier = 0; + } + + printk("%s: cache flushes %ssupported\n", + drive->name, barrier ? "" : "not "); + if (barrier) { + blk_queue_ordered(drive->queue, 1); + blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush); + } } static void ide_cacheflush_p(ide_drive_t *drive) --- linux-2.6.8-rc1/drivers/ide/ide-io.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/ide/ide-io.c 2004-07-13 17:09:31.327510368 -0700 @@ -54,38 +54,73 @@ #include #include -/** - * ide_end_request - complete an IDE I/O - * @drive: IDE device for the I/O - * @uptodate: - * @nr_sectors: number of sectors completed - * - * This is our end_request wrapper function. We complete the I/O - * update random number input and dequeue the request, which if - * it was tagged may be out of order. +static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq) +{ + char *buf = rq->cmd; + + /* + * reuse cdb space for ata command + */ + memset(buf, 0, sizeof(rq->cmd)); + + rq->flags |= REQ_DRIVE_TASK | REQ_STARTED; + rq->buffer = buf; + rq->buffer[0] = WIN_FLUSH_CACHE; + + if (ide_id_has_flush_cache_ext(drive->id)) + rq->buffer[0] = WIN_FLUSH_CACHE_EXT; +} + +/* + * preempt pending requests, and store this cache flush for immediate + * execution */ - -int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +static struct request *ide_queue_flush_cmd(ide_drive_t *drive, + struct request *rq, int post) { - struct request *rq; - unsigned long flags; - int ret = 1; + struct request *flush_rq = &HWGROUP(drive)->wrq; - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; + /* + * write cache disabled, just return barrier write immediately + */ + if (!drive->wcache) + return rq; - BUG_ON(!(rq->flags & REQ_STARTED)); + ide_init_drive_cmd(flush_rq); + ide_fill_flush_cmd(drive, flush_rq); - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; + flush_rq->special = rq; + flush_rq->nr_sectors = rq->nr_sectors; + + if (!post) { + drive->doing_barrier = 1; + flush_rq->flags |= REQ_BAR_PREFLUSH; + blkdev_dequeue_request(rq); + } else + flush_rq->flags |= REQ_BAR_POSTFLUSH; + + __elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0); + HWGROUP(drive)->rq = NULL; + return flush_rq; +} + +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + int ret = 1; + + BUG_ON(!(rq->flags & REQ_STARTED)); /* * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && !uptodate) + if (blk_noretry_request(rq) && end_io_error(uptodate)) nr_sectors = rq->hard_nr_sectors; + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO @@ -97,15 +132,56 @@ int ide_end_request (ide_drive_t *drive, if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); + + if (blk_rq_tagged(rq)) + blk_queue_end_tag(drive->queue, rq); + blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; } - spin_unlock_irqrestore(&ide_lock, flags); return ret; } +/** + * ide_end_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * This is our end_request wrapper function. We complete the I/O + * update random number input and dequeue the request, which if + * it was tagged may be out of order. + */ + +int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + + if (!nr_sectors) + nr_sectors = rq->hard_cur_sectors; + + if (!blk_barrier_rq(rq)) + ret = __ide_end_request(drive, rq, uptodate, nr_sectors); + else { + struct request *flush_rq = &HWGROUP(drive)->wrq; + + flush_rq->nr_sectors -= nr_sectors; + if (!flush_rq->nr_sectors) { + ide_queue_flush_cmd(drive, rq, 1); + ret = 0; + } + } + + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} EXPORT_SYMBOL(ide_end_request); /** @@ -137,6 +213,113 @@ static void ide_complete_pm_request (ide spin_unlock_irqrestore(&ide_lock, flags); } +/* + * FIXME: probably move this somewhere else, name is bad too :) + */ +u64 ide_get_error_location(ide_drive_t *drive, char *args) +{ + u32 high, low; + u8 hcyl, lcyl, sect; + u64 sector; + + high = 0; + hcyl = args[5]; + lcyl = args[4]; + sect = args[3]; + + if (ide_id_has_flush_cache_ext(drive->id)) { + low = (hcyl << 16) | (lcyl << 8) | sect; + HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + } else { + u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); + if (cur & 0x40) + low = (hcyl << 16) | (lcyl << 8) | sect; + else { + low = hcyl * drive->head * drive->sect; + low += lcyl * drive->sect; + low += sect - 1; + } + } + + sector = ((u64) high << 24) | low; + return sector; +} +EXPORT_SYMBOL(ide_get_error_location); + +static void ide_complete_barrier(ide_drive_t *drive, struct request *rq, + int error) +{ + struct request *real_rq = rq->special; + int good_sectors, bad_sectors; + sector_t sector; + + if (!error) { + if (blk_barrier_postflush(rq)) { + /* + * this completes the barrier write + */ + __ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors); + drive->doing_barrier = 0; + } else { + /* + * just indicate that we did the pre flush + */ + real_rq->flags |= REQ_BAR_PREFLUSH; + elv_requeue_request(drive->queue, real_rq); + } + /* + * all is fine, return + */ + return; + } + + /* + * we need to end real_rq, but it's not on the queue currently. + * put it back on the queue, so we don't have to special case + * anything else for completing it + */ + if (!blk_barrier_postflush(rq)) + elv_requeue_request(drive->queue, real_rq); + + /* + * drive aborted flush command, assume FLUSH_CACHE_* doesn't + * work and disable barrier support + */ + if (error & ABRT_ERR) { + printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name); + __ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors); + blk_queue_ordered(drive->queue, 0); + blk_queue_issue_flush_fn(drive->queue, NULL); + } else { + /* + * find out what part of the request failed + */ + good_sectors = 0; + if (blk_barrier_postflush(rq)) { + sector = ide_get_error_location(drive, rq->buffer); + + if ((sector >= real_rq->hard_sector) && + (sector < real_rq->hard_sector + real_rq->hard_nr_sectors)) + good_sectors = sector - real_rq->hard_sector; + } else + sector = real_rq->hard_sector; + + bad_sectors = real_rq->hard_nr_sectors - good_sectors; + if (good_sectors) + __ide_end_request(drive, real_rq, 1, good_sectors); + if (bad_sectors) + __ide_end_request(drive, real_rq, 0, bad_sectors); + + printk(KERN_ERR "%s: failed barrier write: " + "sector=%Lx(good=%d/bad=%d)\n", + drive->name, (unsigned long long)sector, + good_sectors, bad_sectors); + } + + drive->doing_barrier = 0; +} + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -226,6 +409,10 @@ void ide_end_drive_cmd (ide_drive_t *dri spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); + + if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq)) + ide_complete_barrier(drive, rq, err); + HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&ide_lock, flags); @@ -712,6 +899,22 @@ static inline ide_drive_t *choose_drive repeat: best = NULL; drive = hwgroup->drive; + + /* + * drive is doing pre-flush, ordered write, post-flush sequence. even + * though that is 3 requests, it must be seen as a single transaction. + * we must not preempt this drive until that is complete + */ + if (drive->doing_barrier) { + /* + * small race where queue could get replugged during + * the 3-request flush cycle, just yank the plug since + * we want it to finish asap + */ + blk_remove_plug(drive->queue); + return drive; + } + do { if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) && !elv_queue_empty(drive->queue)) { @@ -868,6 +1071,13 @@ void ide_do_request (ide_hwgroup_t *hwgr } /* + * if rq is a barrier write, issue pre cache flush if not + * already done + */ + if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq)) + rq = ide_queue_flush_cmd(drive, rq, 0); + + /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as * blk_stop_queue() doesn't prevent the elv_next_request() @@ -917,7 +1127,9 @@ EXPORT_SYMBOL(ide_do_request); */ void do_ide_request(request_queue_t *q) { - ide_do_request(q->queuedata, IDE_NO_IRQ); + ide_drive_t *drive = q->queuedata; + + ide_do_request(HWGROUP(drive), IDE_NO_IRQ); } /* @@ -1286,6 +1498,7 @@ void ide_init_drive_cmd (struct request { memset(rq, 0, sizeof(*rq)); rq->flags = REQ_DRIVE_CMD; + rq->ref_count = 1; } EXPORT_SYMBOL(ide_init_drive_cmd); --- linux-2.6.8-rc1/drivers/ide/ide-pnp.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/ide/ide-pnp.c 2004-07-13 17:09:44.000000000 -0700 @@ -69,7 +69,21 @@ static struct pnp_driver idepnp_driver = .remove = idepnp_remove, }; -void __init pnpide_init(void) +int __init pnpide_init(void) { - pnp_register_driver(&idepnp_driver); + return pnp_register_driver(&idepnp_driver); } + +#ifdef MODULE +static void __exit pnpide_exit(void) +{ + pnp_unregister_driver(&idepnp_driver); +} + +module_init(pnpide_init); +module_exit(pnpide_exit); +#endif + +MODULE_AUTHOR("Andrey Panin"); +MODULE_DESCRIPTION("Enabler for ISAPNP IDE devices"); +MODULE_LICENSE("GPL"); --- linux-2.6.8-rc1/drivers/ide/ide-probe.c 2004-06-15 23:29:41.000000000 -0700 +++ 25/drivers/ide/ide-probe.c 2004-07-13 17:09:31.166534840 -0700 @@ -893,7 +893,7 @@ static int ide_init_queue(ide_drive_t *d if (!q) return 1; - q->queuedata = HWGROUP(drive); + q->queuedata = drive; blk_queue_segment_boundary(q, 0xffff); if (!hwif->rqsize) --- linux-2.6.8-rc1/drivers/ide/ide-taskfile.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/ide-taskfile.c 2004-07-13 17:09:41.000000000 -0700 @@ -303,188 +303,7 @@ static inline void task_buffer_multi_sec task_buffer_sectors(drive, rq, nsect, rw); } -/* - * old taskfile PIO handlers, to be killed as soon as possible. - */ -#ifndef CONFIG_IDE_TASKFILE_IO - -/* - * Handler for command with PIO data-in phase, READ - */ -ide_startstop_t task_in_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); - u8 stat; - - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { - return DRIVER(drive)->error(drive, "task_in_intr", stat); - } - if (!(stat & BUSY_STAT)) { - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - } - - task_buffer_sectors(drive, rq, 1, IDE_PIO_IN); - - /* FIXME: check drive status */ - if (!rq->current_nr_sectors) - if (!DRIVER(drive)->end_request(drive, 1, 0)) - return ide_stopped; - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; -} - -EXPORT_SYMBOL(task_in_intr); - -/* - * Handler for command with Read Multiple - */ -ide_startstop_t task_mulin_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = HWGROUP(drive)->rq; - u8 stat; - - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { - return DRIVER(drive)->error(drive, "task_mulin_intr", stat); - } - /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - - task_buffer_multi_sectors(drive, rq, IDE_PIO_IN); - - /* FIXME: check drive status */ - if (!rq->current_nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); - return ide_stopped; - } - - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; -} - -EXPORT_SYMBOL(task_mulin_intr); - -/* - * VERIFY ME before 2.4 ... unexpected race is possible based on details - * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. - */ -ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", - drive->name, - drive->addressing ? "_EXT" : ""); - return startstop; - } - /* For Write_sectors we need to stuff the first sector */ - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - task_buffer_sectors(drive, rq, 1, IDE_PIO_OUT); - - return ide_started; -} - -EXPORT_SYMBOL(pre_task_out_intr); - -/* - * Handler for command with PIO data-out phase WRITE - * - * WOOHOO this is a CORRECT STATE DIAGRAM NOW, - */ -ide_startstop_t task_out_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = HWGROUP(drive)->rq; - u8 stat; - - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) { - return DRIVER(drive)->error(drive, "task_out_intr", stat); - } - /* - * Safe to update request for partial completions. - * We have a good STATUS CHECK!!! - */ - if (!rq->current_nr_sectors) - if (!DRIVER(drive)->end_request(drive, 1, 0)) - return ide_stopped; - if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { - task_buffer_sectors(drive, rq, 1, IDE_PIO_OUT); - } - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - return ide_started; -} - -EXPORT_SYMBOL(task_out_intr); - -ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", - drive->name, - drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); - return startstop; - } - if (!(drive_is_ready(drive))) { - int i; - for (i=0; i<100; i++) { - if (drive_is_ready(drive)) - break; - } - } - - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - task_buffer_multi_sectors(drive, rq, IDE_PIO_OUT); - - return ide_started; -} - -EXPORT_SYMBOL(pre_task_mulout_intr); - -/* - * Handler for command write multiple - */ -ide_startstop_t task_mulout_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT) || !rq->current_nr_sectors) { - if (stat & (ERR_STAT|DRQ_STAT)) { - return DRIVER(drive)->error(drive, "task_mulout_intr", stat); - } - /* Handle last IRQ, occurs after all data was sent. */ - if (!rq->current_nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); - return ide_stopped; - } - /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - - task_buffer_multi_sectors(drive, rq, IDE_PIO_OUT); - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} - -EXPORT_SYMBOL(task_mulout_intr); - -#else /* !CONFIG_IDE_TASKFILE_IO */ - +#ifdef CONFIG_IDE_TASKFILE_IO static void task_sectors(ide_drive_t *drive, struct request *rq, unsigned nsect, unsigned rw) { @@ -523,6 +342,10 @@ static void task_multi_sectors(ide_drive } else /* task request */ task_buffer_multi_sectors(drive, rq, rw); } +#else +# define task_sectors(d, rq, nsect, rw) task_buffer_sectors(d, rq, nsect, rw) +# define task_multi_sectors(d, rq, rw) task_buffer_multi_sectors(d, rq, rw) +#endif /* CONFIG_IDE_TASKFILE_IO */ static u8 wait_drive_not_busy(ide_drive_t *drive) { @@ -544,6 +367,36 @@ static u8 wait_drive_not_busy(ide_drive_ return stat; } +#ifdef CONFIG_IDE_TASKFILE_IO +static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, + const char *s, u8 stat, unsigned cur_bad) +{ + if (rq->bio) { + int sectors = rq->hard_nr_sectors - rq->nr_sectors - cur_bad; + + if (sectors > 0) + drive->driver->end_request(drive, 1, sectors); + } + return drive->driver->error(drive, s, stat); +} +#else +# define task_error(d, rq, s, stat, cur_bad) drive->driver->error(d, s, stat) +#endif + +static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) +{ + if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *task = rq->special; + + if (task->tf_out_flags.all) { + u8 err = drive->hwif->INB(IDE_ERROR_REG); + ide_end_drive_cmd(drive, stat, err); + return; + } + } + drive->driver->end_request(drive, 1, rq->hard_nr_sectors); +} + /* * Handler for command with PIO data-in phase (Read). */ @@ -554,24 +407,11 @@ ide_startstop_t task_in_intr (ide_drive_ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - /* BUSY_STAT: No data yet, so wait for another IRQ. */ + return task_error(drive, rq, __FUNCTION__, stat, 0); + /* No data yet, so wait for another IRQ. */ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; } -finish_rq: - /* - * Complete previously submitted bios (if any). - * Status was already verifyied. - */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; - /* Complete rq->buffer based request (ioctls). */ - if (!rq->bio && !rq->nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); - return ide_stopped; - } task_sectors(drive, rq, 1, IDE_PIO_IN); @@ -579,8 +419,9 @@ finish_rq: if (!rq->nr_sectors) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_R_STAT)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - goto finish_rq; + return task_error(drive, rq, __FUNCTION__, stat, 1); + task_end_request(drive, rq, stat); + return ide_stopped; } /* Still data left to transfer. */ @@ -600,24 +441,11 @@ ide_startstop_t task_mulin_intr (ide_dri if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - /* BUSY_STAT: No data yet, so wait for another IRQ. */ + return task_error(drive, rq, __FUNCTION__, stat, 0); + /* No data yet, so wait for another IRQ. */ ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); return ide_started; } -finish_rq: - /* - * Complete previously submitted bios (if any). - * Status was already verifyied. - */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; - /* Complete rq->buffer based request (ioctls). */ - if (!rq->bio && !rq->nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); - return ide_stopped; - } task_multi_sectors(drive, rq, IDE_PIO_IN); @@ -625,8 +453,9 @@ finish_rq: if (!rq->nr_sectors) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_R_STAT)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - goto finish_rq; + return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); + task_end_request(drive, rq, stat); + return ide_stopped; } /* Still data left to transfer. */ @@ -645,38 +474,21 @@ ide_startstop_t task_out_intr (ide_drive u8 stat; stat = HWIF(drive)->INB(IDE_STATUS_REG); - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) { - if ((stat & (ERR_STAT | DRQ_STAT)) || - ((stat & WRERR_STAT) && !drive->nowerr)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - if (stat & BUSY_STAT) { - /* Not ready yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - } + if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) + return task_error(drive, rq, __FUNCTION__, stat, 1); /* Deal with unexpected ATA data phase. */ - if ((!(stat & DATA_READY) && rq->nr_sectors) || - ((stat & DATA_READY) && !rq->nr_sectors)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - - /* - * Complete previously submitted bios (if any). - * Status was already verifyied. - */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; - /* Complete rq->buffer based request (ioctls). */ - if (!rq->bio && !rq->nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); + if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) + return task_error(drive, rq, __FUNCTION__, stat, 1); + + if (!rq->nr_sectors) { + task_end_request(drive, rq, stat); return ide_stopped; } /* Still data left to transfer. */ - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); task_sectors(drive, rq, 1, IDE_PIO_OUT); + ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); return ide_started; } @@ -697,7 +509,10 @@ ide_startstop_t pre_task_out_intr (ide_d if (!drive->unmask) local_irq_disable(); - return task_out_intr(drive); + ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); + task_sectors(drive, rq, 1, IDE_PIO_OUT); + + return ide_started; } EXPORT_SYMBOL(pre_task_out_intr); @@ -710,38 +525,21 @@ ide_startstop_t task_mulout_intr (ide_dr u8 stat; stat = HWIF(drive)->INB(IDE_STATUS_REG); - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) { - if ((stat & (ERR_STAT | DRQ_STAT)) || - ((stat & WRERR_STAT) && !drive->nowerr)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - if (stat & BUSY_STAT) { - /* Not ready yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - } + if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) + return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); /* Deal with unexpected ATA data phase. */ - if ((!(stat & DATA_READY) && rq->nr_sectors) || - ((stat & DATA_READY) && !rq->nr_sectors)) - return DRIVER(drive)->error(drive, __FUNCTION__, stat); - - /* - * Complete previously submitted bios (if any). - * Status was already verifyied. - */ - while (rq->bio != rq->cbio) - if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) - return ide_stopped; - /* Complete rq->buffer based request (ioctls). */ - if (!rq->bio && !rq->nr_sectors) { - DRIVER(drive)->end_request(drive, 1, 0); + if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) + return task_error(drive, rq, __FUNCTION__, stat, drive->mult_count); + + if (!rq->nr_sectors) { + task_end_request(drive, rq, stat); return ide_stopped; } /* Still data left to transfer. */ - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); task_multi_sectors(drive, rq, IDE_PIO_OUT); + ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); return ide_started; } @@ -761,12 +559,13 @@ ide_startstop_t pre_task_mulout_intr (id if (!drive->unmask) local_irq_disable(); - return task_mulout_intr(drive); + ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); + task_multi_sectors(drive, rq, IDE_PIO_OUT); + + return ide_started; } EXPORT_SYMBOL(pre_task_mulout_intr); -#endif /* !CONFIG_IDE_TASKFILE_IO */ - int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) { struct request rq; @@ -813,13 +612,6 @@ EXPORT_SYMBOL(ide_raw_taskfile); #define MAX_DMA (256*SECTOR_WORDS) ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *); -ide_startstop_t flagged_task_no_data_intr(ide_drive_t *); -ide_startstop_t flagged_task_in_intr(ide_drive_t *); -ide_startstop_t flagged_task_mulin_intr(ide_drive_t *); -ide_startstop_t flagged_pre_task_out_intr(ide_drive_t *, struct request *); -ide_startstop_t flagged_task_out_intr(ide_drive_t *); -ide_startstop_t flagged_pre_task_mulout_intr(ide_drive_t *, struct request *); -ide_startstop_t flagged_task_mulout_intr(ide_drive_t *); int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { @@ -918,23 +710,13 @@ int ide_taskfile_ioctl (ide_drive_t *dri err = -EPERM; goto abort; } - if (args.tf_out_flags.all != 0) { - args.prehandler = &flagged_pre_task_mulout_intr; - args.handler = &flagged_task_mulout_intr; - } else { - args.prehandler = &pre_task_mulout_intr; - args.handler = &task_mulout_intr; - } + args.prehandler = &pre_task_mulout_intr; + args.handler = &task_mulout_intr; err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_OUT: - if (args.tf_out_flags.all != 0) { - args.prehandler = &flagged_pre_task_out_intr; - args.handler = &flagged_task_out_intr; - } else { - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - } + args.prehandler = &pre_task_out_intr; + args.handler = &task_out_intr; err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_MULTI_IN: @@ -946,27 +728,15 @@ int ide_taskfile_ioctl (ide_drive_t *dri err = -EPERM; goto abort; } - if (args.tf_out_flags.all != 0) { - args.handler = &flagged_task_mulin_intr; - } else { - args.handler = &task_mulin_intr; - } + args.handler = &task_mulin_intr; err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_IN: - if (args.tf_out_flags.all != 0) { - args.handler = &flagged_task_in_intr; - } else { - args.handler = &task_in_intr; - } + args.handler = &task_in_intr; err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_NO_DATA: - if (args.tf_out_flags.all != 0) { - args.handler = &flagged_task_no_data_intr; - } else { - args.handler = &task_no_data_intr; - } + args.handler = &task_no_data_intr; err = ide_diag_taskfile(drive, &args, 0, NULL); break; default: @@ -1239,226 +1009,15 @@ ide_startstop_t flagged_taskfile (ide_dr return ide_stopped; /* Issue the command */ + if (task->prehandler) { + hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); + ndelay(400); /* FIXME */ + return task->prehandler(drive, task->rq); + } ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - if (task->prehandler != NULL) - return task->prehandler(drive, HWGROUP(drive)->rq); } return ide_started; } EXPORT_SYMBOL(flagged_taskfile); - -ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat; - - local_irq_enable(); - - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) { - if (stat & ERR_STAT) { - return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat); - } - /* - * (ks) Unexpected ATA data phase detected. - * This should not happen. But, it can ! - * I am not sure, which function is best to clean up - * this situation. I choose: ide_error(...) - */ - return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); - } - - ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); - - return ide_stopped; -} - -/* - * Handler for command with PIO data-in phase - */ -ide_startstop_t flagged_task_in_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - int retries = 5; - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & ERR_STAT) { - return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat); - } - /* - * (ks) Unexpected ATA data phase detected. - * This should not happen. But, it can ! - * I am not sure, which function is best to clean up - * this situation. I choose: ide_error(...) - */ - return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); - } - - task_buffer_sectors(drive, rq, 1, IDE_PIO_IN); - - if (rq->current_nr_sectors) { - /* - * (ks) We don't know which command was executed. - * So, we wait the 'WORSTCASE' value. - */ - ide_set_handler(drive, &flagged_task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - /* - * (ks) Last sector was transfered, wait until drive is ready. - * This can take up to 10 usec. We willl wait max 50 us. - */ - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(10); - ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG)); - - return ide_stopped; -} - -ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - int retries = 5; - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & ERR_STAT) { - return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat); - } - /* - * (ks) Unexpected ATA data phase detected. - * This should not happen. But, it can ! - * I am not sure, which function is best to clean up - * this situation. I choose: ide_error(...) - */ - return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); - } - - task_buffer_multi_sectors(drive, rq, IDE_PIO_IN); - - if (rq->current_nr_sectors != 0) { - /* - * (ks) We don't know which command was executed. - * So, we wait the 'WORSTCASE' value. - */ - ide_set_handler(drive, &flagged_task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } - - /* - * (ks) Last sector was transfered, wait until drive is ready. - * This can take up to 10 usec. We willl wait max 50 us. - */ - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(10); - ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG)); - - return ide_stopped; -} - -/* - * Pre handler for command with PIO data-out phase - */ -ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - BAD_W_STAT, WAIT_DRQ)) { - printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name); - return startstop; - } - - task_buffer_sectors(drive, rq, 1, IDE_PIO_OUT); - - return ide_started; -} - -ide_startstop_t flagged_task_out_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - - if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) - return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat); - - if (!rq->current_nr_sectors) { - ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG)); - return ide_stopped; - } - - if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) { - /* - * (ks) Unexpected ATA data phase detected. - * This should not happen. But, it can ! - * I am not sure, which function is best to clean up - * this situation. I choose: ide_error(...) - */ - return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); - } - - task_buffer_sectors(drive, rq, 1, IDE_PIO_OUT); - - /* - * (ks) We don't know which command was executed. - * So, we wait the 'WORSTCASE' value. - */ - ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} - -ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop, drive, DATA_READY, - BAD_W_STAT, WAIT_DRQ)) { - printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name); - return startstop; - } - - task_buffer_multi_sectors(drive, rq, IDE_PIO_OUT); - - return ide_started; -} - -ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - - if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) - return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat); - - if (!rq->current_nr_sectors) { - ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG)); - return ide_stopped; - } - - if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) { - /* - * (ks) Unexpected ATA data phase detected. - * This should not happen. But, it can ! - * I am not sure, which function is best to clean up - * this situation. I choose: ide_error(...) - */ - return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); - } - - task_buffer_multi_sectors(drive, rq, IDE_PIO_OUT); - - /* - * (ks) We don't know which command was executed. - * So, we wait the 'WORSTCASE' value. - */ - ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL); - - return ide_started; -} --- linux-2.6.8-rc1/drivers/ide/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/Kconfig 2004-07-13 17:09:44.000000000 -0700 @@ -325,7 +325,7 @@ config BLK_DEV_CMD640_ENHANCED Otherwise say N. config BLK_DEV_IDEPNP - bool "PNP EIDE support" + tristate "PNP EIDE support" depends on PNP help If you have a PnP (Plug and Play) compatible EIDE card and --- linux-2.6.8-rc1/drivers/ide/legacy/ide-cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/legacy/ide-cs.c 2004-07-13 17:09:13.000000000 -0700 @@ -230,7 +230,7 @@ void ide_config(dev_link_t *link) cisparse_t parse; config_info_t conf; cistpl_cftable_entry_t dflt; - } *stk = 0; + } *stk = NULL; cistpl_cftable_entry_t *cfg; int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0; unsigned long io_base, ctl_base; --- linux-2.6.8-rc1/drivers/ide/Makefile 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/Makefile 2004-07-13 17:09:44.000000000 -0700 @@ -23,7 +23,6 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += set ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o ide-core-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o ide-core-$(CONFIG_PROC_FS) += ide-proc.o -ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o # built-in only drivers from arm/ ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o @@ -44,6 +43,7 @@ ide-core-$(CONFIG_H8300) += h8300/ide-h obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o obj-$(CONFIG_IDE_GENERIC) += ide-generic.o +obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o --- linux-2.6.8-rc1/drivers/ide/pci/siimage.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ide/pci/siimage.c 2004-07-13 17:09:13.000000000 -0700 @@ -1007,7 +1007,7 @@ static void __devinit init_iops_siimage( pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - hwif->hwif_data = 0; + hwif->hwif_data = NULL; hwif->rqsize = 128; if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0])) --- linux-2.6.8-rc1/drivers/ieee1394/csr1212.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/ieee1394/csr1212.c 2004-07-13 17:09:21.000000000 -0700 @@ -87,7 +87,8 @@ static const u_int8_t csr1212_key_id_typ static inline void free_keyval(struct csr1212_keyval *kv) { - if (kv->key.type == CSR1212_KV_TYPE_LEAF) + if ((kv->key.type == CSR1212_KV_TYPE_LEAF) && + (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)) CSR1212_FREE(kv->value.leaf.data); CSR1212_FREE(kv); @@ -155,7 +156,7 @@ static inline struct csr1212_keyval *csr { struct csr1212_keyval *kv; - for (kv = kv_list; kv != NULL; kv = kv->next) { + for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) { if (kv->offset == offset) return kv; } @@ -181,9 +182,9 @@ struct csr1212_csr *csr1212_create_csr(s return NULL; } - /* The keyval key id is not used for the root node, but a valid key id - * that can be used for a directory needs to be passed to - * csr1212_new_directory(). */ + /* The keyval key id is not used for the root node, but a valid key id + * that can be used for a directory needs to be passed to + * csr1212_new_directory(). */ csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR); if (!csr->root_kv) { CSR1212_FREE(csr->cache_head); @@ -709,7 +710,7 @@ void _csr1212_destroy_keyval(struct csr1 tail->next = k->value.directory.dentries_head; k->value.directory.dentries_head->prev = tail; tail = k->value.directory.dentries_tail; - } + } } free_keyval(k); k = a; @@ -796,7 +797,8 @@ static int csr1212_append_new_cache(stru return CSR1212_ENOMEM; } cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; - cache->ext_rom->value.leaf.len = 0; + cache->ext_rom->value.leaf.len = -1; + cache->ext_rom->value.leaf.data = cache->data; /* Add cache to tail of cache list */ cache->prev = csr->cache_tail; @@ -864,20 +866,20 @@ static int csr1212_generate_layout_subdi default: case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_CSR_OFFSET: - continue; + break; case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_DIRECTORY: /* Remove from list */ - if (dkv->prev) + if (dkv->prev && (dkv->prev->next == dkv)) dkv->prev->next = dkv->next; - if (dkv->next) + if (dkv->next && (dkv->next->prev == dkv)) dkv->next->prev = dkv->prev; - if (dkv == *layout_tail) - *layout_tail = dkv->prev; + //if (dkv == *layout_tail) + // *layout_tail = dkv->prev; /* Special case: Extended ROM leafs */ if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { - dkv->value.leaf.len = 0; /* initialize to zero */ + dkv->value.leaf.len = -1; /* Don't add Extended ROM leafs in the layout list, * they are handled differently. */ break; @@ -919,8 +921,8 @@ size_t csr1212_generate_layout_order(str } struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, - struct csr1212_keyval *start_kv, - int start_pos) + struct csr1212_keyval *start_kv, + int start_pos) { struct csr1212_keyval *kv = start_kv; struct csr1212_keyval *okv = start_kv; @@ -930,7 +932,10 @@ struct csr1212_keyval *csr1212_generate_ cache->layout_head = kv; while(kv && pos < cache->size) { - kv->offset = cache->offset + pos; + /* Special case: Extended ROM leafs */ + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { + kv->offset = cache->offset + pos; + } switch(kv->key.type) { case CSR1212_KV_TYPE_LEAF: @@ -1090,6 +1095,9 @@ int csr1212_generate_csr_image(struct cs bi->crc_length = bi->length; bi->crc = csr1212_crc16(bi->data, bi->crc_length); + csr->root_kv->next = NULL; + csr->root_kv->prev = NULL; + agg_size = csr1212_generate_layout_order(csr->root_kv); init_offset = csr->bus_info_len; @@ -1158,6 +1166,17 @@ int csr1212_generate_csr_image(struct cs /* Copy the data into the cache buffer */ csr1212_fill_cache(cache); + + if (cache != csr->cache_head) { + /* Set the length and CRC of the extended ROM. */ + struct csr1212_keyval_img *kvi = + (struct csr1212_keyval_img*)cache->data; + + kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1); + kvi->crc = csr1212_crc16(kvi->data, + bytes_to_quads(cache->len) - 1); + + } } return CSR1212_SUCCESS; @@ -1174,11 +1193,6 @@ int csr1212_read(struct csr1212_csr *csr &cache->data[bytes_to_quads(offset - cache->offset)], len); return CSR1212_SUCCESS; - } else if (((offset < cache->offset) && - ((offset + len) >= cache->offset)) || - ((offset >= cache->offset) && - ((offset + len) > (cache->offset + cache->size)))) { - return CSR1212_EINVAL; } } return CSR1212_ENOENT; @@ -1227,8 +1241,8 @@ static int csr1212_parse_bus_info_block( return CSR1212_EINVAL; #if 0 - /* Apparently there are too many differnt wrong implementations of the - * CRC algorithm that verifying them is moot. */ + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) && (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc)) return CSR1212_EINVAL; @@ -1249,10 +1263,9 @@ static int csr1212_parse_bus_info_block( return CSR1212_SUCCESS; } -static inline int csr1212_parse_dir_entry(struct csr1212_keyval *dir, - csr1212_quad_t ki, - u_int32_t kv_pos, - struct csr1212_csr_rom_cache *cache) +static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, + csr1212_quad_t ki, + u_int32_t kv_pos) { int ret = CSR1212_SUCCESS; struct csr1212_keyval *k = NULL; @@ -1291,7 +1304,7 @@ static inline int csr1212_parse_dir_entr goto fail; } - k = csr1212_find_keyval_offset(cache->layout_head, offset); + k = csr1212_find_keyval_offset(dir, offset); if (k) break; /* Found it. */ @@ -1309,11 +1322,10 @@ static inline int csr1212_parse_dir_entr k->valid = 0; /* Contents not read yet so it's not valid. */ k->offset = offset; - k->prev = cache->layout_tail; - k->next = NULL; - if (cache->layout_tail) - cache->layout_tail->next = k; - cache->layout_tail = k; + k->prev = dir; + k->next = dir->next; + dir->next->prev = k; + dir->next = k; } ret = csr1212_attach_keyval_to_directory(dir, k); @@ -1325,6 +1337,7 @@ fail: return ret; } + int csr1212_parse_keyval(struct csr1212_keyval *kv, struct csr1212_csr_rom_cache *cache) { @@ -1338,8 +1351,8 @@ int csr1212_parse_keyval(struct csr1212_ kvi_len = CSR1212_BE16_TO_CPU(kvi->length); #if 0 - /* Apparently there are too many differnt wrong implementations of the - * CRC algorithm that verifying them is moot. */ + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) && (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) { ret = CSR1212_EINVAL; @@ -1353,22 +1366,19 @@ int csr1212_parse_keyval(struct csr1212_ csr1212_quad_t ki = kvi->data[i]; /* Some devices put null entries in their unit - * directories. If we come across such and entry, + * directories. If we come across such an entry, * then skip it. */ if (ki == 0x0) continue; ret = csr1212_parse_dir_entry(kv, ki, (kv->offset + - quads_to_bytes(i + 1)), - cache); + quads_to_bytes(i + 1))); } kv->value.directory.len = kvi_len; break; case CSR1212_KV_TYPE_LEAF: - if (kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { - kv->value.leaf.data = cache->data; - } else { + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len)); if (!kv->value.leaf.data) { @@ -1399,7 +1409,6 @@ int _csr1212_read_keyval(struct csr1212_ u_int32_t *cache_ptr; u_int16_t kv_len = 0; - if (!csr || !kv) return CSR1212_EINVAL; @@ -1413,7 +1422,7 @@ int _csr1212_read_keyval(struct csr1212_ if (!cache) { csr1212_quad_t q; - struct csr1212_csr_rom_cache *nc; + u_int32_t cache_size; /* Only create a new cache for Extended ROM leaves. */ if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) @@ -1425,12 +1434,20 @@ int _csr1212_read_keyval(struct csr1212_ return CSR1212_EIO; } - kv->value.leaf.len = quads_to_bytes(CSR1212_BE32_TO_CPU(q)>>16); + kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16; + + cache_size = (quads_to_bytes(kv->value.leaf.len + 1) + + (csr->max_rom - 1)) & ~(csr->max_rom - 1); - nc = csr1212_rom_cache_malloc(kv->offset, kv->value.leaf.len); - cache->next = nc; - nc->prev = cache; - csr->cache_tail = nc; + cache = csr1212_rom_cache_malloc(kv->offset, cache_size); + if (!cache) + return CSR1212_ENOMEM; + + kv->value.leaf.data = &cache->data[1]; + csr->cache_tail->next = cache; + cache->prev = csr->cache_tail; + cache->next = NULL; + csr->cache_tail = cache; cache->filled_head = CSR1212_MALLOC(sizeof(struct csr1212_cache_region)); if (!cache->filled_head) { @@ -1443,6 +1460,10 @@ int _csr1212_read_keyval(struct csr1212_ cache->filled_head->next = NULL; cache->filled_head->prev = NULL; cache->data[0] = q; + + /* Don't read the entire extended ROM now. Pieces of it will + * be read when entries inside it are read. */ + return csr1212_parse_keyval(kv, cache); } cache_index = kv->offset - cache->offset; @@ -1548,6 +1569,7 @@ int _csr1212_read_keyval(struct csr1212_ int csr1212_parse_csr(struct csr1212_csr *csr) { static const int mr_map[] = { 4, 64, 1024, 0 }; + struct csr1212_dentry *dentry; int ret; if (!csr || !csr->ops->bus_read) @@ -1570,7 +1592,21 @@ int csr1212_parse_csr(struct csr1212_csr csr->bus_info_len; csr->root_kv->valid = 0; + csr->root_kv->next = csr->root_kv; + csr->root_kv->prev = csr->root_kv; csr1212_get_keyval(csr, csr->root_kv); + /* Scan through the Root directory finding all extended ROM regions + * and make cache regions for them */ + for (dentry = csr->root_kv->value.directory.dentries_head; + dentry; dentry = dentry->next) { + if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { + csr1212_get_keyval(csr, dentry->kv); + + if (ret != CSR1212_SUCCESS) + return ret; + } + } + return CSR1212_SUCCESS; } --- linux-2.6.8-rc1/drivers/ieee1394/eth1394.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ieee1394/eth1394.c 2004-07-13 17:09:21.000000000 -0700 @@ -89,7 +89,7 @@ #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) static char version[] __devinitdata = - "$Rev: 1224 $ Ben Collins "; + "$Rev: 1231 $ Ben Collins "; struct fragment_info { struct list_head list; @@ -1796,7 +1796,7 @@ static int ether1394_ethtool_ioctl(struc case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, driver_name); - strcpy (info.version, "$Rev: 1224 $"); + strcpy (info.version, "$Rev: 1231 $"); /* FIXME XXX provide sane businfo */ strcpy (info.bus_info, "ieee1394"); if (copy_to_user (useraddr, &info, sizeof (info))) --- linux-2.6.8-rc1/drivers/ieee1394/ohci1394.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/ieee1394/ohci1394.c 2004-07-13 17:09:21.000000000 -0700 @@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_ printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) static char version[] __devinitdata = - "$Rev: 1223 $ Ben Collins "; + "$Rev: 1226 $ Ben Collins "; /* Module Parameters */ static int phys_dma = 1; @@ -2545,6 +2545,10 @@ static void insert_dma_buffer(struct dma idx = (idx + d->num_desc - 1 ) % d->num_desc; d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); + /* To avoid a race, ensure 1394 interface hardware sees the inserted + * context program descriptors before it sees the wakeup bit set. */ + wmb(); + /* wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { PRINT(KERN_INFO, --- linux-2.6.8-rc1/drivers/ieee1394/pcilynx.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/ieee1394/pcilynx.c 2004-07-13 17:09:21.000000000 -0700 @@ -500,7 +500,7 @@ static void send_next(struct ti_lynx *ly pcl.async_error_next = PCL_NEXT_INVALID; pcl.pcl_status = 0; pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; -#ifdef __BIG_ENDIAN +#ifndef __BIG_ENDIAN pcl.buffer[0].control |= PCL_BIGENDIAN; #endif pcl.buffer[0].pointer = d->header_dma; @@ -1697,7 +1697,7 @@ static int __devinit add_card(struct pci pcl.async_error_next = PCL_NEXT_INVALID; pcl.buffer[0].control = PCL_CMD_RCV | 16; -#ifdef __BIG_ENDIAN +#ifndef __BIG_ENDIAN pcl.buffer[0].control |= PCL_BIGENDIAN; #endif pcl.buffer[1].control = PCL_LAST_BUFF | 4080; --- linux-2.6.8-rc1/drivers/ieee1394/sbp2.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/ieee1394/sbp2.c 2004-07-13 17:09:21.000000000 -0700 @@ -78,7 +78,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 1219 $ Ben Collins "; + "$Rev: 1231 $ Ben Collins "; /* * Module load parameter definitions --- linux-2.6.8-rc1/drivers/input/gameport/emu10k1-gp.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/gameport/emu10k1-gp.c 2004-07-13 17:09:22.000000000 -0700 @@ -50,8 +50,11 @@ struct emu { }; static struct pci_device_id emu_tbl[] = { + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ + { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ + { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ { 0, } }; --- linux-2.6.8-rc1/drivers/input/joystick/gamecon.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/gamecon.c 2004-07-13 17:09:22.000000000 -0700 @@ -1,7 +1,8 @@ /* - * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $ + * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Peter Nelson * * Based on the work of: * Andree Borrmann John Dahlstrom @@ -9,10 +10,6 @@ */ /* - * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux - */ - -/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -72,8 +69,9 @@ __obsolete_setup("gc_3="); #define GC_MULTI2 5 #define GC_N64 6 #define GC_PSX 7 +#define GC_DDR 8 -#define GC_MAX 7 +#define GC_MAX 8 #define GC_REFRESH_TIME HZ/100 @@ -91,7 +89,8 @@ static struct gc *gc_base[3]; static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" + "PSX DDR controller" }; /* * N64 support. */ @@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ #define GC_PSX_CLOCK 0x04 /* Pin 4 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_COMMAND 0x01 /* Pin 2 */ #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ #define GC_PSX_SELECT 0x02 /* Pin 3 */ @@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay="); static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; +static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; /* * gc_psx_command() writes 8bit command and reads 8bit data from * the psx pad. */ -static int gc_psx_command(struct gc *gc, int b) +static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH]) { - int i, cmd, data = 0; + int i, j, cmd, read; + for (i = 0; i < 5; i++) + data[i] = 0; for (i = 0; i < 8; i++, b >>= 1) { cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(gc_psx_delay); - data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; + read = parport_read_status(gc->pd->port) ^ 0x80; + for (j = 0; j < 5; j++) + data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(gc_psx_delay); } - return data; } /* @@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, unsigned char *data) +static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5]) { - int i, id; + int i, j, max_len = 0; unsigned long flags; + unsigned char data2[5]; parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); local_irq_save(flags); - gc_psx_command(gc, 0x01); /* Access pad */ - id = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ - for (i = 0; i < GC_PSX_LEN(id) * 2; i++) - data[i] = gc_psx_command(gc, 0); - } else id = 0; + gc_psx_command(gc, 0x01, data2); /* Access pad */ + gc_psx_command(gc, 0x42, id); /* Get device ids */ + gc_psx_command(gc, 0, data2); /* Dump status */ + + for (i =0; i < 5; i++) /* Find the longest pad */ + if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len)) + max_len = GC_PSX_LEN(id[i]); + + for (i = 0; i < max_len * 2; i++) { /* Read in all the data */ + gc_psx_command(gc, 0, data2); + for (j = 0; j < 5; j++) + data[j][i] = data2[j]; + } local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); - return GC_PSX_ID(id); + for(i = 0; i < 5; i++) /* Set id's to the real value */ + id[i] = GC_PSX_ID(id[i]); } /* @@ -316,6 +328,7 @@ static void gc_timer(unsigned long priva struct gc *gc = (void *) private; struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; + unsigned char data_psx[5][GC_PSX_LENGTH]; int i, j, s; /* @@ -412,53 +425,72 @@ static void gc_timer(unsigned long priva * PSX controllers */ - if (gc->pads[GC_PSX]) { + if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { - for (i = 0; i < 5; i++) - if (gc->pads[GC_PSX] & gc_status_bit[i]) - break; + gc_psx_read_packet(gc, data_psx, data); - switch (gc_psx_read_packet(gc, data)) { + for (i = 0; i < 5; i++) { + switch (data[i]) { - case GC_PSX_RUMBLE: + case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); - input_sync(dev + i); + input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); - case GC_PSX_NEGCON: - case GC_PSX_ANALOG: + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; - case GC_PSX_NORMAL: + case GC_PSX_NORMAL: + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); - input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); + /* for some reason if the extra axes are left unset they drift */ + /* for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], 128); + * This needs to be debugged properly, + * maybe fuzz processing needs to be done in input_sync() + * --vojtech + */ + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; + + case 0: /* not a pad, ignore */ + break; + } } } @@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *c { struct gc *gc; struct parport *pp; - int i, j, psx; - unsigned char data[32]; + int i, j; if (config[0] < 0) return NULL; @@ -588,43 +619,22 @@ static struct gc __init *gc_probe(int *c break; case GC_PSX: + case GC_DDR: + if(config[i + 1] == GC_DDR) { + for (j = 0; j < 4; j++) + set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); + } else { + for (j = 0; j < 6; j++) { + set_bit(gc_psx_abs[j], gc->dev[i].absbit); + gc->dev[i].absmin[gc_psx_abs[j]] = 4; + gc->dev[i].absmax[gc_psx_abs[j]] = 252; + gc->dev[i].absflat[gc_psx_abs[j]] = 2; + } + } - psx = gc_psx_read_packet(gc, data); + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); - switch(psx) { - case GC_PSX_NEGCON: - case GC_PSX_NORMAL: - case GC_PSX_ANALOG: - case GC_PSX_RUMBLE: - - for (j = 0; j < 6; j++) { - psx = gc_psx_abs[j]; - set_bit(psx, gc->dev[i].absbit); - if (j < 4) { - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; - } else { - gc->dev[i].absmin[psx] = -1; - gc->dev[i].absmax[psx] = 1; - } - } - - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - - break; - - case 0: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); - break; - - default: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," - " please report to .\n", psx); - } break; } --- linux-2.6.8-rc1/drivers/input/joystick/grip.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/grip.c 2004-07-13 17:09:13.000000000 -0700 @@ -76,8 +76,8 @@ static int grip_abs_dc[] = { ABS_X, ABS_ static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital", "Gravis Xterminator Digital", "Gravis Xterminator DualControl" }; -static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; -static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; +static int *grip_abs[] = { NULL, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; +static int *grip_btn[] = { NULL, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; static char grip_anx[] = { 0, 0, 3, 5, 5 }; static char grip_cen[] = { 0, 0, 2, 2, 4 }; --- linux-2.6.8-rc1/drivers/input/joystick/grip_mp.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/grip_mp.c 2004-07-13 17:09:13.000000000 -0700 @@ -92,8 +92,8 @@ static int grip_btn_c64[] = { BTN_JOYSTI static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; -static int *grip_abs[] = { 0, 0, grip_abs_gp, grip_abs_c64 }; -static int *grip_btn[] = { 0, 0, grip_btn_gp, grip_btn_c64 }; +static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; +static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; --- linux-2.6.8-rc1/drivers/input/joystick/iforce/iforce.h 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/iforce/iforce.h 2004-07-13 17:09:22.000000000 -0700 @@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); /* Public variables */ -extern struct serio_dev iforce_serio_dev; +extern struct serio_driver iforce_serio_drv; extern struct usb_driver iforce_usb_driver; --- linux-2.6.8-rc1/drivers/input/joystick/iforce/iforce-main.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/iforce/iforce-main.c 2004-07-13 17:09:22.000000000 -0700 @@ -524,7 +524,7 @@ static int __init iforce_init(void) usb_register(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_register_device(&iforce_serio_dev); + serio_register_driver(&iforce_serio_drv); #endif return 0; } @@ -535,7 +535,7 @@ static void __exit iforce_exit(void) usb_deregister(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_device(&iforce_serio_dev); + serio_unregister_driver(&iforce_serio_drv); #endif } --- linux-2.6.8-rc1/drivers/input/joystick/iforce/iforce-serio.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/iforce/iforce-serio.c 2004-07-13 17:09:22.000000000 -0700 @@ -124,7 +124,7 @@ out: return IRQ_HANDLED; } -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) @@ -137,7 +137,7 @@ static void iforce_serio_connect(struct iforce->serio = serio; serio->private = iforce; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(iforce); return; } @@ -158,9 +158,13 @@ static void iforce_serio_disconnect(stru kfree(iforce); } -struct serio_dev iforce_serio_dev = { - .write_wakeup = iforce_serio_write_wakeup, - .interrupt = iforce_serio_irq, - .connect = iforce_serio_connect, - .disconnect = iforce_serio_disconnect, +struct serio_driver iforce_serio_drv = { + .driver = { + .name = "iforce", + }, + .description = "RS232 I-Force joysticks and wheels driver", + .write_wakeup = iforce_serio_write_wakeup, + .interrupt = iforce_serio_irq, + .connect = iforce_serio_connect, + .disconnect = iforce_serio_disconnect, }; --- linux-2.6.8-rc1/drivers/input/joystick/Kconfig 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/Kconfig 2004-07-13 17:09:22.000000000 -0700 @@ -247,7 +247,7 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. -config INPUT_JOYDUMP +config JOYSTICK_JOYDUMP tristate "Gameport data dumper" depends on INPUT && INPUT_JOYSTICK help --- linux-2.6.8-rc1/drivers/input/joystick/magellan.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/magellan.c 2004-07-13 17:09:22.000000000 -0700 @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -146,7 +148,7 @@ static void magellan_disconnect(struct s * it as an input device. */ -static void magellan_connect(struct serio *serio, struct serio_dev *dev) +static void magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; int i, t; @@ -184,7 +186,7 @@ static void magellan_connect(struct seri serio->private = magellan; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(magellan); return; } @@ -199,10 +201,14 @@ static void magellan_connect(struct seri * The serio device structure. */ -static struct serio_dev magellan_dev = { - .interrupt = magellan_interrupt, - .connect = magellan_connect, - .disconnect = magellan_disconnect, +static struct serio_driver magellan_drv = { + .driver = { + .name = "magellan", + }, + .description = DRIVER_DESC, + .interrupt = magellan_interrupt, + .connect = magellan_connect, + .disconnect = magellan_disconnect, }; /* @@ -211,13 +217,13 @@ static struct serio_dev magellan_dev = { int __init magellan_init(void) { - serio_register_device(&magellan_dev); + serio_register_driver(&magellan_drv); return 0; } void __exit magellan_exit(void) { - serio_unregister_device(&magellan_dev); + serio_unregister_driver(&magellan_drv); } module_init(magellan_init); --- linux-2.6.8-rc1/drivers/input/joystick/spaceball.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/spaceball.c 2004-07-13 17:09:22.000000000 -0700 @@ -39,8 +39,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -201,7 +203,7 @@ static void spaceball_disconnect(struct * it as an input device. */ -static void spaceball_connect(struct serio *serio, struct serio_dev *dev) +static void spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; int i, t, id; @@ -254,7 +256,7 @@ static void spaceball_connect(struct ser serio->private = spaceball; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceball); return; } @@ -269,10 +271,14 @@ static void spaceball_connect(struct ser * The serio device structure. */ -static struct serio_dev spaceball_dev = { - .interrupt = spaceball_interrupt, - .connect = spaceball_connect, - .disconnect = spaceball_disconnect, +static struct serio_driver spaceball_drv = { + .driver = { + .name = "spaceball", + }, + .description = DRIVER_DESC, + .interrupt = spaceball_interrupt, + .connect = spaceball_connect, + .disconnect = spaceball_disconnect, }; /* @@ -281,13 +287,13 @@ static struct serio_dev spaceball_dev = int __init spaceball_init(void) { - serio_register_device(&spaceball_dev); + serio_register_driver(&spaceball_drv); return 0; } void __exit spaceball_exit(void) { - serio_unregister_device(&spaceball_dev); + serio_unregister_driver(&spaceball_drv); } module_init(spaceball_init); --- linux-2.6.8-rc1/drivers/input/joystick/spaceorb.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/spaceorb.c 2004-07-13 17:09:22.000000000 -0700 @@ -38,8 +38,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -162,7 +164,7 @@ static void spaceorb_disconnect(struct s * it as an input device. */ -static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) +static void spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; int i, t; @@ -201,7 +203,7 @@ static void spaceorb_connect(struct seri serio->private = spaceorb; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceorb); return; } @@ -213,10 +215,14 @@ static void spaceorb_connect(struct seri * The serio device structure. */ -static struct serio_dev spaceorb_dev = { - .interrupt = spaceorb_interrupt, - .connect = spaceorb_connect, - .disconnect = spaceorb_disconnect, +static struct serio_driver spaceorb_drv = { + .driver = { + .name = "spaceorb", + }, + .description = DRIVER_DESC, + .interrupt = spaceorb_interrupt, + .connect = spaceorb_connect, + .disconnect = spaceorb_disconnect, }; /* @@ -225,13 +231,13 @@ static struct serio_dev spaceorb_dev = { int __init spaceorb_init(void) { - serio_register_device(&spaceorb_dev); + serio_register_driver(&spaceorb_drv); return 0; } void __exit spaceorb_exit(void) { - serio_unregister_device(&spaceorb_dev); + serio_unregister_driver(&spaceorb_drv); } module_init(spaceorb_init); --- linux-2.6.8-rc1/drivers/input/joystick/stinger.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/stinger.c 2004-07-13 17:09:22.000000000 -0700 @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gravis Stinger gamepad driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -134,7 +136,7 @@ static void stinger_disconnect(struct se * it as an input device. */ -static void stinger_connect(struct serio *serio, struct serio_dev *dev) +static void stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; int i; @@ -172,7 +174,7 @@ static void stinger_connect(struct serio stinger->dev.private = stinger; serio->private = stinger; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(stinger); return; } @@ -187,10 +189,14 @@ static void stinger_connect(struct serio * The serio device structure. */ -static struct serio_dev stinger_dev = { - .interrupt = stinger_interrupt, - .connect = stinger_connect, - .disconnect = stinger_disconnect, +static struct serio_driver stinger_drv = { + .driver = { + .name = "stinger", + }, + .description = DRIVER_DESC, + .interrupt = stinger_interrupt, + .connect = stinger_connect, + .disconnect = stinger_disconnect, }; /* @@ -199,13 +205,13 @@ static struct serio_dev stinger_dev = { int __init stinger_init(void) { - serio_register_device(&stinger_dev); + serio_register_driver(&stinger_drv); return 0; } void __exit stinger_exit(void) { - serio_unregister_device(&stinger_dev); + serio_unregister_driver(&stinger_drv); } module_init(stinger_init); --- linux-2.6.8-rc1/drivers/input/joystick/tmdc.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/tmdc.c 2004-07-13 17:09:51.000000000 -0700 @@ -322,7 +322,7 @@ static void tmdc_connect(struct gameport tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - if (tmdc->abs[i] < 0) continue; + if (*(tmdc->abs[i]) < 0) continue; set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; --- linux-2.6.8-rc1/drivers/input/joystick/twidjoy.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/twidjoy.c 2004-07-13 17:09:22.000000000 -0700 @@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct se * it as an input device. */ -static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +static void twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; @@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio twidjoy->dev.private = twidjoy; serio->private = twidjoy; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(twidjoy); return; } @@ -246,10 +246,14 @@ static void twidjoy_connect(struct serio * The serio device structure. */ -static struct serio_dev twidjoy_dev = { - .interrupt = twidjoy_interrupt, - .connect = twidjoy_connect, - .disconnect = twidjoy_disconnect, +static struct serio_driver twidjoy_drv = { + .driver = { + .name = "twidjoy", + }, + .description = DRIVER_DESC, + .interrupt = twidjoy_interrupt, + .connect = twidjoy_connect, + .disconnect = twidjoy_disconnect, }; /* @@ -258,13 +262,13 @@ static struct serio_dev twidjoy_dev = { int __init twidjoy_init(void) { - serio_register_device(&twidjoy_dev); + serio_register_driver(&twidjoy_drv); return 0; } void __exit twidjoy_exit(void) { - serio_unregister_device(&twidjoy_dev); + serio_unregister_driver(&twidjoy_drv); } module_init(twidjoy_init); --- linux-2.6.8-rc1/drivers/input/joystick/warrior.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/joystick/warrior.c 2004-07-13 17:09:22.000000000 -0700 @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Logitech WingMan Warrior joystick driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -139,7 +141,7 @@ static void warrior_disconnect(struct se * it as an input device. */ -static void warrior_connect(struct serio *serio, struct serio_dev *dev) +static void warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; int i; @@ -185,7 +187,7 @@ static void warrior_connect(struct serio serio->private = warrior; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(warrior); return; } @@ -199,10 +201,14 @@ static void warrior_connect(struct serio * The serio device structure. */ -static struct serio_dev warrior_dev = { - .interrupt = warrior_interrupt, - .connect = warrior_connect, - .disconnect = warrior_disconnect, +static struct serio_driver warrior_drv = { + .driver = { + .name = "warrior", + }, + .description = DRIVER_DESC, + .interrupt = warrior_interrupt, + .connect = warrior_connect, + .disconnect = warrior_disconnect, }; /* @@ -211,13 +217,13 @@ static struct serio_dev warrior_dev = { int __init warrior_init(void) { - serio_register_device(&warrior_dev); + serio_register_driver(&warrior_drv); return 0; } void __exit warrior_exit(void) { - serio_unregister_device(&warrior_dev); + serio_unregister_driver(&warrior_drv); } module_init(warrior_init); --- linux-2.6.8-rc1/drivers/input/keyboard/atkbd.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/keyboard/atkbd.c 2004-07-13 17:09:22.059919256 -0700 @@ -27,8 +27,10 @@ #include #include +#define DRIVER_DESC "AT and PS/2 keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static int atkbd_set = 2; @@ -47,6 +49,10 @@ static int atkbd_softrepeat; module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_softraw = 1; +module_param_named(softraw, atkbd_softraw, bool, 0); +MODULE_PARM_DESC(softraw, "Use software generated rawmode"); + static int atkbd_scroll; module_param_named(scroll, atkbd_scroll, bool, 0); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); @@ -164,34 +170,48 @@ static unsigned char atkbd_scroll_keys[5 { ATKBD_SCR_CLICK, 0x60 }, }; +#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */ +#define ATKBD_FLAG_CMD1 2 /* First byte of command response */ +#define ATKBD_FLAG_ID 3 /* First byte is not keyboard ID */ +#define ATKBD_FLAG_ENABLED 4 /* Waining for init to finish */ + /* * The atkbd control structure */ struct atkbd { - unsigned char keycode[512]; - struct input_dev dev; - struct serio *serio; + /* Written only during init */ char name[64]; char phys[32]; - unsigned short id; + struct serio *serio; + struct input_dev dev; + unsigned char set; - unsigned int translated:1; - unsigned int extra:1; - unsigned int write:1; + unsigned short id; + unsigned char keycode[512]; + unsigned char translated; + unsigned char extra; + unsigned char write; + + /* Protected by FLAG_ACK */ + unsigned char nak; + /* Protected by FLAG_CMD */ unsigned char cmdbuf[4]; unsigned char cmdcnt; - volatile signed char ack; - unsigned char emul; - unsigned int resend:1; - unsigned int release:1; - unsigned int bat_xl:1; - unsigned int enabled:1; + /* Accessed only from interrupt */ + unsigned char emul; + unsigned char resend; + unsigned char release; + unsigned char bat_xl; unsigned int last; unsigned long time; + + /* Flags */ + unsigned long flags; }; static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) @@ -224,7 +244,7 @@ static irqreturn_t atkbd_interrupt(struc #if !defined(__i386__) && !defined (__x86_64__) if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - printk("atkbd.c: frame/parity error: %02x\n", flags); + printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); atkbd->resend = 1; goto out; @@ -234,24 +254,45 @@ static irqreturn_t atkbd_interrupt(struc atkbd->resend = 0; #endif - if (!atkbd->ack) + if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) switch (code) { case ATKBD_RET_ACK: - atkbd->ack = 1; + atkbd->nak = 0; + if (atkbd->cmdcnt) { + set_bit(ATKBD_FLAG_CMD, &atkbd->flags); + set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + set_bit(ATKBD_FLAG_ID, &atkbd->flags); + } + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); goto out; case ATKBD_RET_NAK: - atkbd->ack = -1; + atkbd->nak = 1; + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); goto out; } - if (atkbd->cmdcnt) { - atkbd->cmdbuf[--atkbd->cmdcnt] = code; + if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) { + + atkbd->cmdcnt--; + atkbd->cmdbuf[atkbd->cmdcnt] = code; + + if (atkbd->cmdcnt == 1) { + if (code != 0xab && code != 0xac) + clear_bit(ATKBD_FLAG_ID, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + } + + if (!atkbd->cmdcnt) + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + goto out; } - if (!atkbd->enabled) + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) goto out; + input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + if (atkbd->translated) { if (atkbd->emul || @@ -270,6 +311,7 @@ static irqreturn_t atkbd_interrupt(struc switch (code) { case ATKBD_RET_BAT: + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); serio_rescan(atkbd->serio); goto out; case ATKBD_RET_EMUL0: @@ -300,6 +342,9 @@ static irqreturn_t atkbd_interrupt(struc code |= (atkbd->set != 3) ? 0x80 : 0x100; } + if (atkbd->keycode[code] != ATKBD_KEY_NULL) + input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: break; @@ -376,18 +421,20 @@ out: static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { - int timeout = 20000; /* 200 msec */ - atkbd->ack = 0; + int timeout = 200000; /* 200 msec */ #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif + + set_bit(ATKBD_FLAG_ACK, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (serio_write(atkbd->serio, byte)) return -1; + while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1); + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); - while (!atkbd->ack && timeout--) udelay(10); - - return -(atkbd->ack <= 0); + return -atkbd->nak; } /* @@ -405,7 +452,7 @@ static int atkbd_command(struct atkbd *a atkbd->cmdcnt = receive; if (command == ATKBD_CMD_RESET_BAT) - timeout = 2000000; /* 2 sec */ + timeout = 4000000; /* 4 sec */ if (receive && param) for (i = 0; i < receive; i++) @@ -413,38 +460,40 @@ static int atkbd_command(struct atkbd *a if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) - return (atkbd->cmdcnt = 0) - 1; + return -1; for (i = 0; i < send; i++) if (atkbd_sendbyte(atkbd, param[i])) - return (atkbd->cmdcnt = 0) - 1; - - while (atkbd->cmdcnt && timeout--) { + return -1; - if (atkbd->cmdcnt == 1 && - command == ATKBD_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; + while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) { - if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && - atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) { - atkbd->cmdcnt = 0; - break; + if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) { + + if (command == ATKBD_CMD_RESET_BAT && timeout > 100000) + timeout = 100000; + + if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + atkbd->cmdcnt = 0; + break; + } } udelay(1); } + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (param) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) - atkbd->cmdcnt = 0; + return 0; - if (atkbd->cmdcnt) { - atkbd->cmdcnt = 0; + if (atkbd->cmdcnt) return -1; - } return 0; } @@ -672,6 +721,7 @@ static void atkbd_cleanup(struct serio * static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); @@ -684,7 +734,7 @@ static void atkbd_disconnect(struct seri * to the input module. */ -static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +static void atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; int i; @@ -709,17 +759,22 @@ static void atkbd_connect(struct serio * return; } + if (!atkbd->write) + atkbd_softrepeat = 1; + if (atkbd_softrepeat) + atkbd_softraw = 1; + if (atkbd->write) { - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (!atkbd_softrepeat) { atkbd->dev.rep[REP_DELAY] = 250; atkbd->dev.rep[REP_PERIOD] = 33; - } + } else atkbd_softraw = 1; - atkbd->ack = 1; atkbd->serio = serio; init_input_dev(&atkbd->dev); @@ -732,7 +787,7 @@ static void atkbd_connect(struct serio * serio->private = atkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(atkbd); return; } @@ -754,8 +809,6 @@ static void atkbd_connect(struct serio * atkbd->id = 0xab00; } - atkbd->enabled = 1; - if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); sprintf(atkbd->name, "AT Set 2 Extra keyboard"); @@ -797,6 +850,8 @@ static void atkbd_connect(struct serio * input_register_device(&atkbd->dev); + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); } @@ -808,10 +863,10 @@ static void atkbd_connect(struct serio * static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; - struct serio_dev *dev = serio->dev; + struct serio_driver *drv = serio->drv; unsigned char param[1]; - if (!dev) { + if (!drv) { printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -832,26 +887,32 @@ static int atkbd_reconnect(struct serio return -1; } + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + return 0; } -static struct serio_dev atkbd_dev = { - .interrupt = atkbd_interrupt, - .connect = atkbd_connect, - .reconnect = atkbd_reconnect, - .disconnect = atkbd_disconnect, - .cleanup = atkbd_cleanup, +static struct serio_driver atkbd_drv = { + .driver = { + .name = "atkbd", + }, + .description = DRIVER_DESC, + .interrupt = atkbd_interrupt, + .connect = atkbd_connect, + .reconnect = atkbd_reconnect, + .disconnect = atkbd_disconnect, + .cleanup = atkbd_cleanup, }; int __init atkbd_init(void) { - serio_register_device(&atkbd_dev); + serio_register_driver(&atkbd_drv); return 0; } void __exit atkbd_exit(void) { - serio_unregister_device(&atkbd_dev); + serio_unregister_driver(&atkbd_drv); } module_init(atkbd_init); --- linux-2.6.8-rc1/drivers/input/keyboard/lkkbd.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/input/keyboard/lkkbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -76,8 +76,10 @@ #include #include +#define DRIVER_DESC "LK keyboard driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); /* @@ -622,7 +624,7 @@ lkkbd_reinit (void *data) * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ static void -lkkbd_connect (struct serio *serio, struct serio_dev *dev) +lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; int i; @@ -665,7 +667,7 @@ lkkbd_connect (struct serio *serio, stru serio->private = lk; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (lk); return; } @@ -703,10 +705,14 @@ lkkbd_disconnect (struct serio *serio) kfree (lk); } -static struct serio_dev lkkbd_dev = { - .connect = lkkbd_connect, - .disconnect = lkkbd_disconnect, - .interrupt = lkkbd_interrupt, +static struct serio_driver lkkbd_drv = { + .driver = { + .name = "lkkbd", + }, + .description = DRIVER_DESC, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* @@ -715,14 +721,14 @@ static struct serio_dev lkkbd_dev = { int __init lkkbd_init (void) { - serio_register_device (&lkkbd_dev); + serio_register_driver(&lkkbd_drv); return 0; } void __exit lkkbd_exit (void) { - serio_unregister_device (&lkkbd_dev); + serio_unregister_driver(&lkkbd_drv); } module_init (lkkbd_init); --- linux-2.6.8-rc1/drivers/input/keyboard/newtonkbd.c 2004-02-03 20:42:35.000000000 -0800 +++ 25/drivers/input/keyboard/newtonkbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -32,8 +32,10 @@ #include #include +#define DRIVER_DESC "Newton keyboard driver" + MODULE_AUTHOR("Justin Cormack "); -MODULE_DESCRIPTION("Newton keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define NKBD_KEY 0x7f @@ -82,7 +84,7 @@ irqreturn_t nkbd_interrupt(struct serio } -void nkbd_connect(struct serio *serio, struct serio_dev *dev) +void nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; int i; @@ -106,7 +108,7 @@ void nkbd_connect(struct serio *serio, s nkbd->dev.private = nkbd; serio->private = nkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(nkbd); return; } @@ -138,21 +140,25 @@ void nkbd_disconnect(struct serio *serio kfree(nkbd); } -struct serio_dev nkbd_dev = { - .interrupt = nkbd_interrupt, - .connect = nkbd_connect, - .disconnect = nkbd_disconnect +struct serio_driver nkbd_drv = { + .driver = { + .name = "newtonkbd", + }, + .description = DRIVER_DESC, + .interrupt = nkbd_interrupt, + .connect = nkbd_connect, + .disconnect = nkbd_disconnect, }; int __init nkbd_init(void) { - serio_register_device(&nkbd_dev); + serio_register_driver(&nkbd_drv); return 0; } void __exit nkbd_exit(void) { - serio_unregister_device(&nkbd_dev); + serio_unregister_driver(&nkbd_drv); } module_init(nkbd_init); --- linux-2.6.8-rc1/drivers/input/keyboard/sunkbd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/keyboard/sunkbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Sun keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { @@ -221,7 +223,7 @@ static void sunkbd_reinit(void *data) * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. */ -static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +static void sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; int i; @@ -257,7 +259,7 @@ static void sunkbd_connect(struct serio serio->private = sunkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sunkbd); return; } @@ -301,10 +303,14 @@ static void sunkbd_disconnect(struct ser kfree(sunkbd); } -static struct serio_dev sunkbd_dev = { - .interrupt = sunkbd_interrupt, - .connect = sunkbd_connect, - .disconnect = sunkbd_disconnect +static struct serio_driver sunkbd_drv = { + .driver = { + .name = "sunkbd", + }, + .description = DRIVER_DESC, + .interrupt = sunkbd_interrupt, + .connect = sunkbd_connect, + .disconnect = sunkbd_disconnect, }; /* @@ -313,13 +319,13 @@ static struct serio_dev sunkbd_dev = { int __init sunkbd_init(void) { - serio_register_device(&sunkbd_dev); + serio_register_driver(&sunkbd_drv); return 0; } void __exit sunkbd_exit(void) { - serio_unregister_device(&sunkbd_dev); + serio_unregister_driver(&sunkbd_drv); } module_init(sunkbd_init); --- linux-2.6.8-rc1/drivers/input/keyboard/xtkbd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/keyboard/xtkbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -34,8 +34,10 @@ #include #include +#define DRIVER_DESC "XT keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define XTKBD_EMUL0 0xe0 @@ -86,7 +88,7 @@ irqreturn_t xtkbd_interrupt(struct serio return IRQ_HANDLED; } -void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +void xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; int i; @@ -111,7 +113,7 @@ void xtkbd_connect(struct serio *serio, serio->private = xtkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(xtkbd); return; } @@ -143,21 +145,25 @@ void xtkbd_disconnect(struct serio *seri kfree(xtkbd); } -struct serio_dev xtkbd_dev = { - .interrupt = xtkbd_interrupt, - .connect = xtkbd_connect, - .disconnect = xtkbd_disconnect +struct serio_driver xtkbd_drv = { + .driver = { + .name = "xtkbd", + }, + .description = DRIVER_DESC, + .interrupt = xtkbd_interrupt, + .connect = xtkbd_connect, + .disconnect = xtkbd_disconnect, }; int __init xtkbd_init(void) { - serio_register_device(&xtkbd_dev); + serio_register_driver(&xtkbd_drv); return 0; } void __exit xtkbd_exit(void) { - serio_unregister_device(&xtkbd_dev); + serio_unregister_driver(&xtkbd_drv); } module_init(xtkbd_init); --- linux-2.6.8-rc1/drivers/input/misc/uinput.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/misc/uinput.c 2004-07-13 17:09:22.000000000 -0700 @@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct f { struct uinput_device *udev = file->private_data; + if (!test_bit(UIST_CREATED, &(udev->state))) + return 0; + poll_wait(file, &udev->waitq, wait); if (udev->head != udev->tail) --- linux-2.6.8-rc1/drivers/input/mousedev.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/mousedev.c 2004-07-13 17:09:22.071917432 -0700 @@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_ module_param(yres, uint, 0); MODULE_PARM_DESC(yres, "Vertical screen resolution"); +static unsigned tap_time = 200; +module_param(tap_time, uint, 0); +MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); + struct mousedev_motion { int dx, dy, dz; + unsigned long buttons; }; struct mousedev { @@ -62,21 +67,31 @@ struct mousedev { struct input_handle handle; struct mousedev_motion packet; - unsigned long buttons; unsigned int pkt_count; int old_x[4], old_y[4]; - unsigned int touch; + unsigned long touch; }; +enum mousedev_emul { + MOUSEDEV_EMUL_PS2, + MOUSEDEV_EMUL_IMPS, + MOUSEDEV_EMUL_EXPS +} __attribute__ ((packed)); + +#define PACKET_QUEUE_LEN 16 struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; - int dx, dy, dz; - unsigned long buttons; + + struct mousedev_motion packets[PACKET_QUEUE_LEN]; + unsigned int head, tail; + spinlock_t packet_lock; + signed char ps2[6]; unsigned char ready, buffer, bufsiz; - unsigned char mode, imexseq, impsseq; + unsigned char imexseq, impsseq; + enum mousedev_emul mode; }; #define MOUSEDEV_SEQ_LEN 6 @@ -165,30 +180,70 @@ static void mousedev_key_event(struct mo } if (value) { - set_bit(index, &mousedev->buttons); - set_bit(index, &mousedev_mix.buttons); + set_bit(index, &mousedev->packet.buttons); + set_bit(index, &mousedev_mix.packet.buttons); } else { - clear_bit(index, &mousedev->buttons); - clear_bit(index, &mousedev_mix.buttons); + clear_bit(index, &mousedev->packet.buttons); + clear_bit(index, &mousedev_mix.packet.buttons); } } static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) { struct mousedev_list *list; + struct mousedev_motion *p; + unsigned long flags; list_for_each_entry(list, &mousedev->list, node) { - list->dx += packet->dx; - list->dy += packet->dy; - list->dz += packet->dz; - list->buttons = mousedev->buttons; + spin_lock_irqsave(&list->packet_lock, flags); + + p = &list->packets[list->head]; + if (list->ready && p->buttons != packet->buttons) { + unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; + if (new_head != list->tail) { + p = &list->packets[list->head = new_head]; + memset(p, 0, sizeof(struct mousedev_motion)); + } + } + + p->dx += packet->dx; + p->dy += packet->dy; + p->dz += packet->dz; + p->buttons = mousedev->packet.buttons; + list->ready = 1; + + spin_unlock_irqrestore(&list->packet_lock, flags); kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&mousedev->wait); } +static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) +{ + if (!value) { + if (mousedev->touch && + !time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + /* + * Toggle left button to emulate tap. + * We rely on the fact that mousedev_mix always has 0 + * motion packet so we won't mess current position. + */ + set_bit(0, &mousedev->packet.buttons); + set_bit(0, &mousedev_mix.packet.buttons); + mousedev_notify_readers(mousedev, &mousedev_mix.packet); + mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); + clear_bit(0, &mousedev->packet.buttons); + clear_bit(0, &mousedev_mix.packet.buttons); + } + mousedev->touch = mousedev->pkt_count = 0; + } + else + if (!mousedev->touch) + mousedev->touch = jiffies; +} + static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct mousedev *mousedev = handle->private; @@ -212,12 +267,8 @@ static void mousedev_event(struct input_ case EV_KEY: if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - /* Handle touchpad data */ - mousedev->touch = value; - if (!mousedev->touch) - mousedev->pkt_count = 0; - } + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_touch(mousedev, value); else mousedev_key_event(mousedev, code, value); } @@ -237,7 +288,7 @@ static void mousedev_event(struct input_ mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet); - memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); + mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; } break; } @@ -322,6 +373,7 @@ static int mousedev_open(struct inode * return -ENOMEM; memset(list, 0, sizeof(struct mousedev_list)); + spin_lock_init(&list->packet_lock); list->mousedev = mousedev_table[i]; list_add_tail(&list->node, &mousedev_table[i]->list); file->private_data = list; @@ -341,32 +393,56 @@ static int mousedev_open(struct inode * return 0; } -static void mousedev_packet(struct mousedev_list *list, unsigned char off) +static inline int mousedev_limit_delta(int delta, int limit) { - list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); - list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); - list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); - list->dx -= list->ps2[off + 1]; - list->dy -= list->ps2[off + 2]; - list->bufsiz = off + 3; - - if (list->mode == 2) { - list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); - list->bufsiz++; - } else { - list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); + return delta > limit ? limit : (delta < -limit ? -limit : delta); +} + +static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) +{ + struct mousedev_motion *p; + unsigned long flags; + + spin_lock_irqsave(&list->packet_lock, flags); + p = &list->packets[list->tail]; + + ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); + ps2_data[1] = mousedev_limit_delta(p->dx, 127); + ps2_data[2] = mousedev_limit_delta(p->dy, 127); + p->dx -= ps2_data[1]; + p->dy -= ps2_data[2]; + + switch (list->mode) { + case MOUSEDEV_EMUL_EXPS: + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_IMPS: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_PS2: + default: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + p->dz = 0; + list->bufsiz = 3; + break; } - if (list->mode == 1) { - list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->bufsiz++; + if (!p->dx && !p->dy && !p->dz) { + if (list->tail != list->head) + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; + if (list->tail == list->head) + list->ready = 0; } - if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; - list->buffer = list->bufsiz; + spin_unlock_irqrestore(&list->packet_lock, flags); } @@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct fil if (c == mousedev_imex_seq[list->imexseq]) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) { list->imexseq = 0; - list->mode = 2; + list->mode = MOUSEDEV_EMUL_EXPS; } } else list->imexseq = 0; if (c == mousedev_imps_seq[list->impsseq]) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) { list->impsseq = 0; - list->mode = 1; + list->mode = MOUSEDEV_EMUL_IMPS; } } else list->impsseq = 0; list->ps2[0] = 0xfa; - list->bufsiz = 1; switch (c) { case 0xeb: /* Poll */ - mousedev_packet(list, 1); + mousedev_packet(list, &list->ps2[1]); + list->bufsiz++; /* account for leading ACK */ break; case 0xf2: /* Get ID */ switch (list->mode) { - case 0: list->ps2[1] = 0; break; - case 1: list->ps2[1] = 3; break; - case 2: list->ps2[1] = 4; break; + case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; + case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; + case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; } list->bufsiz = 2; break; @@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct fil break; case 0xff: /* Reset */ - list->impsseq = 0; - list->imexseq = 0; - list->mode = 0; - list->ps2[1] = 0xaa; - list->ps2[2] = 0x00; + list->impsseq = list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_PS2; + list->ps2[1] = 0xaa; list->ps2[2] = 0x00; list->bufsiz = 3; break; + + default: + list->bufsiz = 1; + break; } list->buffer = list->bufsiz; @@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file if (retval) return retval; - if (!list->buffer && list->ready) - mousedev_packet(list, 0); + if (!list->buffer && list->ready) { + mousedev_packet(list, list->ps2); + list->buffer = list->bufsiz; + } if (count > list->buffer) count = list->buffer; --- linux-2.6.8-rc1/drivers/input/mouse/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/mouse/Kconfig 2004-07-13 17:09:22.000000000 -0700 @@ -30,8 +30,6 @@ config MOUSE_PS2 and a new verion of GPM at: http://www.geocities.com/dt_or/gpm/gpm.html to take advantage of the advanced features of the touchpad. - If you do not want install specialized drivers but want tapping - working please use option psmouse.proto=imps. If unsure, say Y. --- linux-2.6.8-rc1/drivers/input/mouse/logips2pp.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/mouse/logips2pp.c 2004-07-13 17:09:22.064918496 -0700 @@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, protocol = PSMOUSE_PS2TPP; } - } else if (get_model_info(model) != NULL) { + } else if (model_info != NULL) { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ --- linux-2.6.8-rc1/drivers/input/mouse/psmouse-base.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/mouse/psmouse-base.c 2004-07-13 17:09:22.066918192 -0700 @@ -22,8 +22,10 @@ #include "synaptics.h" #include "logips2pp.h" +#define DRIVER_DESC "PS/2 mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *psmouse_proto; @@ -142,34 +144,45 @@ static irqreturn_t psmouse_interrupt(str printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_PARITY ? " bad parity" : ""); - if (psmouse->acking) { - psmouse->ack = -1; - psmouse->acking = 0; - } - psmouse->pktcnt = 0; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); goto out; } - if (psmouse->acking) { + if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) switch (data) { case PSMOUSE_RET_ACK: - psmouse->ack = 1; + psmouse->nak = 0; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + goto out; break; case PSMOUSE_RET_NAK: - psmouse->ack = -1; - break; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + goto out; default: - psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ - if (psmouse->cmdcnt) - psmouse->cmdbuf[--psmouse->cmdcnt] = data; - break; + psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */ + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) + goto out; + } - psmouse->acking = 0; - goto out; - } - if (psmouse->cmdcnt) { - psmouse->cmdbuf[--psmouse->cmdcnt] = data; + if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + + psmouse->cmdcnt--; + psmouse->cmdbuf[psmouse->cmdcnt] = data; + + if (psmouse->cmdcnt == 1) { + if (data != 0xab && data != 0xac) + clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + } + + if (!psmouse->cmdcnt) + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + goto out; } @@ -242,18 +255,15 @@ out: static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { - int timeout = 10000; /* 100 msec */ - psmouse->ack = 0; - psmouse->acking = 1; + int timeout = 200000; /* 200 msec */ - if (serio_write(psmouse->serio, byte)) { - psmouse->acking = 0; + set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + if (serio_write(psmouse->serio, byte)) return -1; - } - - while (!psmouse->ack && timeout--) udelay(10); + while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1); + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - return -(psmouse->ack <= 0); + return -psmouse->nak; } /* @@ -271,46 +281,62 @@ int psmouse_command(struct psmouse *psmo psmouse->cmdcnt = receive; if (command == PSMOUSE_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + timeout = 4000000; /* 4 sec */ - /* initialize cmdbuf with preset values from param */ - if (receive) - for (i = 0; i < receive; i++) - psmouse->cmdbuf[(receive - 1) - i] = param[i]; + if (receive && param) + for (i = 0; i < receive; i++) + psmouse->cmdbuf[(receive - 1) - i] = param[i]; + + if (receive) { + set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + set_bit(PSMOUSE_FLAG_ID, &psmouse->flags); + } if (command & 0xff) - if (psmouse_sendbyte(psmouse, command & 0xff)) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse_sendbyte(psmouse, command & 0xff)) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + return -1; + } for (i = 0; i < send; i++) - if (psmouse_sendbyte(psmouse, param[i])) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse_sendbyte(psmouse, param[i])) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + return -1; + } - while (psmouse->cmdcnt && timeout--) { + while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && - timeout > 100000) /* do not run in a endless loop */ - timeout = 100000; /* 1 sec */ - - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && - psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { - psmouse->cmdcnt = 0; - break; + if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) { + + if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) + timeout = 100000; + + if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + psmouse->cmdcnt = 0; + break; + } } udelay(1); } - for (i = 0; i < receive; i++) - param[i] = psmouse->cmdbuf[(receive - 1) - i]; + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + + if (param) + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; + + if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1) + return 0; if (psmouse->cmdcnt) - return (psmouse->cmdcnt = 0) - 1; + return -1; return 0; } - /* * psmouse_sliced_command() sends an extended PS/2 command to the mouse * using sliced syntax, understood by advanced devices, such as Logitech @@ -394,6 +420,8 @@ static int im_explorer_detect(struct psm { unsigned char param[2]; + intellimouse_detect(psmouse); + param[0] = 200; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); param[0] = 200; @@ -626,16 +654,15 @@ static void psmouse_cleanup(struct serio static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse = serio->private; + struct psmouse *psmouse, *parent; + psmouse = serio->private; psmouse->state = PSMOUSE_CMD_MODE; - if (psmouse->ptport) { - if (psmouse->ptport->deactivate) - psmouse->ptport->deactivate(psmouse); - __serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */ - kfree(psmouse->ptport); - psmouse->ptport = NULL; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + if (parent->pt_deactivate) + parent->pt_deactivate(parent); } if (psmouse->disconnect) @@ -652,16 +679,19 @@ static void psmouse_disconnect(struct se * psmouse_connect() is a callback from the serio module when * an unhandled serio port is found. */ -static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +static void psmouse_connect(struct serio *serio, struct serio_driver *drv) { - struct psmouse *psmouse; + struct psmouse *psmouse, *parent = NULL; if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) + parent = serio->parent->private; + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) - return; + goto out; memset(psmouse, 0, sizeof(struct psmouse)); @@ -674,17 +704,17 @@ static void psmouse_connect(struct serio psmouse->dev.private = psmouse; serio->private = psmouse; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(psmouse); serio->private = NULL; - return; + goto out; } if (psmouse_probe(psmouse) < 0) { serio_close(serio); kfree(psmouse); serio->private = NULL; - return; + goto out; } psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); @@ -713,29 +743,50 @@ static void psmouse_connect(struct serio psmouse_initialize(psmouse); - if (psmouse->ptport) { - printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys); - __serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */ - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } + if (parent && parent->pt_activate) + parent->pt_activate(parent); - psmouse_activate(psmouse); + /* + * OK, the device is ready, we just need to activate it (turn the + * stream mode on). But if mouse has a pass-through port we don't + * want to do it yet to not disturb child detection. + * The child will activate this port when it's ready. + */ + + if (serio->child) { + /* + * Nothing to be done here, serio core will detect that + * the driver set serio->child and will register it for us. + */ + printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys); + } else + psmouse_activate(psmouse); + +out: + /* If this is a pass-through port the parent awaits to be activated */ + if (parent) + psmouse_activate(parent); } static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; - struct serio_dev *dev = serio->dev; + struct psmouse *parent = NULL; + struct serio_driver *drv = serio->drv; - if (!dev || !psmouse) { + if (!drv || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } psmouse->state = PSMOUSE_CMD_MODE; - psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0; + + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + + psmouse->pktcnt = psmouse->out_of_sync = 0; + if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) return -1; @@ -748,26 +799,33 @@ static int psmouse_reconnect(struct seri */ psmouse_initialize(psmouse); - if (psmouse->ptport) { - if (psmouse_reconnect(&psmouse->ptport->serio)) { - __serio_unregister_port(&psmouse->ptport->serio); - __serio_register_port(&psmouse->ptport->serio); - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } - } + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) + parent = serio->parent->private; + + if (parent && parent->pt_activate) + parent->pt_activate(parent); + + if (!serio->child) + psmouse_activate(psmouse); + + /* If this is a pass-through port the parent waits to be activated */ + if (parent) + psmouse_activate(parent); - psmouse_activate(psmouse); return 0; } -static struct serio_dev psmouse_dev = { - .interrupt = psmouse_interrupt, - .connect = psmouse_connect, - .reconnect = psmouse_reconnect, - .disconnect = psmouse_disconnect, - .cleanup = psmouse_cleanup, +static struct serio_driver psmouse_drv = { + .driver = { + .name = "psmouse", + }, + .description = DRIVER_DESC, + .interrupt = psmouse_interrupt, + .connect = psmouse_connect, + .reconnect = psmouse_reconnect, + .disconnect = psmouse_disconnect, + .cleanup = psmouse_cleanup, }; static inline void psmouse_parse_proto(void) @@ -787,13 +845,13 @@ static inline void psmouse_parse_proto(v int __init psmouse_init(void) { psmouse_parse_proto(); - serio_register_device(&psmouse_dev); + serio_register_driver(&psmouse_drv); return 0; } void __exit psmouse_exit(void) { - serio_unregister_device(&psmouse_dev); + serio_unregister_driver(&psmouse_drv); } module_init(psmouse_init); --- linux-2.6.8-rc1/drivers/input/mouse/psmouse.h 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/mouse/psmouse.h 2004-07-13 17:09:22.066918192 -0700 @@ -22,6 +22,11 @@ #define PSMOUSE_ACTIVATED 1 #define PSMOUSE_IGNORE 2 +#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ +#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */ +#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */ + /* psmouse protocol handler return codes */ typedef enum { PSMOUSE_BAD_DATA, @@ -29,20 +34,10 @@ typedef enum { PSMOUSE_FULL_PACKET } psmouse_ret_t; -struct psmouse; - -struct psmouse_ptport { - struct serio serio; - - void (*activate)(struct psmouse *parent); - void (*deactivate)(struct psmouse *parent); -}; - struct psmouse { void *private; struct input_dev dev; struct serio *serio; - struct psmouse_ptport *ptport; char *vendor; char *name; unsigned char cmdbuf[8]; @@ -54,15 +49,18 @@ struct psmouse { unsigned long last; unsigned long out_of_sync; unsigned char state; - char acking; - volatile char ack; + unsigned char nak; char error; char devname[64]; char phys[32]; + unsigned long flags; - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + + void (*pt_activate)(struct psmouse *psmouse); + void (*pt_deactivate)(struct psmouse *psmouse); }; #define PSMOUSE_PS2 1 --- linux-2.6.8-rc1/drivers/input/mouse/sermouse.c 2003-06-14 12:18:25.000000000 -0700 +++ 25/drivers/input/mouse/sermouse.c 2004-07-13 17:09:22.000000000 -0700 @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Serial mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", @@ -237,7 +239,7 @@ static void sermouse_disconnect(struct s * an unhandled serio port is found. */ -static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +static void sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; unsigned char c; @@ -279,7 +281,7 @@ static void sermouse_connect(struct seri sermouse->dev.id.product = c; sermouse->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sermouse); return; } @@ -289,21 +291,25 @@ static void sermouse_connect(struct seri printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); } -static struct serio_dev sermouse_dev = { - .interrupt = sermouse_interrupt, - .connect = sermouse_connect, - .disconnect = sermouse_disconnect +static struct serio_driver sermouse_drv = { + .driver = { + .name = "sermouse", + }, + .description = DRIVER_DESC, + .interrupt = sermouse_interrupt, + .connect = sermouse_connect, + .disconnect = sermouse_disconnect, }; int __init sermouse_init(void) { - serio_register_device(&sermouse_dev); + serio_register_driver(&sermouse_drv); return 0; } void __exit sermouse_exit(void) { - serio_unregister_device(&sermouse_dev); + serio_unregister_driver(&sermouse_drv); } module_init(sermouse_init); --- linux-2.6.8-rc1/drivers/input/mouse/synaptics.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/mouse/synaptics.c 2004-07-13 17:09:22.068917888 -0700 @@ -212,9 +212,9 @@ static int synaptics_set_mode(struct psm /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *port, unsigned char c) +static int synaptics_pt_write(struct serio *serio, unsigned char c) { - struct psmouse *parent = port->driver; + struct psmouse *parent = serio->parent->private; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ if (psmouse_sliced_command(parent, c)) @@ -248,7 +248,7 @@ static void synaptics_pass_pt_packet(str static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->ptport->serio.private; + struct psmouse *child = psmouse->serio->child->private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { @@ -259,23 +259,25 @@ static void synaptics_pt_activate(struct static void synaptics_pt_create(struct psmouse *psmouse) { - struct psmouse_ptport *port; + struct serio *serio; - psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); - if (!port) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } - memset(port, 0, sizeof(struct psmouse_ptport)); + memset(serio, 0, sizeof(struct serio)); - port->serio.type = SERIO_PS_PSTHRU; - port->serio.name = "Synaptics pass-through"; - port->serio.phys = "synaptics-pt/serio0"; - port->serio.write = synaptics_pt_write; - port->serio.driver = psmouse; + serio->type = SERIO_PS_PSTHRU; + strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); + strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); + serio->write = synaptics_pt_write; + serio->parent = psmouse->serio; - port->activate = synaptics_pt_activate; + psmouse->pt_activate = synaptics_pt_activate; + + psmouse->serio->child = serio; } /***************************************************************************** @@ -470,8 +472,8 @@ static psmouse_ret_t synaptics_process_b if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); + if (psmouse->serio->child && psmouse->serio->child->drv && synaptics_is_pt_packet(psmouse->packet)) + synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); else synaptics_process_packet(psmouse); --- linux-2.6.8-rc1/drivers/input/mouse/vsxxxaa.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/input/mouse/vsxxxaa.c 2004-07-13 17:09:22.000000000 -0700 @@ -82,8 +82,10 @@ #include #include +#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); #undef VSXXXAA_DEBUG @@ -482,7 +484,7 @@ vsxxxaa_disconnect (struct serio *serio) } static void -vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; @@ -524,7 +526,7 @@ vsxxxaa_connect (struct serio *serio, st mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (mouse); return; } @@ -540,23 +542,27 @@ vsxxxaa_connect (struct serio *serio, st printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } -static struct serio_dev vsxxxaa_dev = { - .connect = vsxxxaa_connect, - .interrupt = vsxxxaa_interrupt, - .disconnect = vsxxxaa_disconnect, +static struct serio_driver vsxxxaa_drv = { + .driver = { + .name = "vsxxxaa", + }, + .description = DRIVER_DESC, + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init vsxxxaa_init (void) { - serio_register_device (&vsxxxaa_dev); + serio_register_driver(&vsxxxaa_drv); return 0; } void __exit vsxxxaa_exit (void) { - serio_unregister_device (&vsxxxaa_dev); + serio_unregister_driver(&vsxxxaa_drv); } module_init (vsxxxaa_init); --- linux-2.6.8-rc1/drivers/input/serio/ambakmi.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/serio/ambakmi.c 2004-07-13 17:09:22.000000000 -0700 @@ -29,7 +29,7 @@ #define KMI_BASE (kmi->base) struct amba_kmi_port { - struct serio io; + struct serio *io; struct clk *clk; unsigned char *base; unsigned int irq; @@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); status = readb(KMIIR); handled = IRQ_HANDLED; } @@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, static int amba_kmi_write(struct serio *io, unsigned char val) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int timeleft = 10000; /* timeout in 100ms */ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) @@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio * static int amba_kmi_open(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int divisor; int ret; @@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *i static void amba_kmi_close(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; writeb(0, KMICR); @@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; + struct serio *io; int ret; ret = amba_request_regions(dev, NULL); @@ -124,21 +125,25 @@ static int amba_kmi_probe(struct amba_de return ret; kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); - if (!kmi) { + io = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!kmi || !io) { ret = -ENOMEM; goto out; } memset(kmi, 0, sizeof(struct amba_kmi_port)); + memset(io, 0, sizeof(struct serio)); - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.driver = kmi; + io->type = SERIO_8042; + io->write = amba_kmi_write; + io->open = amba_kmi_open; + io->close = amba_kmi_close; + strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); + io->port_data = kmi; + io->dev.parent = &dev->dev; + kmi->io = io; kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; @@ -154,13 +159,14 @@ static int amba_kmi_probe(struct amba_de kmi->irq = dev->irq[0]; amba_set_drvdata(dev, kmi); - serio_register_port(&kmi->io); + serio_register_port(kmi->io); return 0; unmap: iounmap(kmi->base); out: kfree(kmi); + kfree(io); amba_release_regions(dev); return ret; } @@ -171,7 +177,7 @@ static int amba_kmi_remove(struct amba_d amba_set_drvdata(dev, NULL); - serio_unregister_port(&kmi->io); + serio_unregister_port(kmi->io); clk_put(kmi->clk); iounmap(kmi->base); kfree(kmi); @@ -184,7 +190,7 @@ static int amba_kmi_resume(struct amba_d struct amba_kmi_port *kmi = amba_get_drvdata(dev); /* kick the serio layer to rescan this port */ - serio_rescan(&kmi->io); + serio_reconnect(kmi->io); return 0; } @@ -214,7 +220,7 @@ static int __init amba_kmi_init(void) static void __exit amba_kmi_exit(void) { - return amba_driver_unregister(&ambakmi_driver); + amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); --- linux-2.6.8-rc1/drivers/input/serio/ct82c710.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/ct82c710.c 2004-07-13 17:09:22.000000000 -0700 @@ -43,9 +43,6 @@ MODULE_AUTHOR("Vojtech Pavlik type = SERIO_8042; + serio->open = ct82c710_open; + serio->close = ct82c710_close; + serio->write = ct82c710_write; + strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "isa%04x/serio0", ct82c710_data); + } + + return serio; +} + int __init ct82c710_init(void) { if (ct82c710_probe()) @@ -191,9 +196,12 @@ int __init ct82c710_init(void) if (request_region(ct82c710_data, 2, "ct82c710")) return -EBUSY; - sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + if (!(ct82c710_port = ct82c710_allocate_port())) { + release_region(ct82c710_data, 2); + return -ENOMEM; + } - serio_register_port(&ct82c710_port); + serio_register_port(ct82c710_port); printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", ct82c710_data, CT82C710_IRQ); @@ -203,7 +211,7 @@ int __init ct82c710_init(void) void __exit ct82c710_exit(void) { - serio_unregister_port(&ct82c710_port); + serio_unregister_port(ct82c710_port); release_region(ct82c710_data, 2); } --- linux-2.6.8-rc1/drivers/input/serio/gscps2.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/gscps2.c 2004-07-13 17:09:22.000000000 -0700 @@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int struct gscps2port { struct list_head node; struct parisc_device *padev; - struct serio port; + struct serio *port; spinlock_t lock; char *addr; u8 act, append; /* position in buffer[] */ @@ -100,7 +100,6 @@ struct gscps2port { u8 str; } buffer[BUFFER_SIZE+1]; int id; - char name[32]; }; /* @@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - serio_interrupt(&ps2port->port, data, rxflags, regs); + serio_interrupt(ps2port->port, data, rxflags, regs); } /* while() */ @@ -288,7 +287,7 @@ static irqreturn_t gscps2_interrupt(int static int gscps2_write(struct serio *port, unsigned char data) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; if (!gscps2_writeb_output(ps2port, data)) { printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); @@ -304,7 +303,7 @@ static int gscps2_write(struct serio *po static int gscps2_open(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_reset(ps2port); @@ -319,7 +318,7 @@ static int gscps2_open(struct serio *por static void gscps2_close(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_enable(ps2port, DISABLE); } @@ -343,7 +342,8 @@ static struct serio gscps2_serio_port = static int __init gscps2_probe(struct parisc_device *dev) { - struct gscps2port *ps2port; + struct gscps2port *ps2port; + struct serio *serio; unsigned long hpa = dev->hpa; int ret; @@ -355,34 +355,45 @@ static int __init gscps2_probe(struct pa hpa += GSC_DINO_OFFSET; ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); - if (!ps2port) - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2port || !serio) { + ret = -ENOMEM; + goto fail_nomem; + } dev_set_drvdata(&dev->dev, ps2port); memset(ps2port, 0, sizeof(struct gscps2port)); + memset(serio, 0, sizeof(struct serio)); + ps2port->port = serio; ps2port->padev = dev; ps2port->addr = ioremap(hpa, GSC_STATUS + 4); spin_lock_init(&ps2port->lock); gscps2_reset(ps2port); - ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; - snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", - gscps2_serio_port.name, - (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); - - memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); - ps2port->port.driver = ps2port; - ps2port->port.name = ps2port->name; - ps2port->port.phys = dev->dev.bus_id; + ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; + + snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->idbus = BUS_GSC; + serio->idvendor = PCI_VENDOR_ID_HP; + serio->idproduct = 0x0001; + serio->idversion = 0x0010; + serio->type = SERIO_8042; + serio->write = gscps2_write; + serio->open = gscps2_open; + serio->close = gscps2_close; + serio->port_data = ps2port; + serio->dev.parent = &dev->dev; list_add_tail(&ps2port->node, &ps2port_list); ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; - if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", hpa, ps2port->id); ret = -ENODEV; @@ -395,12 +406,12 @@ static int __init gscps2_probe(struct pa #endif printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", - ps2port->name, + ps2port->port->name, ps2port->addr, ps2port->padev->irq, - ps2port->port.phys); + ps2port->port->phys); - serio_register_port(&ps2port->port); + serio_register_port(ps2port->port); return 0; @@ -411,7 +422,10 @@ fail_miserably: list_del(&ps2port->node); iounmap(ps2port->addr); release_mem_region(dev->hpa, GSC_STATUS + 4); + +fail_nomem: kfree(ps2port); + kfree(serio); return ret; } @@ -424,7 +438,7 @@ static int __devexit gscps2_remove(struc { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); - serio_unregister_port(&ps2port->port); + serio_unregister_port(ps2port->port); free_irq(dev->irq, ps2port); gscps2_flush(ps2port); list_del(&ps2port->node); --- linux-2.6.8-rc1/drivers/input/serio/i8042.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/i8042.c 2004-07-13 17:09:22.077916520 -0700 @@ -1,7 +1,7 @@ /* * i8042 keyboard and mouse controller driver for Linux * - * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik */ /* @@ -52,6 +52,10 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +static unsigned int i8042_noloop; +module_param_named(noloop, i8042_noloop, bool, 0); +MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port"); + __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_unlock"); @@ -70,19 +74,35 @@ struct i8042_values { unsigned char irqen; unsigned char exists; signed char mux; - unsigned char *name; - unsigned char *phys; + char name[8]; +}; + +static struct i8042_values i8042_kbd_values = { + .disable = I8042_CTR_KBDDIS, + .irqen = I8042_CTR_KBDINT, + .mux = -1, + .name = "KBD", +}; + +static struct i8042_values i8042_aux_values = { + .disable = I8042_CTR_AUXDIS, + .irqen = I8042_CTR_AUXINT, + .mux = -1, + .name = "AUX", }; -static struct serio i8042_kbd_port; -static struct serio i8042_aux_port; +static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS]; + +static struct serio *i8042_kbd_port; +static struct serio *i8042_aux_port; +static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS]; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -struct timer_list i8042_timer; +static struct timer_list i8042_timer; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -95,6 +115,7 @@ static irqreturn_t i8042_interrupt(int i /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. + * Called always with i8042_lock held. */ static int i8042_wait_read(void) @@ -154,6 +175,9 @@ static int i8042_command(unsigned char * unsigned long flags; int retval = 0, i = 0; + if (i8042_noloop && command == I8042_CMD_AUX_LOOP) + return -1; + spin_lock_irqsave(&i8042_lock, flags); retval = i8042_wait_write(); @@ -214,7 +238,7 @@ static int i8042_kbd_write(struct serio static int i8042_aux_write(struct serio *port, unsigned char c) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; int retval; /* @@ -242,7 +266,7 @@ static int i8042_aux_write(struct serio static int i8042_activate_port(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; i8042_flush(); @@ -270,7 +294,7 @@ static int i8042_activate_port(struct se static int i8042_open(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (i8042_mux_open++) @@ -309,7 +333,7 @@ irq_fail: static void i8042_close(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (--i8042_mux_open) @@ -328,52 +352,6 @@ static void i8042_close(struct serio *po } /* - * Structures for registering the devices in the serio.c module. - */ - -static struct i8042_values i8042_kbd_values = { - .irqen = I8042_CTR_KBDINT, - .disable = I8042_CTR_KBDDIS, - .name = "KBD", - .mux = -1, -}; - -static struct serio i8042_kbd_port = -{ - .type = SERIO_8042_XL, - .write = i8042_kbd_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_kbd_values, - .name = "i8042 Kbd Port", - .phys = I8042_KBD_PHYS_DESC, -}; - -static struct i8042_values i8042_aux_values = { - .irqen = I8042_CTR_AUXINT, - .disable = I8042_CTR_AUXDIS, - .name = "AUX", - .mux = -1, -}; - -static struct serio i8042_aux_port = -{ - .type = SERIO_8042, - .write = i8042_aux_write, - .open = i8042_open, - .close = i8042_close, - .driver = &i8042_aux_values, - .name = "i8042 Aux Port", - .phys = I8042_AUX_PHYS_DESC, -}; - -static struct i8042_values i8042_mux_values[4]; -static struct serio i8042_mux_port[4]; -static char i8042_mux_names[4][32]; -static char i8042_mux_short[4][16]; -static char i8042_mux_phys[4][32]; - -/* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes * to the upper layers. @@ -419,7 +397,7 @@ static irqreturn_t i8042_interrupt(int i dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); + serio_interrupt(i8042_mux_port[(str >> 6) & 3], data, dfl, regs); goto irq_ret; } @@ -430,14 +408,14 @@ static irqreturn_t i8042_interrupt(int i dfl & SERIO_TIMEOUT ? ", timeout" : ""); if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(&i8042_aux_port, data, dfl, regs); + serio_interrupt(i8042_aux_port, data, dfl, regs); goto irq_ret; } if (!i8042_kbd_values.exists) goto irq_ret; - serio_interrupt(&i8042_kbd_port, data, dfl, regs); + serio_interrupt(i8042_kbd_port, data, dfl, regs); irq_ret: ret = 1; @@ -474,17 +452,8 @@ static int i8042_enable_mux_mode(struct if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9) return -1; param = 0xa4; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) { - -/* - * Do another loop test with the 0x5a value. Doing anything else upsets - * Profusion/ServerWorks OSB4 chipsets. - */ - - param = 0x5a; - i8042_command(¶m, I8042_CMD_AUX_LOOP); + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) return -1; - } if (mux_version) *mux_version = ~param; @@ -639,8 +608,10 @@ static int __init i8042_check_aux(struct * registers it, and reports to the user. */ -static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +static int __init i8042_port_register(struct serio *port) { + struct i8042_values *values = port->port_data; + values->exists = 1; i8042_ctr &= ~values->disable; @@ -677,6 +648,7 @@ static void i8042_timer_func(unsigned lo static int i8042_controller_init(void) { + unsigned long flags; /* * Test the i8042. We need to know if it thinks it's working correctly @@ -723,12 +695,14 @@ static int i8042_controller_init(void) * Handle keylock. */ + spin_lock_irqsave(&i8042_lock, flags); if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (i8042_unlock) i8042_ctr |= I8042_CTR_IGNKEYLOCK; else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } + spin_unlock_irqrestore(&i8042_lock, flags); /* * If the chip is configured into nontranslated mode by the BIOS, don't @@ -745,10 +719,8 @@ static int i8042_controller_init(void) * BIOSes. */ - if (i8042_direct) { + if (i8042_direct) i8042_ctr &= ~I8042_CTR_XLATE; - i8042_kbd_port.type = SERIO_8042; - } /* * Write CTR back. @@ -802,14 +774,14 @@ void i8042_controller_cleanup(void) */ if (i8042_kbd_values.exists) - serio_cleanup(&i8042_kbd_port); + serio_cleanup(i8042_kbd_port); if (i8042_aux_values.exists) - serio_cleanup(&i8042_aux_port); + serio_cleanup(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_cleanup(i8042_mux_port + i); + serio_cleanup(i8042_mux_port[i]); i8042_controller_reset(); } @@ -851,15 +823,15 @@ static int i8042_controller_resume(void) * Reconnect anything that was connected to the ports. */ - if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0) - serio_reconnect(&i8042_kbd_port); + if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0) + serio_reconnect(i8042_kbd_port); - if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0) - serio_reconnect(&i8042_aux_port); + if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0) + serio_reconnect(i8042_aux_port); - for (i = 0; i < 4; i++) - if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0) - serio_reconnect(i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) + if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0) + serio_reconnect(i8042_mux_port[i]); /* * Restart timer (for polling "stuck" data) */ @@ -929,18 +901,66 @@ static int i8042_pm_callback(struct pm_d return 0; } -static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) +static struct serio * __init i8042_allocate_kbd_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = i8042_direct ? SERIO_8042 : SERIO_8042_XL, + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write, + serio->open = i8042_open, + serio->close = i8042_close, + serio->port_data = &i8042_kbd_values, + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_aux_port(void) { - memcpy(port, &i8042_aux_port, sizeof(struct serio)); - memcpy(values, &i8042_aux_values, sizeof(struct i8042_values)); - sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index); - sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1); - sprintf(i8042_mux_short[index], "AUX%d", index); - port->name = i8042_mux_names[index]; - port->phys = i8042_mux_phys[index]; - port->driver = values; - values->name = i8042_mux_short[index]; - values->mux = index; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = &i8042_aux_values, + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_mux_port(int index) +{ + struct serio *serio; + struct i8042_values *values = &i8042_mux_values[index]; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + *values = i8042_aux_values; + snprintf(values->name, sizeof(values->name), "AUX%d", index); + values->mux = index; + + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = values; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + } + + return serio; } int __init i8042_init(void) @@ -961,20 +981,23 @@ int __init i8042_init(void) if (i8042_controller_init()) return -ENODEV; - if (i8042_dumbkbd) - i8042_kbd_port.write = NULL; - if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) - for (i = 0; i < 4; i++) { - i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i); - i8042_port_register(i8042_mux_values + i, i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + i8042_mux_port[i] = i8042_allocate_mux_port(i); + if (i8042_mux_port[i]) + i8042_port_register(i8042_mux_port[i]); } - else - i8042_port_register(&i8042_aux_values, &i8042_aux_port); + else { + i8042_aux_port = i8042_allocate_aux_port(); + if (i8042_aux_port) + i8042_port_register(i8042_aux_port); + } } - i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + i8042_kbd_port = i8042_allocate_kbd_port(); + if (i8042_kbd_port) + i8042_port_register(i8042_kbd_port); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -1009,14 +1032,15 @@ void __exit i8042_exit(void) i8042_controller_cleanup(); if (i8042_kbd_values.exists) - serio_unregister_port(&i8042_kbd_port); + serio_unregister_port(i8042_kbd_port); if (i8042_aux_values.exists) - serio_unregister_port(&i8042_aux_port); + serio_unregister_port(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_unregister_port(i8042_mux_port + i); + serio_unregister_port(i8042_mux_port[i]); + del_timer_sync(&i8042_timer); i8042_platform_exit(); --- linux-2.6.8-rc1/drivers/input/serio/i8042.h 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/input/serio/i8042.h 2004-07-13 17:09:22.078916368 -0700 @@ -104,6 +104,13 @@ #define I8042_BUFFER_SIZE 32 /* + * Number of AUX ports on controllers supporting active multiplexing + * specification + */ + +#define I8042_NUM_MUX_PORTS 4 + +/* * Debug. */ --- linux-2.6.8-rc1/drivers/input/serio/i8042-io.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/serio/i8042-io.h 2004-07-13 17:09:22.075916824 -0700 @@ -65,6 +65,31 @@ static inline void i8042_write_command(i return; } +#if defined(__i386__) + +#include + +static struct dmi_system_id __initdata i8042_dmi_table[] = { + { + .ident = "Compaq Proliant 8500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, + }, + { + .ident = "Compaq Proliant DL760", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, + }, + { } +}; +#endif + static inline int i8042_platform_init(void) { /* @@ -79,6 +104,12 @@ static inline int i8042_platform_init(vo #if !defined(__i386__) && !defined(__x86_64__) i8042_reset = 1; #endif + +#if defined(__i386__) + if (dmi_check_system(i8042_dmi_table)) + i8042_noloop = 1; +#endif + return 0; } --- linux-2.6.8-rc1/drivers/input/serio/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/serio/Kconfig 2004-07-13 17:09:22.000000000 -0700 @@ -130,3 +130,19 @@ config SERIO_MACEPS2 To compile this driver as a module, choose M here: the module will be called maceps2. + +config SERIO_RAW + tristate "Raw access to serio ports" + depends on SERIO + help + Say Y here if you want to have raw access to serio ports, such as + AUX ports on i8042 keyboard controller. Each serio port that is + bound to this driver will be accessible via a char device with + major 10 and dynamically allocated minor. The driver will try + allocating minor 1 (that historically corresponds to /dev/psaux) + first. To bind this driver to a serio port use sysfs interface: + + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver + + To compile this driver as a module, choose M here: the + module will be called serio_raw. --- linux-2.6.8-rc1/drivers/input/serio/maceps2.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/input/serio/maceps2.c 2004-07-13 17:09:22.000000000 -0700 @@ -46,15 +46,17 @@ MODULE_LICENSE("GPL"); #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ #define PS2_CONTROL_RESET BIT(5) /* reset */ - struct maceps2_data { struct mace_ps2port *port; int irq; }; +static struct maceps2_data port_data[2]; +static struct serio *maceps2_port[2]; + static int maceps2_write(struct serio *dev, unsigned char val) { - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int timeout = MACE_PS2_TIMEOUT; do { @@ -68,11 +70,10 @@ static int maceps2_write(struct serio *d return -1; } -static irqreturn_t maceps2_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct serio *dev = dev_id; - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int byte; if (mace_read(port->status) & PS2_STATUS_RX_FULL) { @@ -85,7 +86,7 @@ static irqreturn_t maceps2_interrupt(int static int maceps2_open(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); @@ -106,7 +107,7 @@ static int maceps2_open(struct serio *de static void maceps2_close(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, data->port->control); @@ -114,46 +115,52 @@ static void maceps2_close(struct serio * free_irq(data->irq, dev); } -static struct maceps2_data port0_data, port1_data; -static struct serio maceps2_port0 = +static struct serio * __init maceps2_allocate_port(int idx) { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port0", - .phys = "mace/serio0", - .driver = &port0_data, -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = maceps2_write; + serio->open = maceps2_open; + serio->close = maceps2_close; + snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); + snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); + serio->port_data = &port_data[idx]; + } + + return serio; +} -static struct serio maceps2_port1 = -{ - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port1", - .phys = "mace/serio1", - .driver = &port1_data, -}; static int __init maceps2_init(void) { - port0_data.port = &mace->perif.ps2.keyb; - port0_data.irq = MACEISA_KEYB_IRQ; - port1_data.port = &mace->perif.ps2.mouse; - port1_data.irq = MACEISA_MOUSE_IRQ; - serio_register_port(&maceps2_port0); - serio_register_port(&maceps2_port1); + port_data[0].port = &mace->perif.ps2.keyb; + port_data[0].irq = MACEISA_KEYB_IRQ; + port_data[1].port = &mace->perif.ps2.mouse; + port_data[1].irq = MACEISA_MOUSE_IRQ; + + maceps2_port[0] = maceps2_allocate_port(0); + maceps2_port[1] = maceps2_allocate_port(1); + if (!maceps2_port[0] || !maceps2_port[1]) { + kfree(maceps2_port[0]); + kfree(maceps2_port[1]); + return -ENOMEM; + } + + serio_register_port(maceps2_port[0]); + serio_register_port(maceps2_port[1]); return 0; } static void __exit maceps2_exit(void) { - serio_unregister_port(&maceps2_port0); - serio_unregister_port(&maceps2_port1); + serio_unregister_port(maceps2_port[0]); + serio_unregister_port(maceps2_port[1]); } module_init(maceps2_init); --- linux-2.6.8-rc1/drivers/input/serio/Makefile 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/input/serio/Makefile 2004-07-13 17:09:22.071917432 -0700 @@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o +obj-$(CONFIG_SERIO_RAW) += serio_raw.o --- linux-2.6.8-rc1/drivers/input/serio/parkbd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/parkbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -53,9 +53,7 @@ static int parkbd_writing; static unsigned long parkbd_start; static struct pardevice *parkbd_dev; - -static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; -static char parkbd_phys[32]; +static struct serio *parkbd_port; static int parkbd_readlines(void) { @@ -86,13 +84,6 @@ static int parkbd_write(struct serio *po return 0; } -static struct serio parkbd_port = -{ - .write = parkbd_write, - .name = parkbd_name, - .phys = parkbd_phys, -}; - static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, vo parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; if (parkbd_counter == parkbd_mode + 10) - serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); + serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); } parkbd_last = jiffies; @@ -163,16 +154,38 @@ static int parkbd_getport(void) return 0; } +static struct serio * __init parkbd_allocate_serio(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + serio->type = parkbd_mode; + serio->write = parkbd_write, + strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); + } + + return serio; +} int __init parkbd_init(void) { - if (parkbd_getport()) return -1; - parkbd_writelines(3); - parkbd_port.type = parkbd_mode; + int err; - sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + err = parkbd_getport(); + if (err) + return err; + + parkbd_port = parkbd_allocate_serio(); + if (!parkbd_port) { + parport_release(parkbd_dev); + return -ENOMEM; + } + + parkbd_writelines(3); - serio_register_port(&parkbd_port); + serio_register_port(parkbd_port); printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); @@ -183,7 +196,7 @@ int __init parkbd_init(void) void __exit parkbd_exit(void) { parport_release(parkbd_dev); - serio_unregister_port(&parkbd_port); + serio_unregister_port(parkbd_port); parport_unregister_device(parkbd_dev); } --- linux-2.6.8-rc1/drivers/input/serio/pcips2.c 2003-08-22 19:23:40.000000000 -0700 +++ 25/drivers/input/serio/pcips2.c 2004-07-13 17:09:22.000000000 -0700 @@ -38,14 +38,14 @@ #define PS2_STAT_TXEMPTY (1<<7) struct pcips2_data { - struct serio io; + struct serio *io; unsigned int base; struct pci_dev *dev; }; static int pcips2_write(struct serio *io, unsigned char val) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; unsigned int stat; do { @@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); } while (1); return IRQ_RETVAL(handled); } @@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pc static int pcips2_open(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; int ret, val = 0; outb(PS2_CTRL_ENABLE, ps2if->base); @@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io) static void pcips2_close(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; outb(0, ps2if->base); @@ -129,6 +129,7 @@ static void pcips2_close(struct serio *i static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct pcips2_data *ps2if; + struct serio *serio; int ret; ret = pci_enable_device(dev); @@ -142,29 +143,35 @@ static int __devinit pcips2_probe(struct } ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); - if (!ps2if) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { ret = -ENOMEM; goto release; } memset(ps2if, 0, sizeof(struct pcips2_data)); + memset(serio, 0, sizeof(struct serio)); - ps2if->io.type = SERIO_8042; - ps2if->io.write = pcips2_write; - ps2if->io.open = pcips2_open; - ps2if->io.close = pcips2_close; - ps2if->io.name = pci_name(dev); - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + serio->type = SERIO_8042; + serio->write = pcips2_write; + serio->open = pcips2_open; + serio->close = pcips2_close; + strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); pci_set_drvdata(dev, ps2if); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; release: + kfree(ps2if); + kfree(serio); release_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); disable: @@ -176,7 +183,7 @@ static void __devexit pcips2_remove(stru { struct pcips2_data *ps2if = pci_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); pci_set_drvdata(dev, NULL); --- linux-2.6.8-rc1/drivers/input/serio/q40kbd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/q40kbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -47,43 +47,98 @@ MODULE_AUTHOR("Vojtech Pavlik type = SERIO_8042; + serio->open = q40kbd_open; + serio->close = q40kbd_close; + strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, "Q40", sizeof(serio->phys)); + } + + return serio; +} + +static int __init q40kbd_init(void) +{ if (!MACH_IS_Q40) return -EIO; - /* allocate the IRQ */ - request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL); - - /* flush any pending input */ - while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) - master_inb(KEYCODE_REG); - - /* off we go */ - master_outb(-1,KEYBOARD_UNLOCK_REG); - master_outb(1,KEY_IRQ_ENABLE_REG); + if (!(q40kbd_port = q40kbd_allocate_port())) + return -ENOMEM; - serio_register_port(&q40kbd_port); + serio_register_port(q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); return 0; @@ -91,11 +146,7 @@ static int __init q40kbd_init(void) static void __exit q40kbd_exit(void) { - master_outb(0,KEY_IRQ_ENABLE_REG); - master_outb(-1,KEYBOARD_UNLOCK_REG); - - serio_unregister_port(&q40kbd_port); - free_irq(Q40_IRQ_KEYBOARD, NULL); + serio_unregister_port(q40kbd_port); } module_init(q40kbd_init); --- linux-2.6.8-rc1/drivers/input/serio/rpckbd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/rpckbd.c 2004-07-13 17:09:22.000000000 -0700 @@ -44,6 +44,8 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell K MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); +static struct serio *rpckbd_port; + static int rpckbd_write(struct serio *port, unsigned char val) { while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) @@ -101,25 +103,41 @@ static void rpckbd_close(struct serio *p free_irq(IRQ_KEYBOARDTX, port); } -static struct serio rpckbd_port = -{ - .type = SERIO_8042, - .open = rpckbd_open, - .close = rpckbd_close, - .write = rpckbd_write, - .name = "RiscPC PS/2 kbd port", - .phys = "rpckbd/serio0", -}; +/* + * Allocate and initialize serio structure for subsequent registration + * with serio core. + */ + +static struct serio * __init rpckbd_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = rpckbd_write; + serio->open = rpckbd_open; + serio->close = rpckbd_close; + strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); + strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); + } + + return serio; +} static int __init rpckbd_init(void) { - serio_register_port(&rpckbd_port); + if (!(rpckbd_port = rpckbd_allocate_port())) + return -ENOMEM; + + serio_register_port(rpckbd_port); return 0; } static void __exit rpckbd_exit(void) { - serio_unregister_port(&rpckbd_port); + serio_unregister_port(rpckbd_port); } module_init(rpckbd_init); --- linux-2.6.8-rc1/drivers/input/serio/sa1111ps2.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/sa1111ps2.c 2004-07-13 17:09:22.000000000 -0700 @@ -26,7 +26,7 @@ #include struct ps2if { - struct serio io; + struct serio *io; struct sa1111_dev *dev; unsigned long base; unsigned int open; @@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, vo if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); status = sa1111_readl(ps2if->base + SA1111_PS2STAT); } @@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, vo */ static int ps2_write(struct serio *io, unsigned char val) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; unsigned long flags; unsigned int head; @@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, u static int ps2_open(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; int ret; sa1111_enable_device(ps2if->dev); @@ -154,7 +154,7 @@ static int ps2_open(struct serio *io) static void ps2_close(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; sa1111_writel(0, ps2if->base + SA1111_PS2CR); @@ -232,22 +232,28 @@ static int __init ps2_test(struct ps2if static int ps2_probe(struct sa1111_dev *dev) { struct ps2if *ps2if; + struct serio *serio; int ret; ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); - if (!ps2if) { - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + ret = -ENOMEM; + goto free; } memset(ps2if, 0, sizeof(struct ps2if)); + memset(serio, 0, sizeof(struct serio)); - ps2if->io.type = SERIO_8042; - ps2if->io.write = ps2_write; - ps2if->io.open = ps2_open; - ps2if->io.close = ps2_close; - ps2if->io.name = dev->dev.bus_id; - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + serio->type = SERIO_8042; + serio->write = ps2_write; + serio->open = ps2_open; + serio->close = ps2_close; + strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + serio->dev.parent = &dev->dev; + ps2if->io = serio; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); @@ -292,7 +298,7 @@ static int ps2_probe(struct sa1111_dev * ps2_clear_input(ps2if); sa1111_disable_device(ps2if->dev); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; out: @@ -302,6 +308,7 @@ static int ps2_probe(struct sa1111_dev * free: sa1111_set_drvdata(dev, NULL); kfree(ps2if); + kfree(serio); return ret; } @@ -312,7 +319,7 @@ static int ps2_remove(struct sa1111_dev { struct ps2if *ps2if = sa1111_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); sa1111_set_drvdata(dev, NULL); --- linux-2.6.8-rc1/drivers/input/serio/serio.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/serio.c 2004-07-13 17:09:22.085915304 -0700 @@ -1,11 +1,9 @@ /* - * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - -/* * The Serio abstraction module + * + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Dmitry Torokhov + * Copyright (c) 2003 Daniele Bellucci */ /* @@ -26,10 +24,6 @@ * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - * - * Changes: - * 20 Jul. 2003 Daniele Bellucci - * Minor cleanups. */ #include @@ -50,100 +44,178 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port_delayed); -EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port_delayed); -EXPORT_SYMBOL(__serio_unregister_port); -EXPORT_SYMBOL(serio_register_device); -EXPORT_SYMBOL(serio_unregister_device); +EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */ +static LIST_HEAD(serio_list); +static LIST_HEAD(serio_driver_list); +static unsigned int serio_no; + +struct bus_type serio_bus = { + .name = "serio", +}; + +static void serio_find_driver(struct serio *serio); +static void serio_create_port(struct serio *serio); +static void serio_destroy_port(struct serio *serio); +static void serio_connect_port(struct serio *serio, struct serio_driver *drv); +static void serio_reconnect_port(struct serio *serio); +static void serio_disconnect_port(struct serio *serio); + +static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) +{ + get_driver(&drv->driver); + + drv->connect(serio, drv); + if (serio->drv) { + down_write(&serio_bus.subsys.rwsem); + serio->dev.driver = &drv->driver; + device_bind_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + return 1; + } + + put_driver(&drv->driver); + return 0; +} + +/* serio_find_driver() must be called with serio_sem down. */ +static void serio_find_driver(struct serio *serio) +{ + struct serio_driver *drv; + + list_for_each_entry(drv, &serio_driver_list, node) + if (!drv->manual_bind) + if (serio_bind_driver(serio, drv)) + break; +} + +/* + * Serio event processing. + */ + struct serio_event { int type; struct serio *serio; struct list_head node; }; -static DECLARE_MUTEX(serio_sem); -static LIST_HEAD(serio_list); -static LIST_HEAD(serio_dev_list); +enum serio_event_type { + SERIO_RESCAN, + SERIO_RECONNECT, + SERIO_REGISTER_PORT, + SERIO_UNREGISTER_PORT, +}; + +static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ static LIST_HEAD(serio_event_list); +static DECLARE_WAIT_QUEUE_HEAD(serio_wait); +static DECLARE_COMPLETION(serio_exited); static int serio_pid; -static void serio_find_dev(struct serio *serio) +static void serio_queue_event(struct serio *serio, int event_type) { - struct serio_dev *dev; + unsigned long flags; + struct serio_event *event; - list_for_each_entry(dev, &serio_dev_list, node) { - if (serio->dev) - break; - if (dev->connect) - dev->connect(serio, dev); - } -} + spin_lock_irqsave(&serio_event_lock, flags); + + if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { + event->type = event_type; + event->serio = serio; -#define SERIO_RESCAN 1 -#define SERIO_RECONNECT 2 -#define SERIO_REGISTER_PORT 3 -#define SERIO_UNREGISTER_PORT 4 + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); + } -static DECLARE_WAIT_QUEUE_HEAD(serio_wait); -static DECLARE_COMPLETION(serio_exited); + spin_unlock_irqrestore(&serio_event_lock, flags); +} -static void serio_invalidate_pending_events(struct serio *serio) +static struct serio_event *serio_get_event(void) { struct serio_event *event; + struct list_head *node; + unsigned long flags; - list_for_each_entry(event, &serio_event_list, node) - if (event->serio == serio) - event->serio = NULL; + spin_lock_irqsave(&serio_event_lock, flags); + + if (list_empty(&serio_event_list)) { + spin_unlock_irqrestore(&serio_event_lock, flags); + return NULL; + } + + node = serio_event_list.next; + event = container_of(node, struct serio_event, node); + list_del_init(node); + + spin_unlock_irqrestore(&serio_event_lock, flags); + + return event; } -void serio_handle_events(void) +static void serio_handle_events(void) { - struct list_head *node, *next; struct serio_event *event; - list_for_each_safe(node, next, &serio_event_list) { - event = container_of(node, struct serio_event, node); + while ((event = serio_get_event())) { down(&serio_sem); - if (event->serio == NULL) - goto event_done; switch (event->type) { case SERIO_REGISTER_PORT : - __serio_register_port(event->serio); + serio_create_port(event->serio); + serio_connect_port(event->serio, NULL); break; case SERIO_UNREGISTER_PORT : - __serio_unregister_port(event->serio); + serio_disconnect_port(event->serio); + serio_destroy_port(event->serio); break; case SERIO_RECONNECT : - if (event->serio->dev && event->serio->dev->reconnect) - if (event->serio->dev->reconnect(event->serio) == 0) - break; - /* reconnect failed - fall through to rescan */ + serio_reconnect_port(event->serio); + break; case SERIO_RESCAN : - if (event->serio->dev && event->serio->dev->disconnect) - event->serio->dev->disconnect(event->serio); - serio_find_dev(event->serio); + serio_disconnect_port(event->serio); + serio_connect_port(event->serio, NULL); break; default: break; } -event_done: + up(&serio_sem); - list_del_init(node); kfree(event); } } +static void serio_remove_pending_events(struct serio *serio) +{ + struct list_head *node, *next; + struct serio_event *event; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + list_for_each_safe(node, next, &serio_event_list) { + event = container_of(node, struct serio_event, node); + if (event->serio == serio) { + list_del_init(node); + kfree(event); + } + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} + + static int serio_thread(void *nothing) { lock_kernel(); @@ -163,52 +235,211 @@ static int serio_thread(void *nothing) complete_and_exit(&serio_exited, 0); } -static void serio_queue_event(struct serio *serio, int event_type) + +/* + * Serio port operations + */ + +static ssize_t serio_show_description(struct device *dev, char *buf) { - struct serio_event *event; + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->name); +} +static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - event->type = event_type; - event->serio = serio; +static ssize_t serio_show_driver(struct device *dev, char *buf) +{ + return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)"); +} - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); +static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +{ + struct serio *serio = to_serio_port(dev); + struct device_driver *drv; + struct kobject *k; + int retval; + + retval = down_interruptible(&serio_sem); + if (retval) + return retval; + + retval = count; + if (!strncmp(buf, "none", count)) { + serio_disconnect_port(serio); + } else if (!strncmp(buf, "reconnect", count)) { + serio_reconnect_port(serio); + } else if (!strncmp(buf, "rescan", count)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + } else if ((k = kset_find_obj(&serio_bus.drivers, buf)) != NULL) { + drv = container_of(k, struct device_driver, kobj); + serio_disconnect_port(serio); + serio_connect_port(serio, to_serio_driver(drv)); + } else { + retval = -EINVAL; } + + up(&serio_sem); + + return retval; } +static DEVICE_ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver); -void serio_rescan(struct serio *serio) +static void serio_release_port(struct device *dev) { - serio_queue_event(serio, SERIO_RESCAN); + struct serio *serio = to_serio_port(dev); + + kfree(serio); + module_put(THIS_MODULE); } -void serio_reconnect(struct serio *serio) +static void serio_create_port(struct serio *serio) { - serio_queue_event(serio, SERIO_RECONNECT); + try_module_get(THIS_MODULE); + + spin_lock_init(&serio->lock); + list_add_tail(&serio->node, &serio_list); + snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++); + serio->dev.bus = &serio_bus; + serio->dev.release = serio_release_port; + if (serio->parent) + serio->dev.parent = &serio->parent->dev; + device_register(&serio->dev); + device_create_file(&serio->dev, &dev_attr_description); + device_create_file(&serio->dev, &dev_attr_driver); } -irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) +/* + * serio_destroy_port() completes deregistration process and removes + * port from the system + */ +static void serio_destroy_port(struct serio *serio) { - irqreturn_t ret = IRQ_NONE; + struct serio_driver *drv = serio->drv; + unsigned long flags; - if (serio->dev && serio->dev->interrupt) { - ret = serio->dev->interrupt(serio, data, flags, regs); - } else { - if (!flags) { - if ((serio->type == SERIO_8042 || - serio->type == SERIO_8042_XL) && (data != 0xaa)) - return ret; - serio_rescan(serio); - ret = IRQ_HANDLED; + serio_remove_pending_events(serio); + list_del_init(&serio->node); + + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } + + if (serio->parent) { + spin_lock_irqsave(&serio->parent->lock, flags); + serio->parent->child = NULL; + spin_unlock_irqrestore(&serio->parent->lock, flags); + } + + device_unregister(&serio->dev); +} + +/* + * serio_connect_port() tries to bind the port and possible all its + * children to appropriate drivers. If driver passed in the function will not + * try otehr drivers when binding parent port. + */ +static void serio_connect_port(struct serio *serio, struct serio_driver *drv) +{ + WARN_ON(serio->drv); + WARN_ON(serio->child); + + if (drv) + serio_bind_driver(serio, drv); + else + serio_find_driver(serio); + + /* Ok, now bind children, if any */ + while (serio->child) { + serio = serio->child; + + WARN_ON(serio->drv); + WARN_ON(serio->child); + + serio_create_port(serio); + + /* + * With children we just _prefer_ passed in driver, + * but we will try other options in case preferred + * is not the one + */ + if (!drv || !serio_bind_driver(serio, drv)) + serio_find_driver(serio); + } +} + +/* + * + */ +static void serio_reconnect_port(struct serio *serio) +{ + do { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* Ok, old children are now gone, we are done */ + break; + } + serio = serio->child; + } while (serio); +} + +/* + * serio_disconnect_port() unbinds a port from its driver. As a side effect + * all child ports are unbound and destroyed. + */ +static void serio_disconnect_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + struct serio *s; + + if (serio->child) { + /* + * Children ports should be disconnected and destroyed + * first, staring with the leaf one, since we don't want + * to do recursion + */ + do { + s = serio->child; + } while (s->child); + + while (s != serio) { + s = s->parent; + serio_destroy_port(s->child); } } - return ret; + + /* + * Ok, no children left, now disconnect this port + */ + if (drv) { + drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } +} + +void serio_rescan(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RESCAN); +} + +void serio_reconnect(struct serio *serio) +{ + serio_queue_event(serio, SERIO_RECONNECT); } void serio_register_port(struct serio *serio) { down(&serio_sem); - __serio_register_port(serio); + serio_create_port(serio); + serio_connect_port(serio, NULL); up(&serio_sem); } @@ -222,21 +453,11 @@ void serio_register_port_delayed(struct serio_queue_event(serio, SERIO_REGISTER_PORT); } -/* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * connect() function. - */ -void __serio_register_port(struct serio *serio) -{ - list_add_tail(&serio->node, &serio_list); - serio_find_dev(serio); -} - void serio_unregister_port(struct serio *serio) { down(&serio_sem); - __serio_unregister_port(serio); + serio_disconnect_port(serio); + serio_destroy_port(serio); up(&serio_sem); } @@ -250,82 +471,142 @@ void serio_unregister_port_delayed(struc serio_queue_event(serio, SERIO_UNREGISTER_PORT); } + /* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * disconnect() function. + * Serio driver operations */ -void __serio_unregister_port(struct serio *serio) + +static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) { - serio_invalidate_pending_events(serio); - list_del_init(&serio->node); - if (serio->dev && serio->dev->disconnect) - serio->dev->disconnect(serio); + struct serio_driver *driver = to_serio_driver(drv); + return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); } +static DRIVER_ATTR(description, S_IRUGO, serio_driver_show_description, NULL); -void serio_register_device(struct serio_dev *dev) +void serio_register_driver(struct serio_driver *drv) { struct serio *serio; + down(&serio_sem); - list_add_tail(&dev->node, &serio_dev_list); - list_for_each_entry(serio, &serio_list, node) - if (!serio->dev && dev->connect) - dev->connect(serio, dev); + + list_add_tail(&drv->node, &serio_driver_list); + + drv->driver.bus = &serio_bus; + driver_register(&drv->driver); + driver_create_file(&drv->driver, &driver_attr_description); + + if (drv->manual_bind) + goto out; + +start_over: + list_for_each_entry(serio, &serio_list, node) { + if (!serio->drv) { + serio_connect_port(serio, drv); + /* + * if new child appeared then the list is changed, + * we need to start over + */ + if (serio->child) + goto start_over; + } + } + +out: up(&serio_sem); } -void serio_unregister_device(struct serio_dev *dev) +void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; down(&serio_sem); - list_del_init(&dev->node); + list_del_init(&drv->node); + +start_over: list_for_each_entry(serio, &serio_list, node) { - if (serio->dev == dev && dev->disconnect) - dev->disconnect(serio); - serio_find_dev(serio); + if (serio->drv == drv) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* we could've deleted some ports, restart */ + goto start_over; + } } + + driver_unregister(&drv->driver); + up(&serio_sem); } -/* called from serio_dev->connect/disconnect methods under serio_sem */ -int serio_open(struct serio *serio, struct serio_dev *dev) +/* called from serio_driver->connect/disconnect methods under serio_sem */ +int serio_open(struct serio *serio, struct serio_driver *drv) { - serio->dev = dev; + unsigned long flags; + + spin_lock_irqsave(&serio->lock, flags); + serio->drv = drv; + spin_unlock_irqrestore(&serio->lock, flags); if (serio->open && serio->open(serio)) { - serio->dev = NULL; + spin_lock_irqsave(&serio->lock, flags); + serio->drv = NULL; + spin_unlock_irqrestore(&serio->lock, flags); return -1; } return 0; } -/* called from serio_dev->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { + unsigned long flags; + if (serio->close) serio->close(serio); - serio->dev = NULL; + spin_lock_irqsave(&serio->lock, flags); + serio->drv = NULL; + spin_unlock_irqrestore(&serio->lock, flags); } -static int __init serio_init(void) +irqreturn_t serio_interrupt(struct serio *serio, + unsigned char data, unsigned int dfl, struct pt_regs *regs) { - int pid; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&serio->lock, flags); + + if (likely(serio->drv)) { + ret = serio->drv->interrupt(serio, data, dfl, regs); + } else { + if (!dfl) { + if ((serio->type != SERIO_8042 && + serio->type != SERIO_8042_XL) || (data == 0xaa)) { + serio_rescan(serio); + ret = IRQ_HANDLED; + } + } + } - pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL); + spin_unlock_irqrestore(&serio->lock, flags); - if (!pid) { + return ret; +} + +static int __init serio_init(void) +{ + if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { printk(KERN_WARNING "serio: Failed to start kseriod\n"); return -1; } - serio_pid = pid; + bus_register(&serio_bus); return 0; } static void __exit serio_exit(void) { + bus_unregister(&serio_bus); kill_proc(serio_pid, SIGTERM, 1); wait_for_completion(&serio_exited); } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/input/serio/serio_raw.c 2004-07-13 17:09:22.000000000 -0700 @@ -0,0 +1,390 @@ +/* + * Raw serio device providing access to a raw byte stream from underlying + * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device + * + * Copyright (c) 2004 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Raw serio driver" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define SERIO_RAW_QUEUE_LEN 64 +struct serio_raw { + unsigned char queue[SERIO_RAW_QUEUE_LEN]; + unsigned int tail, head; + + char name[16]; + unsigned int refcnt; + struct serio *serio; + struct miscdevice dev; + wait_queue_head_t wait; + struct list_head list; + struct list_head node; +}; + +struct serio_raw_list { + struct fasync_struct *fasync; + struct serio_raw *serio_raw; + struct list_head node; +}; + +static DECLARE_MUTEX(serio_raw_sem); +static LIST_HEAD(serio_raw_list); +static unsigned int serio_raw_no; + +/********************************************************************* + * Interface with userspace (file operations) * + *********************************************************************/ + +static int serio_raw_fasync(int fd, struct file *file, int on) +{ + struct serio_raw_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static struct serio_raw *serio_raw_locate(int minor) +{ + struct serio_raw *serio_raw; + + list_for_each_entry(serio_raw, &serio_raw_list, node) { + if (serio_raw->dev.minor == minor) + return serio_raw; + } + + return NULL; +} + +static int serio_raw_open(struct inode *inode, struct file *file) +{ + struct serio_raw *serio_raw; + struct serio_raw_list *list; + int retval = 0; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!(serio_raw = serio_raw_locate(iminor(inode)))) { + retval = -ENODEV; + goto out; + } + + if (!serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } + + memset(list, 0, sizeof(struct serio_raw_list)); + list->serio_raw = serio_raw; + file->private_data = list; + + serio_raw->refcnt++; + list_add_tail(&list->node, &serio_raw->list); + +out: + up(&serio_raw_sem); + return retval; +} + +static int serio_raw_cleanup(struct serio_raw *serio_raw) +{ + if (--serio_raw->refcnt == 0) { + misc_deregister(&serio_raw->dev); + list_del_init(&serio_raw->node); + kfree(serio_raw); + + return 1; + } + + return 0; +} + +static int serio_raw_release(struct inode *inode, struct file *file) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + + down(&serio_raw_sem); + + serio_raw_fasync(-1, file, 0); + serio_raw_cleanup(serio_raw); + + up(&serio_raw_sem); + return 0; +} + +static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) +{ + unsigned long flags; + int empty; + + spin_lock_irqsave(&serio_raw->serio->lock, flags); + + empty = serio_raw->head == serio_raw->tail; + if (!empty) { + *c = serio_raw->queue[serio_raw->tail]; + serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; + } + + spin_unlock_irqrestore(&serio_raw->serio->lock, flags); + + return !empty; +} + +static ssize_t serio_raw_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + char c; + ssize_t retval = 0; + + if (!serio_raw->serio) + return -ENODEV; + + if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + + retval = wait_event_interruptible(list->serio_raw->wait, + serio_raw->head != serio_raw->tail || !serio_raw->serio); + if (retval) + return retval; + + if (!serio_raw->serio) + return -ENODEV; + + while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { + if (put_user(c, buffer++)) + return -EFAULT; + retval++; + } + + return retval; +} + +static ssize_t serio_raw_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + ssize_t written = 0; + int retval; + unsigned char c; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!list->serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (count > 32) + count = 32; + + while (count--) { + if (get_user(c, buffer++)) { + retval = -EFAULT; + goto out; + } + if (serio_write(list->serio_raw->serio, c)) { + retval = -EIO; + goto out; + } + written++; + }; + +out: + up(&serio_raw_sem); + return written; +} + +static unsigned int serio_raw_poll(struct file *file, poll_table *wait) +{ + struct serio_raw_list *list = file->private_data; + + poll_wait(file, &list->serio_raw->wait, wait); + + if (list->serio_raw->head != list->serio_raw->tail) + return POLLIN | POLLRDNORM; + + return 0; +} + +struct file_operations serio_raw_fops = { + .owner = THIS_MODULE, + .open = serio_raw_open, + .release = serio_raw_release, + .read = serio_raw_read, + .write = serio_raw_write, + .poll = serio_raw_poll, + .fasync = serio_raw_fasync, +}; + + +/********************************************************************* + * Interface with serio port * + *********************************************************************/ + +static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, + unsigned int dfl, struct pt_regs *regs) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_raw_list *list; + unsigned int head = serio_raw->head; + + /* we are holding serio->lock here so we are prootected */ + serio_raw->queue[head] = data; + head = (head + 1) % SERIO_RAW_QUEUE_LEN; + if (likely(head != serio_raw->tail)) { + serio_raw->head = head; + list_for_each_entry(list, &serio_raw->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&serio_raw->wait); + } + + return IRQ_HANDLED; +} + +static void serio_raw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct serio_raw *serio_raw; + int err; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); + return; + } + + down(&serio_raw_sem); + + memset(serio_raw, 0, sizeof(struct serio_raw)); + snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); + serio_raw->refcnt = 1; + serio_raw->serio = serio; + INIT_LIST_HEAD(&serio_raw->list); + init_waitqueue_head(&serio_raw->wait); + + serio->private = serio_raw; + if (serio_open(serio, drv)) + goto out_free; + + list_add_tail(&serio_raw->node, &serio_raw_list); + + serio_raw->dev.minor = PSMOUSE_MINOR; + serio_raw->dev.name = serio_raw->name; + serio_raw->dev.fops = &serio_raw_fops; + + err = misc_register(&serio_raw->dev); + if (err) { + serio_raw->dev.minor = MISC_DYNAMIC_MINOR; + err = misc_register(&serio_raw->dev); + } + + if (err) { + printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", + serio->phys); + goto out_close; + } + + printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", + serio->phys, serio_raw->name, serio_raw->dev.minor); + goto out; + +out_close: + serio_close(serio); + list_del_init(&serio_raw->node); +out_free: + serio->private = NULL; + kfree(serio_raw); +out: + up(&serio_raw_sem); +} + +static int serio_raw_reconnect(struct serio *serio) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_driver *drv = serio->drv; + + if (!drv || !serio_raw) { + printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } + + /* + * Nothing needs to be done here, we just need this method to + * keep the same device. + */ + return 0; +} + +static void serio_raw_disconnect(struct serio *serio) +{ + struct serio_raw *serio_raw; + + down(&serio_raw_sem); + + serio_raw = serio->private; + + serio_close(serio); + serio->private = NULL; + + serio_raw->serio = NULL; + if (!serio_raw_cleanup(serio_raw)) + wake_up_interruptible(&serio_raw->wait); + + up(&serio_raw_sem); +} + +static struct serio_driver serio_raw_drv = { + .driver = { + .name = "serio_raw", + }, + .description = DRIVER_DESC, + .interrupt = serio_raw_interrupt, + .connect = serio_raw_connect, + .reconnect = serio_raw_reconnect, + .disconnect = serio_raw_disconnect, + .manual_bind = 1, +}; + +int __init serio_raw_init(void) +{ + serio_register_driver(&serio_raw_drv); + return 0; +} + +void __exit serio_raw_exit(void) +{ + serio_unregister_driver(&serio_raw_drv); +} + +module_init(serio_raw_init); +module_exit(serio_raw_exit); --- linux-2.6.8-rc1/drivers/input/serio/serport.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/serio/serport.c 2004-07-13 17:09:22.088914848 -0700 @@ -31,28 +31,25 @@ MODULE_ALIAS_LDISC(N_MOUSE); struct serport { struct tty_struct *tty; wait_queue_head_t wait; - struct serio serio; + struct serio *serio; unsigned long flags; - char phys[32]; }; -char serport_name[] = "Serial port"; - /* * Callback functions from the serio code. */ static int serport_serio_write(struct serio *serio, unsigned char data) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); } static void serport_serio_close(struct serio *serio) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; - serport->serio.type = 0; + serport->serio->type = 0; wake_up_interruptible(&serport->wait); } @@ -64,26 +61,30 @@ static void serport_serio_close(struct s static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + struct serio *serio; char name[64]; serport = kmalloc(sizeof(struct serport), GFP_KERNEL); - if (unlikely(!serport)) + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (unlikely(!serport || !serio)) { + kfree(serport); + kfree(serio); return -ENOMEM; - memset(serport, 0, sizeof(struct serport)); + } + memset(serport, 0, sizeof(struct serport)); + serport->serio = serio; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; - snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name)); - - serport->serio.name = serport_name; - serport->serio.phys = serport->phys; - - serport->serio.type = SERIO_RS232; - serport->serio.write = serport_serio_write; - serport->serio.close = serport_serio_close; - serport->serio.driver = serport; + memset(serio, 0, sizeof(struct serio)); + strlcpy(serio->name, "Serial port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); + serio->type = SERIO_RS232; + serio->write = serport_serio_write; + serio->close = serport_serio_close; + serio->port_data = serport; init_waitqueue_head(&serport->wait); @@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct struct serport *serport = (struct serport*) tty->disc_data; int i; for (i = 0; i < count; i++) - serio_interrupt(&serport->serio, cp[i], 0, NULL); + serio_interrupt(serport->serio, cp[i], 0, NULL); } /* @@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serio_register_port(&serport->serio); + serio_register_port(serport->serio); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); - wait_event_interruptible(serport->wait, !serport->serio.type); - serio_unregister_port(&serport->serio); + wait_event_interruptible(serport->wait, !serport->serio->type); + serio_unregister_port(serport->serio); clear_bit(SERPORT_BUSY, &serport->flags); @@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tt struct serport *serport = (struct serport*) tty->disc_data; if (cmd == SPIOCSTYPE) - return get_user(serport->serio.type, (unsigned long __user *) arg); + return get_user(serport->serio->type, (unsigned long __user *) arg); return -EINVAL; } @@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(s { struct serport *sp = (struct serport *) tty->disc_data; - serio_dev_write_wakeup(&sp->serio); + serio_drv_write_wakeup(sp->serio); } /* --- linux-2.6.8-rc1/drivers/input/touchscreen/gunze.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/touchscreen/gunze.c 2004-07-13 17:09:22.000000000 -0700 @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -111,7 +113,7 @@ static void gunze_disconnect(struct seri * and if yes, registers it as an input device. */ -static void gunze_connect(struct serio *serio, struct serio_dev *dev) +static void gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; @@ -142,7 +144,7 @@ static void gunze_connect(struct serio * gunze->dev.id.product = 0x0051; gunze->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(gunze); return; } @@ -156,10 +158,14 @@ static void gunze_connect(struct serio * * The serio device structure. */ -static struct serio_dev gunze_dev = { - .interrupt = gunze_interrupt, - .connect = gunze_connect, - .disconnect = gunze_disconnect, +static struct serio_driver gunze_drv = { + .driver = { + .name = "gunze", + }, + .description = DRIVER_DESC, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, }; /* @@ -168,13 +174,13 @@ static struct serio_dev gunze_dev = { int __init gunze_init(void) { - serio_register_device(&gunze_dev); + serio_register_driver(&gunze_drv); return 0; } void __exit gunze_exit(void) { - serio_unregister_device(&gunze_dev); + serio_unregister_driver(&gunze_drv); } module_init(gunze_init); --- linux-2.6.8-rc1/drivers/input/touchscreen/h3600_ts_input.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/input/touchscreen/h3600_ts_input.c 2004-07-13 17:09:22.000000000 -0700 @@ -45,8 +45,10 @@ #include #include +#define DRIVER_DESC "H3600 touchscreen driver" + MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("H3600 touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -373,7 +375,7 @@ static irqreturn_t h3600ts_interrupt(str * new serio device. It looks whether it was registered as a H3600 touchscreen * and if yes, registers it as an input device. */ -static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) +static void h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; @@ -441,7 +443,7 @@ static void h3600ts_connect(struct serio ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ ts->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); kfree(ts); @@ -478,10 +480,14 @@ static void h3600ts_disconnect(struct se * The serio device structure. */ -static struct serio_dev h3600ts_dev = { - .interrupt = h3600ts_interrupt, - .connect = h3600ts_connect, - .disconnect = h3600ts_disconnect, +static struct serio_driver h3600ts_drv = { + .driver = { + .name = "h3600ts", + }, + .description = DRIVER_DESC, + .interrupt = h3600ts_interrupt, + .connect = h3600ts_connect, + .disconnect = h3600ts_disconnect, }; /* @@ -490,13 +496,13 @@ static struct serio_dev h3600ts_dev = { static int __init h3600ts_init(void) { - serio_register_device(&h3600ts_dev); + serio_register_driver(&h3600ts_drv); return 0; } static void __exit h3600ts_exit(void) { - serio_unregister_device(&h3600ts_dev); + serio_unregister_driver(&h3600ts_drv); } module_init(h3600ts_init); --- linux-2.6.8-rc1/drivers/input/tsdev.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/input/tsdev.c 2004-07-13 17:09:22.000000000 -0700 @@ -3,9 +3,17 @@ * * Copyright (c) 2001 "Crazy" james Simmons * - * Input driver to Touchscreen device driver module. + * Compaq touchscreen protocol driver. The protocol emulated by this driver + * is obsolete; for new programs use the tslib library which can read directly + * from evdev and perform dejittering, variance filtering and calibration - + * all in user space, not at kernel level. The meaning of this driver is + * to allow usage of newer input drivers with old applications that use the + * old /dev/h3600_ts and /dev/h3600_tsraw devices. * - * Sponsored by Transvirtual Technology + * 09-Apr-2004: Andrew Zabolotny + * Fixed to actually work, not just output random numbers. + * Added support for both h3600_ts and h3600_tsraw protocol + * emulation. */ /* @@ -24,11 +32,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to . + * e-mail - mail your message to . */ #define TSDEV_MINOR_BASE 128 #define TSDEV_MINORS 32 +/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ +#define TSDEV_MINOR_MASK 15 #define TSDEV_BUFFER_SIZE 64 #include @@ -52,48 +62,84 @@ #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 #endif +/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw + * devices. The first one must output X/Y data in 'cooked' format, e.g. + * filtered, dejittered and calibrated. Second device just outputs raw + * data received from the hardware. + * + * This driver doesn't support filtering and dejittering; it supports only + * calibration. Filtering and dejittering must be done in the low-level + * driver, if needed, because it may gain additional benefits from knowing + * the low-level details, the nature of noise and so on. + * + * The driver precomputes a calibration matrix given the initial xres and + * yres values (quite innacurate for most touchscreens) that will result + * in a more or less expected range of output values. The driver supports + * the TS_SET_CAL ioctl, which will replace the calibration matrix with a + * new one, supposedly generated from the values taken from the raw device. + */ + MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Input driver to touchscreen converter"); MODULE_LICENSE("GPL"); static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; module_param(xres, uint, 0); -MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; module_param(yres, uint, 0); -MODULE_PARM_DESC(yres, "Vertical screen resolution"); +MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +struct ts_event { + short pressure; + short x; + short y; + short millisecs; +}; + +struct ts_calibration { + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +}; struct tsdev { int exist; int open; int minor; - char name[16]; + char name[8]; wait_queue_head_t wait; struct list_head list; struct input_handle handle; + int x, y, pressure; + struct ts_calibration cal; }; -/* From Compaq's Touch Screen Specification version 0.2 (draft) */ -typedef struct { - short pressure; - short x; - short y; - short millisecs; -} TS_EVENT; - struct tsdev_list { struct fasync_struct *fasync; struct list_head node; struct tsdev *tsdev; int head, tail; - int oldx, oldy, pendown; - TS_EVENT event[TSDEV_BUFFER_SIZE]; + struct ts_event event[TSDEV_BUFFER_SIZE]; + int raw; }; +/* The following ioctl codes are defined ONLY for backward compatibility. + * Don't use tsdev for new developement; use the tslib library instead. + * Touchscreen calibration is a fully userspace task. + */ +/* Use 'f' as magic number */ +#define IOC_H3600_TS_MAGIC 'f' +#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) +#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) + static struct input_handler tsdev_handler; -static struct tsdev *tsdev_table[TSDEV_MINORS]; +static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) { @@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inod int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; - if (i >= TSDEV_MINORS || !tsdev_table[i]) + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; memset(list, 0, sizeof(struct tsdev_list)); + list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; + + i &= TSDEV_MINOR_MASK; list->tsdev = tsdev_table[i]; list_add_tail(&list->node, &tsdev_table[i]->list); file->private_data = list; @@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *f if (!list->tsdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) { - if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT))) + while (list->head != list->tail && + retval + sizeof (struct ts_event) <= count) { + if (copy_to_user (buffer + retval, list->event + list->tail, + sizeof (struct ts_event))) return -EFAULT; list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); - retval += sizeof(TS_EVENT); + retval += sizeof (struct ts_event); } return retval; @@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct fi static int tsdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { -/* struct tsdev_list *list = file->private_data; - struct tsdev *evdev = list->tsdev; - struct input_dev *dev = tsdev->handle.dev; - int retval; - + struct tsdev *tsdev = list->tsdev; + int retval = 0; + switch (cmd) { - case HHEHE: - return 0; - case hjff: - return 0; - default: - return 0; + case TS_GET_CAL: + if (copy_to_user ((void *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + case TS_SET_CAL: + if (copy_from_user (&tsdev->cal, (void *)arg, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + default: + retval = -EINVAL; + break; } -*/ - return -EINVAL; + + return retval; } struct file_operations tsdev_fops = { @@ -227,82 +283,85 @@ static void tsdev_event(struct input_han struct tsdev *tsdev = handle->private; struct tsdev_list *list; struct timeval time; - int size; - list_for_each_entry(list, &tsdev->list, node) { - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - if (size > 0) - list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size); - else - list->oldx = ((value - handle->dev->absmin[ABS_X])); - break; - case ABS_Y: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - if (size > 0) - list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size); - else - list->oldy = ((value - handle->dev->absmin[ABS_Y])); - break; - case ABS_PRESSURE: - list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ? - value - handle->dev->absmin[ABS_PRESSURE] : 0; - break; - } + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + tsdev->x = value; + break; + case ABS_Y: + tsdev->y = value; + break; + case ABS_PRESSURE: + if (value > handle->dev->absmax[ABS_PRESSURE]) + value = handle->dev->absmax[ABS_PRESSURE]; + value -= handle->dev->absmin[ABS_PRESSURE]; + if (value < 0) + value = 0; + tsdev->pressure = value; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: + tsdev->x += value; + if (tsdev->x < 0) + tsdev->x = 0; + else if (tsdev->x > xres) + tsdev->x = xres; + break; + case REL_Y: + tsdev->y += value; + if (tsdev->y < 0) + tsdev->y = 0; + else if (tsdev->y > yres) + tsdev->y = yres; break; + } + break; - case EV_REL: - switch (code) { - case REL_X: - if (!list->pendown) - return; - list->oldx += value; - if (list->oldx < 0) - list->oldx = 0; - else if (list->oldx > xres) - list->oldx = xres; + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + tsdev->pressure = 0; break; - case REL_Y: - if (!list->pendown) - return; - list->oldy += value; - if (list->oldy < 0) - list->oldy = 0; - else if (list->oldy > xres) - list->oldy = xres; + case 1: + if (!tsdev->pressure) + tsdev->pressure = 1; break; } - break; - - case EV_KEY: - if (code == BTN_TOUCH || code == BTN_MOUSE) { - switch (value) { - case 0: - list->pendown = 0; - break; - case 1: - if (!list->pendown) - list->pendown = 1; - break; - case 2: - return; - } - } else - return; - break; } + break; + } + + if (type != EV_SYN || code != SYN_REPORT) + return; + + list_for_each_entry(list, &tsdev->list, node) { + int x, y, tmp; + do_gettimeofday(&time); list->event[list->head].millisecs = time.tv_usec / 100; - list->event[list->head].pressure = list->pendown; - list->event[list->head].x = list->oldx; - list->event[list->head].y = list->oldy; + list->event[list->head].pressure = tsdev->pressure; + + x = tsdev->x; + y = tsdev->y; + + /* Calibration */ + if (!list->raw) { + x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; + y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; + if (tsdev->cal.xyswap) { + tmp = x; x = y; y = tmp; + } + } + + list->event[list->head].x = x; + list->event[list->head].y = y; list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -314,11 +373,11 @@ static struct input_handle *tsdev_connec struct input_device_id *id) { struct tsdev *tsdev; - int minor; + int minor, delta; - for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; + for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; minor++); - if (minor == TSDEV_MINORS) { + if (minor >= TSDEV_MINORS/2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); return NULL; @@ -340,10 +399,25 @@ static struct input_handle *tsdev_connec tsdev->handle.handler = handler; tsdev->handle.private = tsdev; + /* Precompute the rough calibration matrix */ + delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.xscale = (xres << 8) / delta; + tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); + + delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.yscale = (yres << 8) / delta; + tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); + tsdev_table[minor] = tsdev; - + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), + S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); @@ -362,6 +436,7 @@ static void tsdev_disconnect(struct inpu wake_up_interruptible(&tsdev->wait); } else tsdev_free(tsdev); + devfs_remove("input/tsraw%d", tsdev->minor); } static struct input_device_id tsdev_ids[] = { @@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[ .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, },/* A tablet like device, at least touch detection, two absolute axes */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, + },/* A tablet like device with several gradations of pressure */ + {},/* Terminating entry */ }; --- linux-2.6.8-rc1/drivers/isdn/act2000/act2000.h 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/act2000/act2000.h 2004-07-13 17:09:13.000000000 -0700 @@ -15,6 +15,8 @@ #ifndef act2000_h #define act2000_h +#include + #define ACT2000_IOCTL_SETPORT 1 #define ACT2000_IOCTL_GETPORT 2 #define ACT2000_IOCTL_SETIRQ 3 @@ -46,7 +48,7 @@ typedef struct act2000_cdef { /* Struct for downloading firmware */ typedef struct act2000_ddef { int length; /* Length of code */ - char *buffer; /* Ptr. to code */ + char __user *buffer; /* Ptr. to code */ } act2000_ddef; typedef struct act2000_fwid { --- linux-2.6.8-rc1/drivers/isdn/act2000/act2000_isa.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/act2000/act2000_isa.c 2004-07-13 17:09:13.000000000 -0700 @@ -405,7 +405,7 @@ act2000_isa_getid(act2000_card * card) * Download microcode into card, check Firmware signature. */ int -act2000_isa_download(act2000_card * card, act2000_ddef * cb) +act2000_isa_download(act2000_card * card, act2000_ddef __user * cb) { unsigned int length; int ret; @@ -413,18 +413,18 @@ act2000_isa_download(act2000_card * card int c; long timeout; u_char *b; - u_char *p; + u_char __user *p; u_char *buf; act2000_ddef cblock; if (!act2000_isa_reset(card->port)) return -ENXIO; act2000_isa_delay(HZ / 2); - if(copy_from_user(&cblock, (char *) cb, sizeof(cblock))) + if(copy_from_user(&cblock, cb, sizeof(cblock))) return -EFAULT; length = cblock.length; p = cblock.buffer; - if ((ret = verify_area(VERIFY_READ, (void *) p, length))) + if ((ret = verify_area(VERIFY_READ, p, length))) return ret; buf = (u_char *) kmalloc(1024, GFP_KERNEL); if (!buf) --- linux-2.6.8-rc1/drivers/isdn/act2000/act2000_isa.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/isdn/act2000/act2000_isa.h 2004-07-13 17:09:13.000000000 -0700 @@ -128,7 +128,7 @@ typedef enum { extern int act2000_isa_detect(unsigned short portbase); extern int act2000_isa_config_irq(act2000_card * card, short irq); extern int act2000_isa_config_port(act2000_card * card, unsigned short portbase); -extern int act2000_isa_download(act2000_card * card, act2000_ddef * cb); +extern int act2000_isa_download(act2000_card * card, act2000_ddef __user * cb); extern void act2000_isa_release(act2000_card * card); extern void act2000_isa_receive(act2000_card *card); extern void act2000_isa_send(act2000_card *card); --- linux-2.6.8-rc1/drivers/isdn/act2000/module.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/act2000/module.c 2004-07-13 17:09:13.000000000 -0700 @@ -243,16 +243,18 @@ act2000_command(act2000_card * card, isd char tmp[17]; int ret; unsigned long flags; + void __user *arg; switch (c->command) { case ISDN_CMD_IOCTL: memcpy(&a, c->parm.num, sizeof(ulong)); + arg = (void __user *)a; switch (c->arg) { case ACT2000_IOCTL_LOADBOOT: switch (card->bus) { case ACT2000_BUS_ISA: ret = act2000_isa_download(card, - (act2000_ddef *)a); + arg); if (!ret) { card->flags |= ACT2000_FLAGS_LOADED; if (!(card->flags & ACT2000_FLAGS_IVALID)) { @@ -278,7 +280,7 @@ act2000_command(act2000_card * card, isd actcapi_manufacturer_req_net(card); return 0; case ACT2000_IOCTL_SETMSN: - if (copy_from_user(tmp, (char *)a, + if (copy_from_user(tmp, arg, sizeof(tmp))) return -EFAULT; if ((ret = act2000_set_msn(card, tmp))) @@ -287,7 +289,7 @@ act2000_command(act2000_card * card, isd return(actcapi_manufacturer_req_msn(card)); return 0; case ACT2000_IOCTL_ADDCARD: - if (copy_from_user(&cdef, (char *)a, + if (copy_from_user(&cdef, arg, sizeof(cdef))) return -EFAULT; if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id)) @@ -463,18 +465,15 @@ act2000_sendbuf(act2000_card *card, int /* Read the Status-replies from the Interface */ static int -act2000_readstatus(u_char * buf, int len, int user, act2000_card * card) +act2000_readstatus(u_char __user * buf, int len, act2000_card * card) { int count; - u_char *p; + u_char __user *p; for (p = buf, count = 0; count < len; p++, count++) { if (card->status_buf_read == card->status_buf_write) return count; - if (user) - put_user(*card->status_buf_read++, p); - else - *p = *card->status_buf_read++; + put_user(*card->status_buf_read++, p); if (card->status_buf_read > card->status_buf_end) card->status_buf_read = card->status_buf; } @@ -514,7 +513,7 @@ if_command(isdn_ctrl * c) } static int -if_writecmd(const u_char * buf, int len, int user, int id, int channel) +if_writecmd(const u_char __user *buf, int len, int id, int channel) { act2000_card *card = act2000_findcard(id); @@ -529,14 +528,14 @@ if_writecmd(const u_char * buf, int len, } static int -if_readstatus(u_char * buf, int len, int user, int id, int channel) +if_readstatus(u_char __user * buf, int len, int id, int channel) { act2000_card *card = act2000_findcard(id); if (card) { if (!card->flags & ACT2000_FLAGS_RUNNING) return -ENODEV; - return (act2000_readstatus(buf, len, user, card)); + return (act2000_readstatus(buf, len, card)); } printk(KERN_ERR "act2000: if_readstatus called with invalid driverId!\n"); --- linux-2.6.8-rc1/drivers/isdn/capi/capi.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/isdn/capi/capi.c 2004-07-13 17:09:13.000000000 -0700 @@ -162,7 +162,7 @@ static int capincci_add_ack(struct capim printk(KERN_ERR "capi: alloc datahandle failed\n"); return -1; } - n->next = 0; + n->next = NULL; n->datahandle = datahandle; for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ; *pp = n; @@ -211,7 +211,7 @@ static struct capiminor *capiminor_alloc mp = kmalloc(sizeof(*mp), GFP_ATOMIC); if (!mp) { printk(KERN_ERR "capi: can't alloc capiminor\n"); - return 0; + return NULL; } memset(mp, 0, sizeof(struct capiminor)); @@ -245,7 +245,7 @@ static struct capiminor *capiminor_alloc if (!(minor < capi_ttyminors)) { printk(KERN_NOTICE "capi: out of minors\n"); kfree(mp); - return 0; + return NULL; } return mp; @@ -260,7 +260,7 @@ static void capiminor_free(struct capimi write_unlock_irqrestore(&capiminor_list_lock, flags); if (mp->ttyskb) kfree_skb(mp->ttyskb); - mp->ttyskb = 0; + mp->ttyskb = NULL; skb_queue_purge(&mp->inqueue); skb_queue_purge(&mp->outqueue); capiminor_del_all_ack(mp); @@ -292,17 +292,17 @@ static struct capincci *capincci_alloc(s { struct capincci *np, **pp; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - struct capiminor *mp = 0; + struct capiminor *mp = NULL; #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ np = kmalloc(sizeof(*np), GFP_ATOMIC); if (!np) - return 0; + return NULL; memset(np, 0, sizeof(struct capincci)); np->ncci = ncci; np->cdev = cdev; #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE - mp = 0; + mp = NULL; if (cdev->userflags & CAPIFLAG_HIGHJACKING) mp = np->minorp = capiminor_alloc(&cdev->ap, ncci); if (mp) { @@ -339,7 +339,7 @@ static void capincci_free(struct capidev capifs_free_ncci(mp->minor); #endif if (mp->tty) { - mp->nccip = 0; + mp->nccip = NULL; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "reset mp->nccip\n"); #endif @@ -377,7 +377,7 @@ static struct capidev *capidev_alloc(voi cdev = kmalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) - return 0; + return NULL; memset(cdev, 0, sizeof(struct capidev)); init_MUTEX(&cdev->ncci_list_sem); @@ -473,7 +473,7 @@ static int handle_recv_skb(struct capimi printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", datahandle, skb->len); #endif - mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len); + mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len); kfree_skb(skb); return 0; @@ -878,8 +878,7 @@ capi_ioctl(struct inode *inode, struct f struct capi_manufacturer_cmd mcmd; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&mcmd, argp, - sizeof(mcmd))) + if (copy_from_user(&mcmd, argp, sizeof(mcmd))) return -EFAULT; return capi20_manufacturer(mcmd.cmd, mcmd.data); } @@ -1026,8 +1025,8 @@ static void capinc_tty_close(struct tty_ #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close lastclose\n"); #endif - tty->driver_data = (void *)0; - mp->tty = 0; + tty->driver_data = NULL; + mp->tty = NULL; } #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount)); @@ -1062,7 +1061,7 @@ static int capinc_tty_write(struct tty_s skb = mp->ttyskb; if (skb) { - mp->ttyskb = 0; + mp->ttyskb = NULL; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; } @@ -1075,7 +1074,8 @@ static int capinc_tty_write(struct tty_s skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); if (from_user) { - if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { + retval = copy_from_user(skb_put(skb, count), buf, count); + if (retval) { kfree_skb(skb); #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval); @@ -1115,7 +1115,7 @@ static void capinc_tty_put_char(struct t *(skb_put(skb, 1)) = ch; return; } - mp->ttyskb = 0; + mp->ttyskb = NULL; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); @@ -1148,7 +1148,7 @@ static void capinc_tty_flush_chars(struc skb = mp->ttyskb; if (skb) { - mp->ttyskb = 0; + mp->ttyskb = NULL; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); @@ -1466,7 +1466,7 @@ static void __init proc_init(void) for (i=0; i < nelem; i++) { struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, 0); + p->procent = create_proc_entry(p->name, p->mode, NULL); if (p->procent) p->procent->read_proc = p->read_proc; } } @@ -1479,8 +1479,8 @@ static void __exit proc_exit(void) for (i=nelem-1; i >= 0; i--) { struct procfsentries *p = procfsentries + i; if (p->procent) { - remove_proc_entry(p->name, 0); - p->procent = 0; + remove_proc_entry(p->name, NULL); + p->procent = NULL; } } } --- linux-2.6.8-rc1/drivers/isdn/capi/capidrv.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/capi/capidrv.c 2004-07-13 17:09:13.000000000 -0700 @@ -230,7 +230,7 @@ static _cstruct b1config(int l2, int l3) case ISDN_PROTO_L2_HDLC: case ISDN_PROTO_L2_TRANS: default: - return 0; + return NULL; case ISDN_PROTO_L2_V11096: return b1config_async_v110(9600); case ISDN_PROTO_L2_V11019: @@ -336,7 +336,7 @@ static capidrv_plci *new_plci(capidrv_co plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC); if (plcip == 0) - return 0; + return NULL; memset(plcip, 0, sizeof(capidrv_plci)); plcip->state = ST_PLCI_NONE; @@ -356,7 +356,7 @@ static capidrv_plci *find_plci_by_plci(c for (p = card->plci_list; p; p = p->next) if (p->plci == plci) return p; - return 0; + return NULL; } static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid) @@ -365,7 +365,7 @@ static capidrv_plci *find_plci_by_msgid( for (p = card->plci_list; p; p = p->next) if (p->msgid == msgid) return p; - return 0; + return NULL; } static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci) @@ -374,7 +374,7 @@ static capidrv_plci *find_plci_by_ncci(c for (p = card->plci_list; p; p = p->next) if (p->plci == (ncci & 0xffff)) return p; - return 0; + return NULL; } static void free_plci(capidrv_contr * card, capidrv_plci * plcip) @@ -384,7 +384,7 @@ static void free_plci(capidrv_contr * ca for (pp = &card->plci_list; *pp; pp = &(*pp)->next) { if (*pp == plcip) { *pp = (*pp)->next; - card->bchans[plcip->chan].plcip = 0; + card->bchans[plcip->chan].plcip = NULL; card->bchans[plcip->chan].disconnecting = 0; card->bchans[plcip->chan].incoming = 0; kfree(plcip); @@ -406,7 +406,7 @@ static inline capidrv_ncci *new_ncci(cap nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC); if (nccip == 0) - return 0; + return NULL; memset(nccip, 0, sizeof(capidrv_ncci)); nccip->ncci = ncci; @@ -429,12 +429,12 @@ static inline capidrv_ncci *find_ncci(ca capidrv_ncci *p; if ((plcip = find_plci_by_ncci(card, ncci)) == 0) - return 0; + return NULL; for (p = plcip->ncci_list; p; p = p->next) if (p->ncci == ncci) return p; - return 0; + return NULL; } static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card, @@ -444,12 +444,12 @@ static inline capidrv_ncci *find_ncci_by capidrv_ncci *p; if ((plcip = find_plci_by_ncci(card, ncci)) == 0) - return 0; + return NULL; for (p = plcip->ncci_list; p; p = p->next) if (p->msgid == msgid) return p; - return 0; + return NULL; } static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip) @@ -462,7 +462,7 @@ static void free_ncci(capidrv_contr * ca break; } } - card->bchans[nccip->chan].nccip = 0; + card->bchans[nccip->chan].nccip = NULL; kfree(nccip); } @@ -477,7 +477,7 @@ static int capidrv_add_ack(struct capidr printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n"); return -1; } - n->next = 0; + n->next = NULL; n->datahandle = datahandle; n->len = len; for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ; @@ -560,7 +560,7 @@ static void p0(capidrv_contr * card, cap { isdn_ctrl cmd; - card->bchans[plci->chan].contr = 0; + card->bchans[plci->chan].contr = NULL; cmd.command = ISDN_STAT_DHUP; cmd.driver = card->myid; cmd.arg = plci->chan; @@ -580,54 +580,54 @@ struct plcistatechange { static struct plcistatechange plcitable[] = { /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0}, - {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0}, + {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL}, + {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL}, + {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL}, + {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL}, /* P-0.1 */ {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0}, + {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL}, /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL}, + {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL}, /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, + {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL}, /* P-3 */ - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, + {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, /* P-5 */ - {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0}, + {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, /* P-6 */ {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, /* P-0.Res */ {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, - {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0}, + {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL}, /* P-RES */ - {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0}, + {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL}, /* P-HELD */ - {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0}, + {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL}, {}, }; @@ -662,10 +662,10 @@ static void n0(capidrv_contr * card, cap global.ap.applid, card->msgid++, ncci->plcip->plci, - 0, /* BChannelinformation */ - 0, /* Keypadfacility */ - 0, /* Useruserdata */ /* $$$$ */ - 0 /* Facilitydataarray */ + NULL, /* BChannelinformation */ + NULL, /* Keypadfacility */ + NULL, /* Useruserdata */ /* $$$$ */ + NULL /* Facilitydataarray */ ); send_message(card, &cmsg); plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); @@ -689,32 +689,32 @@ struct nccistatechange { static struct nccistatechange nccitable[] = { /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0}, + {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL}, + {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL}, /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0}, + {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL}, {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0}, + {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0}, + {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, + {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL}, /* N-5 */ {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, {}, @@ -821,7 +821,7 @@ static void handle_controller(_cmsg * cm goto ignored; case CAPI_MANUFACTURER_CONF: /* Controller */ if (cmsg->ManuID == 0x214D5641) { - char *s = 0; + char *s = NULL; switch (cmsg->Class) { case 0: break; case 1: s = "unknown class"; break; @@ -950,10 +950,10 @@ static void handle_incoming_call(capidrv global.ap.applid, card->msgid++, plcip->plci, /* adr */ - 0, /* BChannelinformation */ - 0, /* Keypadfacility */ - 0, /* Useruserdata */ - 0 /* Facilitydataarray */ + NULL,/* BChannelinformation */ + NULL,/* Keypadfacility */ + NULL,/* Useruserdata */ + NULL /* Facilitydataarray */ ); plcip->msgid = cmsg->Messagenumber; send_message(card, cmsg); @@ -1090,7 +1090,7 @@ static void handle_plci(_cmsg * cmsg) global.ap.applid, card->msgid++, plcip->plci, /* adr */ - 0 /* NCPI */ + NULL /* NCPI */ ); nccip->msgid = cmsg->Messagenumber; send_message(card, cmsg); @@ -1208,7 +1208,7 @@ static void handle_ncci(_cmsg * cmsg) card->msgid++, nccip->ncci, /* adr */ 0, /* Reject */ - 0 /* NCPI */ + NULL /* NCPI */ ); send_message(card, cmsg); ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); @@ -1226,7 +1226,7 @@ static void handle_ncci(_cmsg * cmsg) card->msgid++, cmsg->adr.adrNCCI, 2, /* Reject */ - 0 /* NCPI */ + NULL /* NCPI */ ); send_message(card, cmsg); break; @@ -1624,22 +1624,22 @@ static int capidrv_command(isdn_ctrl * c si2cip(bchan->si1, bchan->si2), /* cipvalue */ called, /* CalledPartyNumber */ calling, /* CallingPartyNumber */ - 0, /* CalledPartySubaddress */ - 0, /* CallingPartySubaddress */ + NULL, /* CalledPartySubaddress */ + NULL, /* CallingPartySubaddress */ b1prot(bchan->l2, bchan->l3), /* B1protocol */ b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ b1config(bchan->l2, bchan->l3), /* B1configuration */ - 0, /* B2configuration */ - 0, /* B3configuration */ - 0, /* BC */ - 0, /* LLC */ - 0, /* HLC */ + NULL, /* B2configuration */ + NULL, /* B3configuration */ + NULL, /* BC */ + NULL, /* LLC */ + NULL, /* HLC */ /* BChannelinformation */ - isleasedline ? AdditionalInfo : 0, - 0, /* Keypadfacility */ - 0, /* Useruserdata */ - 0 /* Facilitydataarray */ + isleasedline ? AdditionalInfo : NULL, + NULL, /* Keypadfacility */ + NULL, /* Useruserdata */ + NULL /* Facilitydataarray */ ); if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) { cmd.command = ISDN_STAT_DHUP; @@ -1672,15 +1672,15 @@ static int capidrv_command(isdn_ctrl * c b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ b1config(bchan->l2, bchan->l3), /* B1configuration */ - 0, /* B2configuration */ - 0, /* B3configuration */ - 0, /* ConnectedNumber */ - 0, /* ConnectedSubaddress */ - 0, /* LLC */ - 0, /* BChannelinformation */ - 0, /* Keypadfacility */ - 0, /* Useruserdata */ - 0 /* Facilitydataarray */ + NULL, /* B2configuration */ + NULL, /* B3configuration */ + NULL, /* ConnectedNumber */ + NULL, /* ConnectedSubaddress */ + NULL, /* LLC */ + NULL, /* BChannelinformation */ + NULL, /* Keypadfacility */ + NULL, /* Useruserdata */ + NULL /* Facilitydataarray */ ); capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); @@ -1714,7 +1714,7 @@ static int capidrv_command(isdn_ctrl * c global.ap.applid, card->msgid++, bchan->nccip->ncci, - 0 /* NCPI */ + NULL /* NCPI */ ); ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); send_message(card, &cmdcmsg); @@ -1735,10 +1735,10 @@ static int capidrv_command(isdn_ctrl * c global.ap.applid, card->msgid++, bchan->plcip->plci, - 0, /* BChannelinformation */ - 0, /* Keypadfacility */ - 0, /* Useruserdata */ - 0 /* Facilitydataarray */ + NULL, /* BChannelinformation */ + NULL, /* Keypadfacility */ + NULL, /* Useruserdata */ + NULL /* Facilitydataarray */ ); plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); send_message(card, &cmdcmsg); @@ -1892,11 +1892,11 @@ static int if_sendbuf(int id, int channe } } -static int if_readstat(u8 *buf, int len, int user, int id, int channel) +static int if_readstat(u8 __user *buf, int len, int id, int channel) { capidrv_contr *card = findcontrbydriverid(id); int count; - u8 *p; + u8 __user *p; if (!card) { printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", @@ -1905,10 +1905,7 @@ static int if_readstat(u8 *buf, int len, } for (p=buf, count=0; count < len; p++, count++) { - if (user) - put_user(*card->q931_read++, p); - else - *p = *card->q931_read++; + put_user(*card->q931_read++, p); if (card->q931_read > card->q931_end) card->q931_read = card->q931_buf; } @@ -1977,7 +1974,7 @@ static void send_listen(capidrv_contr *c 1 << 6, /* Infomask */ card->cipmask, card->cipmask2, - 0, 0); + NULL, NULL); send_message(card, &cmdcmsg); listen_change_state(card, EV_LISTEN_REQ); } @@ -2028,7 +2025,7 @@ static int capidrv_addcontr(u16 contr, s card->interface.maxbufsize = 2048; card->interface.command = if_command; card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = 0; + card->interface.writecmd = NULL; card->interface.readstat = if_readstat; card->interface.features = ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS | @@ -2141,7 +2138,7 @@ static int capidrv_delcontr(u16 contr) card->nbchan--; } kfree(card->bchans); - card->bchans = 0; + card->bchans = NULL; if (debugmode) printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", @@ -2159,7 +2156,7 @@ static int capidrv_delcontr(u16 contr) for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { if (*pp == card) { *pp = (*pp)->next; - card->next = 0; + card->next = NULL; global.ncontr--; break; } @@ -2228,7 +2225,7 @@ static void __init proc_init(void) for (i=0; i < nelem; i++) { struct procfsentries *p = procfsentries + i; - p->procent = create_proc_entry(p->name, p->mode, 0); + p->procent = create_proc_entry(p->name, p->mode, NULL); if (p->procent) p->procent->read_proc = p->read_proc; } } @@ -2241,8 +2238,8 @@ static void __exit proc_exit(void) for (i=nelem-1; i >= 0; i--) { struct procfsentries *p = procfsentries + i; if (p->procent) { - remove_proc_entry(p->name, 0); - p->procent = 0; + remove_proc_entry(p->name, NULL); + p->procent = NULL; } } } --- linux-2.6.8-rc1/drivers/isdn/capi/capilib.c 2003-09-08 13:58:57.000000000 -0700 +++ 25/drivers/isdn/capi/capilib.c 2004-07-13 17:09:13.000000000 -0700 @@ -30,8 +30,8 @@ struct capilib_ncci { static inline void mq_init(struct capilib_ncci * np) { u_int i; - np->msgidqueue = 0; - np->msgidlast = 0; + np->msgidqueue = NULL; + np->msgidlast = NULL; np->nmsg = 0; memset(np->msgidpool, 0, sizeof(np->msgidpool)); np->msgidfree = &np->msgidpool[0]; @@ -48,7 +48,7 @@ static inline int mq_enqueue(struct capi return 0; np->msgidfree = mq->next; mq->msgid = msgid; - mq->next = 0; + mq->next = NULL; if (np->msgidlast) np->msgidlast->next = mq; np->msgidlast = mq; @@ -66,7 +66,7 @@ static inline int mq_dequeue(struct capi struct capilib_msgidqueue *mq = *pp; *pp = mq->next; if (mq == np->msgidlast) - np->msgidlast = 0; + np->msgidlast = NULL; mq->next = np->msgidfree; np->msgidfree = mq; np->nmsg--; --- linux-2.6.8-rc1/drivers/isdn/capi/capiutil.c 2003-06-14 12:18:21.000000000 -0700 +++ 25/drivers/isdn/capi/capiutil.c 2004-07-13 17:09:13.000000000 -0700 @@ -335,85 +335,54 @@ static _cdef cdef[] = static unsigned char *cpars[] = { - /*00 */ 0, - /*01 ALERT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /*02 CONNECT_REQ */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /*03 */ 0, - /*04 DISCONNECT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01", - /*05 LISTEN_REQ */ (unsigned char *) "\x03\x25\x12\x13\x10\x11\x01", - /*06 */ 0, - /*07 */ 0, - /*08 INFO_REQ */ (unsigned char *) "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", - /*09 FACILITY_REQ */ (unsigned char *) "\x03\x1f\x1e\x01", - /*0a SELECT_B_PROTOCOL_REQ */ (unsigned char *) "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", - /*0b CONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01", - /*0c */ 0, - /*0d DISCONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01", - /*0e */ 0, - /*0f DATA_B3_REQ */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01", - /*10 RESET_B3_REQ */ (unsigned char *) "\x03\x2b\x01", - /*11 */ 0, - /*12 */ 0, - /*13 ALERT_CONF */ (unsigned char *) "\x03\x23\x01", - /*14 CONNECT_CONF */ (unsigned char *) "\x03\x23\x01", - /*15 */ 0, - /*16 DISCONNECT_CONF */ (unsigned char *) "\x03\x23\x01", - /*17 LISTEN_CONF */ (unsigned char *) "\x03\x23\x01", - /*18 MANUFACTURER_REQ */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", - /*19 */ 0, - /*1a INFO_CONF */ (unsigned char *) "\x03\x23\x01", - /*1b FACILITY_CONF */ (unsigned char *) "\x03\x23\x1f\x1b\x01", - /*1c SELECT_B_PROTOCOL_CONF */ (unsigned char *) "\x03\x23\x01", - /*1d CONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01", - /*1e */ 0, - /*1f DISCONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01", - /*20 */ 0, - /*21 DATA_B3_CONF */ (unsigned char *) "\x03\x19\x23\x01", - /*22 RESET_B3_CONF */ (unsigned char *) "\x03\x23\x01", - /*23 */ 0, - /*24 */ 0, - /*25 */ 0, - /*26 CONNECT_IND */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", - /*27 CONNECT_ACTIVE_IND */ (unsigned char *) "\x03\x16\x17\x28\x01", - /*28 DISCONNECT_IND */ (unsigned char *) "\x03\x2c\x01", - /*29 */ 0, - /*2a MANUFACTURER_CONF */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", - /*2b */ 0, - /*2c INFO_IND */ (unsigned char *) "\x03\x26\x24\x01", - /*2d FACILITY_IND */ (unsigned char *) "\x03\x1f\x1d\x01", - /*2e */ 0, - /*2f CONNECT_B3_IND */ (unsigned char *) "\x03\x2b\x01", - /*30 CONNECT_B3_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01", - /*31 DISCONNECT_B3_IND */ (unsigned char *) "\x03\x2d\x2b\x01", - /*32 */ 0, - /*33 DATA_B3_IND */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01", - /*34 RESET_B3_IND */ (unsigned char *) "\x03\x2b\x01", - /*35 CONNECT_B3_T90_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01", - /*36 */ 0, - /*37 */ 0, - /*38 CONNECT_RESP */ (unsigned char *) "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", - /*39 CONNECT_ACTIVE_RESP */ (unsigned char *) "\x03\x01", - /*3a DISCONNECT_RESP */ (unsigned char *) "\x03\x01", - /*3b */ 0, - /*3c MANUFACTURER_IND */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", - /*3d */ 0, - /*3e INFO_RESP */ (unsigned char *) "\x03\x01", - /*3f FACILITY_RESP */ (unsigned char *) "\x03\x1f\x01", - /*40 */ 0, - /*41 CONNECT_B3_RESP */ (unsigned char *) "\x03\x2e\x2b\x01", - /*42 CONNECT_B3_ACTIVE_RESP */ (unsigned char *) "\x03\x01", - /*43 DISCONNECT_B3_RESP */ (unsigned char *) "\x03\x01", - /*44 */ 0, - /*45 DATA_B3_RESP */ (unsigned char *) "\x03\x19\x01", - /*46 RESET_B3_RESP */ (unsigned char *) "\x03\x01", - /*47 CONNECT_B3_T90_ACTIVE_RESP */ (unsigned char *) "\x03\x01", - /*48 */ 0, - /*49 */ 0, - /*4a */ 0, - /*4b */ 0, - /*4c */ 0, - /*4d */ 0, - /*4e MANUFACTURER_RESP */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01", + /* ALERT_REQ */ [0x01] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_REQ */ [0x02] = "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /* DISCONNECT_REQ */ [0x04] = "\x03\x04\x0c\x27\x2f\x1c\x01\x01", + /* LISTEN_REQ */ [0x05] = "\x03\x25\x12\x13\x10\x11\x01", + /* INFO_REQ */ [0x08] = "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01", + /* FACILITY_REQ */ [0x09] = "\x03\x1f\x1e\x01", + /* SELECT_B_PROTOCOL_REQ */ [0x0a] = "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01", + /* CONNECT_B3_REQ */ [0x0b] = "\x03\x2b\x01", + /* DISCONNECT_B3_REQ */ [0x0d] = "\x03\x2b\x01", + /* DATA_B3_REQ */ [0x0f] = "\x03\x18\x1a\x19\x20\x01", + /* RESET_B3_REQ */ [0x10] = "\x03\x2b\x01", + /* ALERT_CONF */ [0x13] = "\x03\x23\x01", + /* CONNECT_CONF */ [0x14] = "\x03\x23\x01", + /* DISCONNECT_CONF */ [0x16] = "\x03\x23\x01", + /* LISTEN_CONF */ [0x17] = "\x03\x23\x01", + /* MANUFACTURER_REQ */ [0x18] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_CONF */ [0x1a] = "\x03\x23\x01", + /* FACILITY_CONF */ [0x1b] = "\x03\x23\x1f\x1b\x01", + /* SELECT_B_PROTOCOL_CONF */ [0x1c] = "\x03\x23\x01", + /* CONNECT_B3_CONF */ [0x1d] = "\x03\x23\x01", + /* DISCONNECT_B3_CONF */ [0x1f] = "\x03\x23\x01", + /* DATA_B3_CONF */ [0x21] = "\x03\x19\x23\x01", + /* RESET_B3_CONF */ [0x22] = "\x03\x23\x01", + /* CONNECT_IND */ [0x26] = "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_ACTIVE_IND */ [0x27] = "\x03\x16\x17\x28\x01", + /* DISCONNECT_IND */ [0x28] = "\x03\x2c\x01", + /* MANUFACTURER_CONF */ [0x2a] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_IND */ [0x2c] = "\x03\x26\x24\x01", + /* FACILITY_IND */ [0x2d] = "\x03\x1f\x1d\x01", + /* CONNECT_B3_IND */ [0x2f] = "\x03\x2b\x01", + /* CONNECT_B3_ACTIVE_IND */ [0x30] = "\x03\x2b\x01", + /* DISCONNECT_B3_IND */ [0x31] = "\x03\x2d\x2b\x01", + /* DATA_B3_IND */ [0x33] = "\x03\x18\x1a\x19\x20\x01", + /* RESET_B3_IND */ [0x34] = "\x03\x2b\x01", + /* CONNECT_B3_T90_ACTIVE_IND */ [0x35] = "\x03\x2b\x01", + /* CONNECT_RESP */ [0x38] = "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01", + /* CONNECT_ACTIVE_RESP */ [0x39] = "\x03\x01", + /* DISCONNECT_RESP */ [0x3a] = "\x03\x01", + /* MANUFACTURER_IND */ [0x3c] = "\x03\x2a\x15\x21\x29\x01", + /* INFO_RESP */ [0x3e] = "\x03\x01", + /* FACILITY_RESP */ [0x3f] = "\x03\x1f\x01", + /* CONNECT_B3_RESP */ [0x41] = "\x03\x2e\x2b\x01", + /* CONNECT_B3_ACTIVE_RESP */ [0x42] = "\x03\x01", + /* DISCONNECT_B3_RESP */ [0x43] = "\x03\x01", + /* DATA_B3_RESP */ [0x45] = "\x03\x19\x01", + /* RESET_B3_RESP */ [0x46] = "\x03\x01", + /* CONNECT_B3_T90_ACTIVE_RESP */ [0x47] = "\x03\x01", + /* MANUFACTURER_RESP */ [0x4e] = "\x03\x2a\x15\x21\x29\x01", }; /*-------------------------------------------------------*/ @@ -623,85 +592,54 @@ unsigned capi_cmsg_header(_cmsg * cmsg, static char *mnames[] = { - 0, - "ALERT_REQ", - "CONNECT_REQ", - 0, - "DISCONNECT_REQ", - "LISTEN_REQ", - 0, - 0, - "INFO_REQ", - "FACILITY_REQ", - "SELECT_B_PROTOCOL_REQ", - "CONNECT_B3_REQ", - 0, - "DISCONNECT_B3_REQ", - 0, - "DATA_B3_REQ", - "RESET_B3_REQ", - 0, - 0, - "ALERT_CONF", - "CONNECT_CONF", - 0, - "DISCONNECT_CONF", - "LISTEN_CONF", - "MANUFACTURER_REQ", - 0, - "INFO_CONF", - "FACILITY_CONF", - "SELECT_B_PROTOCOL_CONF", - "CONNECT_B3_CONF", - 0, - "DISCONNECT_B3_CONF", - 0, - "DATA_B3_CONF", - "RESET_B3_CONF", - 0, - 0, - 0, - "CONNECT_IND", - "CONNECT_ACTIVE_IND", - "DISCONNECT_IND", - 0, - "MANUFACTURER_CONF", - 0, - "INFO_IND", - "FACILITY_IND", - 0, - "CONNECT_B3_IND", - "CONNECT_B3_ACTIVE_IND", - "DISCONNECT_B3_IND", - 0, - "DATA_B3_IND", - "RESET_B3_IND", - "CONNECT_B3_T90_ACTIVE_IND", - 0, - 0, - "CONNECT_RESP", - "CONNECT_ACTIVE_RESP", - "DISCONNECT_RESP", - 0, - "MANUFACTURER_IND", - 0, - "INFO_RESP", - "FACILITY_RESP", - 0, - "CONNECT_B3_RESP", - "CONNECT_B3_ACTIVE_RESP", - "DISCONNECT_B3_RESP", - 0, - "DATA_B3_RESP", - "RESET_B3_RESP", - "CONNECT_B3_T90_ACTIVE_RESP", - 0, - 0, - 0, - 0, - 0, - 0, - "MANUFACTURER_RESP" + [0x01] = "ALERT_REQ", + [0x02] = "CONNECT_REQ", + [0x04] = "DISCONNECT_REQ", + [0x05] = "LISTEN_REQ", + [0x08] = "INFO_REQ", + [0x09] = "FACILITY_REQ", + [0x0a] = "SELECT_B_PROTOCOL_REQ", + [0x0b] = "CONNECT_B3_REQ", + [0x0d] = "DISCONNECT_B3_REQ", + [0x0f] = "DATA_B3_REQ", + [0x10] = "RESET_B3_REQ", + [0x13] = "ALERT_CONF", + [0x14] = "CONNECT_CONF", + [0x16] = "DISCONNECT_CONF", + [0x17] = "LISTEN_CONF", + [0x18] = "MANUFACTURER_REQ", + [0x1a] = "INFO_CONF", + [0x1b] = "FACILITY_CONF", + [0x1c] = "SELECT_B_PROTOCOL_CONF", + [0x1d] = "CONNECT_B3_CONF", + [0x1f] = "DISCONNECT_B3_CONF", + [0x21] = "DATA_B3_CONF", + [0x22] = "RESET_B3_CONF", + [0x26] = "CONNECT_IND", + [0x27] = "CONNECT_ACTIVE_IND", + [0x28] = "DISCONNECT_IND", + [0x2a] = "MANUFACTURER_CONF", + [0x2c] = "INFO_IND", + [0x2d] = "FACILITY_IND", + [0x2f] = "CONNECT_B3_IND", + [0x30] = "CONNECT_B3_ACTIVE_IND", + [0x31] = "DISCONNECT_B3_IND", + [0x33] = "DATA_B3_IND", + [0x34] = "RESET_B3_IND", + [0x35] = "CONNECT_B3_T90_ACTIVE_IND", + [0x38] = "CONNECT_RESP", + [0x39] = "CONNECT_ACTIVE_RESP", + [0x3a] = "DISCONNECT_RESP", + [0x3c] = "MANUFACTURER_IND", + [0x3e] = "INFO_RESP", + [0x3f] = "FACILITY_RESP", + [0x41] = "CONNECT_B3_RESP", + [0x42] = "CONNECT_B3_ACTIVE_RESP", + [0x43] = "DISCONNECT_B3_RESP", + [0x45] = "DATA_B3_RESP", + [0x46] = "RESET_B3_RESP", + [0x47] = "CONNECT_B3_T90_ACTIVE_RESP", + [0x4e] = "MANUFACTURER_RESP" }; char *capi_cmd2str(u8 cmd, u8 subcmd) @@ -715,9 +653,9 @@ char *capi_cmd2str(u8 cmd, u8 subcmd) static char *pnames[] = { - /*00 */ 0, - /*01 */ 0, - /*02 */ 0, + /*00 */ NULL, + /*01 */ NULL, + /*02 */ NULL, /*03 */ "Controller/PLCI/NCCI", /*04 */ "AdditionalInfo", /*05 */ "B1configuration", @@ -767,7 +705,7 @@ static char *pnames[] = static char buf[8192]; -static char *p = 0; +static char *p = NULL; #include --- linux-2.6.8-rc1/drivers/isdn/capi/kcapi.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/capi/kcapi.c 2004-07-13 17:09:13.000000000 -0700 @@ -193,7 +193,7 @@ static void notify_down(u32 contr) for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { ap = get_capi_appl_by_nr(applid); if (ap && ap->callback && !ap->release_in_progress) - ap->callback(KCI_CONTRDOWN, contr, 0); + ap->callback(KCI_CONTRDOWN, contr, NULL); } } @@ -421,7 +421,7 @@ attach_capi_ctr(struct capi_ctr *card) card->traceflag = showcapimsgs; sprintf(card->procfn, "capi/controllers/%d", card->cnr); - card->procent = create_proc_entry(card->procfn, 0, 0); + card->procent = create_proc_entry(card->procfn, 0, NULL); if (card->procent) { card->procent->read_proc = (int (*)(char *,char **,off_t,int,int *,void *)) @@ -445,8 +445,8 @@ int detach_capi_ctr(struct capi_ctr *car ncards--; if (card->procent) { - remove_proc_entry(card->procfn, 0); - card->procent = 0; + remove_proc_entry(card->procfn, NULL); + card->procent = NULL; } capi_cards[card->cnr - 1] = NULL; printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n", @@ -524,7 +524,7 @@ u16 capi20_register(struct capi20_appl * ap->nrecvdatapkt = 0; ap->nsentctlpkt = 0; ap->nsentdatapkt = 0; - ap->callback = 0; + ap->callback = NULL; init_MUTEX(&ap->recv_sem); skb_queue_head_init(&ap->recv_queue); INIT_WORK(&ap->recv_work, recv_handler, (void *)ap); @@ -711,14 +711,14 @@ u16 capi20_get_profile(u32 contr, struct EXPORT_SYMBOL(capi20_get_profile); #ifdef CONFIG_AVMB1_COMPAT -static int old_capi_manufacturer(unsigned int cmd, void *data) +static int old_capi_manufacturer(unsigned int cmd, void __user *data) { avmb1_loadandconfigdef ldef; avmb1_extcarddef cdef; avmb1_resetdef rdef; capicardparams cparams; struct capi_ctr *card; - struct capi_driver *driver = 0; + struct capi_driver *driver = NULL; capiloaddata ldata; struct list_head *l; unsigned long flags; @@ -728,12 +728,12 @@ static int old_capi_manufacturer(unsigne case AVMB1_ADDCARD: case AVMB1_ADDCARD_WITH_TYPE: if (cmd == AVMB1_ADDCARD) { - if ((retval = copy_from_user((void *) &cdef, data, + if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_carddef)))) return retval; cdef.cardtype = AVM_CARDTYPE_B1; } else { - if ((retval = copy_from_user((void *) &cdef, data, + if ((retval = copy_from_user(&cdef, data, sizeof(avmb1_extcarddef)))) return retval; } @@ -758,7 +758,7 @@ static int old_capi_manufacturer(unsigne } break; default: - driver = 0; + driver = NULL; break; } if (!driver) { @@ -780,13 +780,13 @@ static int old_capi_manufacturer(unsigne case AVMB1_LOAD_AND_CONFIG: if (cmd == AVMB1_LOAD) { - if (copy_from_user((void *)&ldef, data, + if (copy_from_user(&ldef, data, sizeof(avmb1_loaddef))) return -EFAULT; ldef.t4config.len = 0; - ldef.t4config.data = 0; + ldef.t4config.data = NULL; } else { - if (copy_from_user((void *)&ldef, data, + if (copy_from_user(&ldef, data, sizeof(avmb1_loadandconfigdef))) return -EFAULT; } @@ -843,7 +843,7 @@ static int old_capi_manufacturer(unsigne return 0; case AVMB1_RESETCARD: - if (copy_from_user((void *)&rdef, data, sizeof(avmb1_resetdef))) + if (copy_from_user(&rdef, data, sizeof(avmb1_resetdef))) return -EFAULT; card = get_capi_ctr_by_nr(rdef.contr); if (!card) @@ -869,7 +869,7 @@ static int old_capi_manufacturer(unsigne } #endif -int capi20_manufacturer(unsigned int cmd, void *data) +int capi20_manufacturer(unsigned int cmd, void __user *data) { struct capi_ctr *card; @@ -886,7 +886,7 @@ int capi20_manufacturer(unsigned int cmd { kcapi_flagdef fdef; - if (copy_from_user((void *)&fdef, data, sizeof(kcapi_flagdef))) + if (copy_from_user(&fdef, data, sizeof(kcapi_flagdef))) return -EFAULT; card = get_capi_ctr_by_nr(fdef.contr); @@ -901,13 +901,12 @@ int capi20_manufacturer(unsigned int cmd case KCAPI_CMD_ADDCARD: { struct list_head *l; - struct capi_driver *driver = 0; + struct capi_driver *driver = NULL; capicardparams cparams; kcapi_carddef cdef; int retval; - if ((retval = copy_from_user((void *) &cdef, data, - sizeof(cdef)))) + if ((retval = copy_from_user(&cdef, data, sizeof(cdef)))) return retval; cparams.port = cdef.port; --- linux-2.6.8-rc1/drivers/isdn/capi/kcapi_proc.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/capi/kcapi_proc.c 2004-07-13 17:09:13.000000000 -0700 @@ -246,7 +246,7 @@ create_seq_entry(char *name, mode_t mode static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos) { - struct capi_driver *drv = 0; + struct capi_driver *drv = NULL; struct list_head *l; loff_t i; @@ -256,7 +256,7 @@ static __inline__ struct capi_driver *ca if (i++ == pos) return drv; } - return 0; + return NULL; } static void *capi_driver_start(struct seq_file *seq, loff_t *pos) @@ -271,7 +271,7 @@ static void *capi_driver_next(struct seq { struct capi_driver *drv = (struct capi_driver *)v; ++*pos; - if (drv->list.next == &capi_drivers) return 0; + if (drv->list.next == &capi_drivers) return NULL; return list_entry(drv->list.next, struct capi_driver, list); } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/capifunc.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/capifunc.c 2004-07-13 17:09:13.000000000 -0700 @@ -228,7 +228,7 @@ void sendf(APPL * appl, word command, dw word length = 12, dlength = 0; byte *write; CAPI_MSG msg; - byte *string = 0; + byte *string = NULL; va_list ap; diva_os_message_buffer_s *dmb; diva_card *card = NULL; @@ -1072,7 +1072,7 @@ static int divacapi_connect_didd(void) req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; req.didd_notify.info.callback = (void *)didd_callback; - req.didd_notify.info.context = 0; + req.didd_notify.info.context = NULL; DAdapter.request((ENTITY *) & req); if (req.didd_notify.e.Rc != 0xff) { stop_dbg(); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/capimain.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/capimain.c 2004-07-13 17:09:13.000000000 -0700 @@ -102,8 +102,8 @@ static int diva_ctl_read_proc(char *page void diva_os_set_controller_struct(struct capi_ctr *ctrl) { ctrl->driver_name = DRIVERLNAME; - ctrl->load_firmware = 0; - ctrl->reset_ctr = 0; + ctrl->load_firmware = NULL; + ctrl->reset_ctr = NULL; ctrl->ctr_read_proc = diva_ctl_read_proc; ctrl->owner = THIS_MODULE; } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/dadapter.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/dadapter.c 2004-07-13 17:09:13.000000000 -0700 @@ -293,8 +293,8 @@ static void diva_remove_adapter_callback diva_os_spin_lock_magic_t irql; if (handle && ((--handle) < DIVA_DIDD_MAX_NOTIFICATIONS)) { diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_rm"); - NotificationTable[handle].callback = 0; - NotificationTable[handle].context = 0; + NotificationTable[handle].callback = NULL; + NotificationTable[handle].context = NULL; diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_rm"); DBG_TRC(("Remove adapter notification[%d]", (int)(handle+1))) return; --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/debug.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/debug.c 2004-07-13 17:09:13.000000000 -0700 @@ -89,7 +89,7 @@ static void queueInit (MSG_QUEUE *Q, byt Q->Size = sizeBuffer; Q->Base = Q->Head = Q->Tail = Buffer; Q->High = Buffer + sizeBuffer; - Q->Wrap = 0; + Q->Wrap = NULL; Q->Count= 0; } @@ -107,7 +107,7 @@ static byte *queueAllocMsg (MSG_QUEUE *Q if (Q->Tail == Q->Head) { if (Q->Wrap || need > Q->Size) { - return(0); /* full */ + return NULL; /* full */ } goto alloc; /* empty */ } @@ -115,7 +115,7 @@ static byte *queueAllocMsg (MSG_QUEUE *Q if (Q->Tail > Q->Head) { if (Q->Tail + need <= Q->High) goto alloc; /* append */ if (Q->Base + need > Q->Head) { - return (0); /* too much */ + return NULL; /* too much */ } /* wraparound the queue (but not the message) */ Q->Wrap = Q->Tail; @@ -124,7 +124,7 @@ static byte *queueAllocMsg (MSG_QUEUE *Q } if (Q->Tail + need > Q->Head) { - return (0); /* too much */ + return NULL; /* too much */ } alloc: @@ -151,7 +151,7 @@ static void queueFreeMsg (MSG_QUEUE *Q) if (Q->Wrap) { if (Q->Head >= Q->Wrap) { Q->Head = Q->Base; - Q->Wrap = 0; + Q->Wrap = NULL; } } else if (Q->Head >= Q->Tail) { Q->Head = Q->Tail = Q->Base; @@ -167,7 +167,7 @@ static byte *queuePeekMsg (MSG_QUEUE *Q, if (((byte *)Msg == Q->Tail && !Q->Wrap) || (Msg->Size & MSG_INCOMPLETE)) { - return (0); + return NULL; } else { *size = Msg->Size; return ((byte *)(Msg + 1)); @@ -177,13 +177,13 @@ static byte *queuePeekMsg (MSG_QUEUE *Q, /* Message queue header */ -static MSG_QUEUE* dbg_queue = 0; -static byte* dbg_base = 0; -static int external_dbg_queue = 0; +static MSG_QUEUE* dbg_queue; +static byte* dbg_base; +static int external_dbg_queue; static diva_os_spin_lock_t dbg_q_lock; static diva_os_spin_lock_t dbg_adapter_lock; -static int dbg_q_busy = 0; -static volatile dword dbg_sequence = 0; +static int dbg_q_busy; +static volatile dword dbg_sequence; static dword start_sec; static dword start_usec; @@ -235,16 +235,16 @@ int diva_maint_init (byte* base, unsigne if (diva_os_initialize_spin_lock (&dbg_q_lock, "dbg_init")) { - dbg_queue = 0; - dbg_base = 0; + dbg_queue = NULL; + dbg_base = NULL; external_dbg_queue = 0; return (-1); } if (diva_os_initialize_spin_lock (&dbg_adapter_lock, "dbg_init")) { diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init"); - dbg_queue = 0; - dbg_base = 0; + dbg_queue = NULL; + dbg_base = NULL; external_dbg_queue = 0; return (-1); } @@ -263,8 +263,8 @@ void* diva_maint_finit (void) { void* ret = (void*)dbg_base; int i; - dbg_queue = 0; - dbg_base = 0; + dbg_queue = NULL; + dbg_base = NULL; if (ret) { diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit"); @@ -272,7 +272,7 @@ void* diva_maint_finit (void) { } if (external_dbg_queue) { - ret = 0; + ret = NULL; } external_dbg_queue = 0; @@ -300,12 +300,12 @@ dword diva_dbg_q_length (void) { */ diva_dbg_entry_head_t* diva_maint_get_message (word* size, diva_os_spin_lock_magic_t* old_irql) { - diva_dbg_entry_head_t* pmsg = 0; + diva_dbg_entry_head_t* pmsg = NULL; diva_os_enter_spin_lock_hard (&dbg_q_lock, old_irql, "read"); if (dbg_q_busy) { diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_busy"); - return (0); + return NULL; } dbg_q_busy = 1; @@ -406,7 +406,7 @@ static void DI_register (void *arg) { } if (free_id != -1) { - diva_dbg_entry_head_t* pmsg = 0; + diva_dbg_entry_head_t* pmsg = NULL; int len; char tmp[256]; word size; @@ -476,7 +476,7 @@ static void DI_deregister (pDbgHandle hD dword sec, usec; int i; word size; - byte* pmem = 0; + byte* pmem = NULL; diva_os_get_time (&sec, &usec); @@ -489,24 +489,24 @@ static void DI_deregister (pDbgHandle hD char tmp[256]; int len; - clients[i].hDbg = 0; + clients[i].hDbg = NULL; hDbg->id = -1; hDbg->dbgMask = 0; - hDbg->dbg_end = 0; - hDbg->dbg_prt = 0; - hDbg->dbg_irq = 0; + hDbg->dbg_end = NULL; + hDbg->dbg_prt = NULL; + hDbg->dbg_irq = NULL; if (hDbg->Version > 0) - hDbg->dbg_old = 0; + hDbg->dbg_old = NULL; hDbg->Registered = 0; - hDbg->next = 0; + hDbg->next = NULL; if (clients[i].pIdiLib) { (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib); - clients[i].pIdiLib = 0; + clients[i].pIdiLib = NULL; pmem = clients[i].pmem; - clients[i].pmem = 0; + clients[i].pmem = NULL; } /* @@ -565,7 +565,7 @@ static void DI_format (int do_lock, va_list ap) { diva_os_spin_lock_magic_t old_irql; dword sec, usec; - diva_dbg_entry_head_t* pmsg = 0; + diva_dbg_entry_head_t* pmsg = NULL; dword length; word size; static char fmtBuf[MSG_FRAME_MAX_SIZE+sizeof(*pmsg)+1]; @@ -843,7 +843,7 @@ void diva_mnt_add_xdi_adapter (const DES dword sec, usec, logical, serial, org_mask; int id, best_id = 0, free_id = -1; char tmp[256]; - diva_dbg_entry_head_t* pmsg = 0; + diva_dbg_entry_head_t* pmsg = NULL; int len; word size; byte* pmem; @@ -938,7 +938,7 @@ void diva_mnt_add_xdi_adapter (const DES if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) { diva_mnt_internal_dprintf (0, DLI_ERR, "Adapter(%d) Start failed", (int)logical); (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib); - clients[id].pIdiLib = 0; + clients[id].pIdiLib = NULL; } } else { diva_mnt_internal_dprintf (0, DLI_ERR, "A(%d) management init failed", (int)logical); @@ -946,9 +946,9 @@ void diva_mnt_add_xdi_adapter (const DES } if (!clients[id].pIdiLib) { - clients[id].request = 0; + clients[id].request = NULL; clients[id].request_pending = 0; - clients[id].hDbg = 0; + clients[id].hDbg = NULL; diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register"); diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register"); diva_os_free (0, pmem); @@ -1008,7 +1008,7 @@ void diva_mnt_remove_xdi_adapter (const dword sec, usec; int i; word size; - byte* pmem = 0; + byte* pmem = NULL; diva_os_get_time (&sec, &usec); @@ -1023,14 +1023,14 @@ void diva_mnt_remove_xdi_adapter (const if (clients[i].pIdiLib) { (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib); - clients[i].pIdiLib = 0; + clients[i].pIdiLib = NULL; pmem = clients[i].pmem; - clients[i].pmem = 0; + clients[i].pmem = NULL; } - clients[i].hDbg = 0; - clients[i].request = 0; + clients[i].hDbg = NULL; + clients[i].request = NULL; clients[i].request_pending = 0; /* @@ -1092,7 +1092,7 @@ void* SuperTraceOpenAdapter (int Adapt } } - return (0); + return NULL; } int SuperTraceCloseAdapter (void* AdapterHandle) { @@ -1741,7 +1741,7 @@ int diva_mnt_shutdown_xdi_adapters (void for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) { - pmem = 0; + pmem = NULL; diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload"); diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "unload"); @@ -1753,13 +1753,13 @@ int diva_mnt_shutdown_xdi_adapters (void */ if (clients[i].pIdiLib) { (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib); - clients[i].pIdiLib = 0; + clients[i].pIdiLib = NULL; pmem = clients[i].pmem; - clients[i].pmem = 0; + clients[i].pmem = NULL; } - clients[i].hDbg = 0; - clients[i].request = 0; + clients[i].hDbg = NULL; + clients[i].request = NULL; clients[i].request_pending = 0; } else { fret = -1; --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/di.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/di.c 2004-07-13 17:09:13.000000000 -0700 @@ -81,7 +81,7 @@ static void xdi_xlog_ind (byte Adapter, void pr_out(ADAPTER * a) { byte e_no; - ENTITY * this = 0; + ENTITY * this = NULL; BUFFERS *X; word length; word i; @@ -761,7 +761,7 @@ byte isdn_ind(ADAPTER * a, word clength; word offset; BUFFERS *R; - byte* cma = 0; + byte* cma = NULL; #ifdef USE_EXTENDED_DEBUGS { DBG_TRC(("io)->ANum, Id, Ind)) @@ -814,7 +814,7 @@ byte isdn_ind(ADAPTER * a, Id, cma, sizeof(a->stream_buffer), - &final, 0, 0); + &final, NULL, NULL); } IoAdapter->RBuffer.length = MIN(MLength, 270); if (IoAdapter->RBuffer.length != MLength) { --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/diddfunc.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/diddfunc.c 2004-07-13 17:09:13.000000000 -0700 @@ -66,7 +66,7 @@ static int DIVA_INIT_FUNCTION connect_di req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; req.didd_notify.info.callback = (void *)didd_callback; - req.didd_notify.info.context = 0; + req.didd_notify.info.context = NULL; _DAdapter.request((ENTITY *) & req); if (req.didd_notify.e.Rc != 0xff) return (0); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/diva.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/diva.c 2004-07-13 17:09:13.000000000 -0700 @@ -131,7 +131,7 @@ static diva_supported_cards_info_t divas /* EOL */ - {-1, 0} + {-1} }; static void diva_init_request_array(void); @@ -174,7 +174,7 @@ void *diva_driver_add_card(void *pdev, u for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) { if (divas_supported_cards[i].CardOrdinal == CardOrdinal) { if (!(pdiva = divas_create_pci_card(i, pdev))) { - return (0); + return NULL; } switch (CardOrdinal) { case CARDTYPE_DIVASRV_Q_8M_PCI: @@ -237,11 +237,11 @@ void *diva_driver_add_card(void *pdev, u DBG_ERR(("can not alloc request array")) diva_driver_remove_card(pdiva); - return (0); + return NULL; } } - return (0); + return NULL; } /* -------------------------------------------------------------------------- @@ -286,7 +286,7 @@ void diva_driver_remove_card(void *pdiva int i; pa = a[0] = (diva_os_xdi_adapter_t *) pdiva; - a[1] = a[2] = a[3] = 0; + a[1] = a[2] = a[3] = NULL; diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter"); @@ -311,7 +311,7 @@ void diva_driver_remove_card(void *pdiva if (a[i]) { if (a[i]->controller) { DBG_LOG(("remove adapter (%d)", - a[i]->controller)) IoAdapters[a[i]->controller - 1] = 0; + a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL; remove_adapter_proc(a[i]); } diva_os_free(0, a[i]); @@ -332,7 +332,7 @@ static void *divas_create_pci_card(int h if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) { DBG_ERR(("A: can't alloc adapter")); - return (0); + return NULL; } memset(a, 0x00, sizeof(*a)); @@ -359,7 +359,7 @@ static void *divas_create_pci_card(int h diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card"); diva_os_free(0, a); DBG_ERR(("A: can't get adapter resources")); - return (0); + return NULL; } return (a); @@ -377,7 +377,7 @@ void divasa_xdi_driver_unload(void) (*(a->interface.cleanup_adapter_proc)) (a); } if (a->controller) { - IoAdapters[a->controller - 1] = 0; + IoAdapters[a->controller - 1] = NULL; remove_adapter_proc(a); } diva_os_free(0, a); @@ -388,7 +388,7 @@ void divasa_xdi_driver_unload(void) /* ** Receive and process command from user mode utility */ -void *diva_xdi_open_adapter(void *os_handle, const void *src, +void *diva_xdi_open_adapter(void *os_handle, const void __user *src, int length, divas_xdi_copy_from_user_fn_t cp_fn) { @@ -400,11 +400,11 @@ void *diva_xdi_open_adapter(void *os_han if (length < sizeof(diva_xdi_um_cfg_cmd_t)) { DBG_ERR(("A: A(?) open, msg too small (%d < %d)", length, sizeof(diva_xdi_um_cfg_cmd_t))) - return (0); + return NULL; } if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) - return (0); + return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { @@ -432,12 +432,12 @@ void diva_xdi_close_adapter(void *adapte a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; if (a->xdi_mbox.data) { diva_os_free(0, a->xdi_mbox.data); - a->xdi_mbox.data = 0; + a->xdi_mbox.data = NULL; } } int -diva_xdi_write(void *adapter, void *os_handle, const void *src, +diva_xdi_write(void *adapter, void *os_handle, const void __user *src, int length, divas_xdi_copy_from_user_fn_t cp_fn) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; @@ -480,7 +480,7 @@ diva_xdi_write(void *adapter, void *os_h ** Write answers to user mode utility, if any */ int -diva_xdi_read(void *adapter, void *os_handle, void *dst, +diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; @@ -507,7 +507,7 @@ diva_xdi_read(void *adapter, void *os_ha a->xdi_mbox.data_length); if (ret > 0) { diva_os_free(0, a->xdi_mbox.data); - a->xdi_mbox.data = 0; + a->xdi_mbox.data = NULL; a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY; } @@ -526,7 +526,7 @@ irqreturn_t diva_os_irq_wrapper(int irq, if ((clear_int_proc = a->clear_interrupts_proc)) { (*clear_int_proc) (a); - a->clear_interrupts_proc = 0; + a->clear_interrupts_proc = NULL; return IRQ_HANDLED; } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/diva_dma.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/diva_dma.c 2004-07-13 17:09:13.000000000 -0700 @@ -39,11 +39,10 @@ struct _diva_dma_map_entry { Create local mapping structure and init it to default state */ struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries) { - diva_dma_map_entry_t* pmap; - if (!(pmap = diva_os_malloc (0, sizeof(*pmap)*(nentries+1)))) - return (0); - memset (pmap, 0x00, sizeof(*pmap)*(nentries+1)); - return (pmap); + diva_dma_map_entry_t* pmap = diva_os_malloc(0, sizeof(*pmap)*(nentries+1)); + if (pmap) + memset (pmap, 0, sizeof(*pmap)*(nentries+1)); + return pmap; } /* Free local map (context should be freed before) if any --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/diva.h 2003-06-14 12:18:06.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/diva.h 2004-07-13 17:09:13.000000000 -0700 @@ -9,19 +9,19 @@ void divasa_xdi_driver_unload(void); void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal); void diva_driver_remove_card(void *pdiva); -typedef int (*divas_xdi_copy_to_user_fn_t) (void *os_handle, void *dst, +typedef int (*divas_xdi_copy_to_user_fn_t) (void *os_handle, void __user *dst, const void *src, int length); typedef int (*divas_xdi_copy_from_user_fn_t) (void *os_handle, void *dst, - const void *src, int length); + const void __user *src, int length); -int diva_xdi_read(void *adapter, void *os_handle, void *dst, +int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); -int diva_xdi_write(void *adapter, void *os_handle, const void *src, +int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, int length, divas_xdi_copy_from_user_fn_t cp_fn); -void *diva_xdi_open_adapter(void *os_handle, const void *src, +void *diva_xdi_open_adapter(void *os_handle, const void __user *src, int length, divas_xdi_copy_from_user_fn_t cp_fn); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/divamnt.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/divamnt.c 2004-07-13 17:09:13.000000000 -0700 @@ -53,7 +53,7 @@ static struct timeval start_time; extern int mntfunc_init(int *, void **, unsigned long); extern void mntfunc_finit(void); -extern int maint_read_write(void *buf, int count); +extern int maint_read_write(void __user *buf, int count); /* * helper functions @@ -90,12 +90,12 @@ void diva_os_free_tbuffer(unsigned long /* * kernel/user space copy functions */ -int diva_os_copy_to_user(void *os_handle, void *dst, const void *src, +int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src, int length) { return (copy_to_user(dst, src, length)); } -int diva_os_copy_from_user(void *os_handle, void *dst, const void *src, +int diva_os_copy_from_user(void *os_handle, void *dst, const void __user *src, int length) { return (copy_from_user(dst, src, length)); @@ -142,9 +142,9 @@ static struct proc_dir_entry *maint_proc to read unstructured traces, formated as ascii string only */ static ssize_t -maint_read(struct file *file, char *buf, size_t count, loff_t * off) +maint_read(struct file *file, char __user *buf, size_t count, loff_t * off) { - diva_dbg_entry_head_t *pmsg = 0; + diva_dbg_entry_head_t *pmsg = NULL; diva_os_spin_lock_magic_t old_irql; word size; char *pstr, *dli_label = "UNK"; @@ -264,20 +264,20 @@ maint_read(struct file *file, char *buf, if (diva_os_copy_to_user(NULL, buf, pstr, str_length)) { diva_os_free_tbuffer(0, str_msg); - file->private_data = 0; + file->private_data = NULL; return (-EFAULT); } str_msg[1] += str_length; if ((str_msg[0] - str_msg[1]) <= 0) { diva_os_free_tbuffer(0, str_msg); - file->private_data = 0; + file->private_data = NULL; } return (str_length); } static ssize_t -maint_write(struct file *file, const char *buf, size_t count, loff_t * off) +maint_write(struct file *file, const char __user *buf, size_t count, loff_t * off) { return (-ENODEV); } @@ -304,7 +304,7 @@ static int maint_open(struct inode *ino, opened++; up(&opened_sem); - filep->private_data = 0; + filep->private_data = NULL; return (0); } @@ -313,7 +313,7 @@ static int maint_close(struct inode *ino { if (filep->private_data) { diva_os_free_tbuffer(0, filep->private_data); - filep->private_data = 0; + filep->private_data = NULL; } down(&opened_sem); @@ -360,13 +360,13 @@ static void remove_maint_proc(void) /* * device node operations */ -static ssize_t divas_maint_write(struct file *file, const char *buf, +static ssize_t divas_maint_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { - return (maint_read_write((char *) buf, (int) count)); + return (maint_read_write((char __user *) buf, (int) count)); } -static ssize_t divas_maint_read(struct file *file, char *buf, +static ssize_t divas_maint_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) { return (maint_read_write(buf, (int) count)); @@ -416,7 +416,7 @@ static int DIVA_INIT_FUNCTION maint_init { char tmprev[50]; int ret = 0; - void *buffer = 0; + void *buffer = NULL; do_gettimeofday(&start_time); init_waitqueue_head(&msgwaitq); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/divasfunc.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/divasfunc.c 2004-07-13 17:09:13.000000000 -0700 @@ -173,7 +173,7 @@ static int DIVA_INIT_FUNCTION connect_di req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; req.didd_notify.info.callback = (void *)didd_callback; - req.didd_notify.info.context = 0; + req.didd_notify.info.context = NULL; DAdapter.request((ENTITY *) & req); if (req.didd_notify.e.Rc != 0xff) { stop_dbg(); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/divasi.c 2003-09-27 18:57:44.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/divasi.c 2004-07-13 17:09:13.000000000 -0700 @@ -71,9 +71,9 @@ static char *getrev(const char *revision /* * LOCALS */ -static ssize_t um_idi_read(struct file *file, char *buf, size_t count, +static ssize_t um_idi_read(struct file *file, char __user *buf, size_t count, loff_t * offset); -static ssize_t um_idi_write(struct file *file, const char *buf, +static ssize_t um_idi_write(struct file *file, const char __user *buf, size_t count, loff_t * offset); static unsigned int um_idi_poll(struct file *file, poll_table * wait); static int um_idi_open(struct inode *inode, struct file *file); @@ -231,7 +231,7 @@ divas_um_idi_copy_to_user(void *os_handl } static ssize_t -um_idi_read(struct file *file, char *buf, size_t count, loff_t * offset) +um_idi_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { diva_um_idi_os_context_t *p_os; int ret = -EINVAL; @@ -312,7 +312,7 @@ static int um_idi_open_adapter(struct fi } static ssize_t -um_idi_write(struct file *file, const char *buf, size_t count, +um_idi_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) { diva_um_idi_os_context_t *p_os; --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/divasmain.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/divasmain.c 2004-07-13 17:09:13.000000000 -0700 @@ -556,7 +556,7 @@ void diva_os_remove_soft_isr(diva_os_sof tasklet_kill(&pdpc->divas_task); flush_scheduled_work(); mem = psoft_isr->object; - psoft_isr->object = 0; + psoft_isr->object = NULL; diva_os_free(0, mem); } } @@ -565,7 +565,7 @@ void diva_os_remove_soft_isr(diva_os_sof * kernel/user space copy functions */ static int -xdi_copy_to_user(void *os_handle, void *dst, const void *src, int length) +xdi_copy_to_user(void *os_handle, void __user *dst, const void *src, int length) { if (copy_to_user(dst, src, length)) { return (-EFAULT); @@ -574,7 +574,7 @@ xdi_copy_to_user(void *os_handle, void * } static int -xdi_copy_from_user(void *os_handle, void *dst, const void *src, int length) +xdi_copy_from_user(void *os_handle, void *dst, const void __user *src, int length) { if (copy_from_user(dst, src, length)) { return (-EFAULT); @@ -598,7 +598,7 @@ static int divas_release(struct inode *i return (0); } -static ssize_t divas_write(struct file *file, const char *buf, +static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int ret = -EINVAL; @@ -629,7 +629,7 @@ static ssize_t divas_write(struct file * return (ret); } -static ssize_t divas_read(struct file *file, char *buf, +static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) { int ret = -EINVAL; @@ -703,7 +703,7 @@ static int DIVA_INIT_FUNCTION divas_regi static int __devinit divas_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - void *pdiva = 0; + void *pdiva = NULL; u8 pci_latency; u8 new_latency = 32; --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/divasproc.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/divasproc.c 2004-07-13 17:09:13.000000000 -0700 @@ -54,7 +54,7 @@ extern struct proc_dir_entry *proc_net_e static struct proc_dir_entry *divas_proc_entry = NULL; static ssize_t -divas_read(struct file *file, char *buf, size_t count, loff_t * off) +divas_read(struct file *file, char __user *buf, size_t count, loff_t * off) { int len = 0; int cadapter; @@ -95,7 +95,7 @@ divas_read(struct file *file, char *buf, } static ssize_t -divas_write(struct file *file, const char *buf, size_t count, loff_t * off) +divas_write(struct file *file, const char __user *buf, size_t count, loff_t * off) { return (-ENODEV); } @@ -151,14 +151,17 @@ void remove_divas_proc(void) ** write group_optimization */ static int -write_grp_opt(struct file *file, const char *buffer, unsigned long count, +write_grp_opt(struct file *file, const char __user *buffer, unsigned long count, void *data) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { - switch (buffer[0]) { + char c; + if (get_user(c, buffer)) + return -EFAULT; + switch (c) { case '0': IoAdapter->capi_cfg.cfg_1 &= ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON; @@ -179,14 +182,17 @@ write_grp_opt(struct file *file, const c ** write dynamic_l1_down */ static int -write_d_l1_down(struct file *file, const char *buffer, unsigned long count, +write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count, void *data) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; if ((count == 1) || (count == 2)) { - switch (buffer[0]) { + char c; + if (get_user(c, buffer)) + return -EFAULT; + switch (c) { case '0': IoAdapter->capi_cfg.cfg_1 &= ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON; @@ -256,14 +262,21 @@ read_grp_opt(char *page, char **start, o ** info write */ static int -info_write(struct file *file, const char *buffer, unsigned long count, +info_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; + char c[4]; + + if (count <= 4) + return -EINVAL; + + if (copy_from_user(c, buffer, 4)) + return -EFAULT; /* this is for test purposes only */ - if ((count > 4) && (!memcmp(buffer, "trap", 4))) { + if (!memcmp(c, "trap", 4)) { (*(IoAdapter->os_trap_nfy_Fnc)) (IoAdapter, IoAdapter->ANum); return (count); } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/dqueue.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/dqueue.c 2004-07-13 17:09:13.000000000 -0700 @@ -23,7 +23,7 @@ diva_data_q_init(diva_um_idi_data_queue_ q->segments = max_segments; for (i = 0; i < q->segments; i++) { - q->data[i] = 0; + q->data[i] = NULL; q->length[i] = 0; } q->read = q->write = q->count = q->segment_pending = 0; @@ -46,7 +46,7 @@ int diva_data_q_finit(diva_um_idi_data_q if (q->data[i]) { diva_os_free(0, q->data[i]); } - q->data[i] = 0; + q->data[i] = NULL; q->length[i] = 0; } q->read = q->write = q->count = q->segment_pending = 0; @@ -66,7 +66,7 @@ void *diva_data_q_get_segment4write(diva return (q->data[q->write]); } - return (0); + return NULL; } void @@ -89,7 +89,7 @@ const void *diva_data_q_get_segment4read if (q->count) { return (q->data[q->read]); } - return (0); + return NULL; } int diva_data_q_get_segment_length(const diva_um_idi_data_queue_t * q) --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/idifunc.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/idifunc.c 2004-07-13 17:09:13.000000000 -0700 @@ -199,7 +199,7 @@ static int DIVA_INIT_FUNCTION connect_di req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; req.didd_notify.info.callback = (void *)didd_callback; - req.didd_notify.info.context = 0; + req.didd_notify.info.context = NULL; DAdapter.request((ENTITY *) & req); if (req.didd_notify.e.Rc != 0xff) { stop_dbg(); --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/maintidi.c 2003-06-14 12:17:55.000000000 -0700 +++ 25/drivers/isdn/hardware/eicon/maintidi.c 2004-07-13 17:09:13.000000000 -0700 @@ -112,7 +112,7 @@ diva_strace_library_interface_t* DivaSTr int i; if (!pLib) { - return (0); + return NULL; } pmem += sizeof(*pLib); @@ -161,7 +161,7 @@ diva_strace_library_interface_t* DivaSTr if (!(pLib->hAdapter = SuperTraceOpenAdapter (Adapter))) { diva_mnt_internal_dprintf (0, DLI_ERR, "Can not open XDI adapter"); - return (0); + return NULL; } pLib->Channels = SuperTraceGetNumberOfChannels (pLib->hAdapter); @@ -1170,13 +1170,13 @@ static diva_man_var_header_t* get_next_v byte* start; int msg_length; - if (*msg != ESC) return (0); + if (*msg != ESC) return NULL; start = msg + 2; msg_length = *(msg+1); msg = (start+msg_length); - if (*msg != ESC) return (0); + if (*msg != ESC) return NULL; return ((diva_man_var_header_t*)msg); } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/message.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/message.c 2004-07-13 17:09:13.000000000 -0700 @@ -414,7 +414,7 @@ word api_put(APPL * appl, CAPI_MSG * } a = &adapter[controller]; - plci = 0; + plci = NULL; if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled) { dbug(1,dprintf("plci=%x",msg->header.plci)); @@ -547,7 +547,7 @@ word api_put(APPL * appl, CAPI_MSG * } else { - plci = 0; + plci = NULL; } } dbug(1,dprintf("com=%x",msg->header.command)); @@ -629,7 +629,7 @@ word api_parse(byte * msg, word length if(p>length) return TRUE; } - if(parms) parms[i].info = 0; + if(parms) parms[i].info = NULL; return FALSE; } @@ -661,7 +661,7 @@ void api_save_msg(API_PARSE *in, byte for (j = 0; j < n; j++) *(p++) = in[i].info[j]; } - out->parms[i].info = 0; + out->parms[i].info = NULL; out->parms[i].length = 0; } @@ -725,7 +725,7 @@ void init_internal_command_queue (PLCI plci->internal_command = 0; for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++) - plci->internal_command_queue[i] = 0; + plci->internal_command_queue[i] = NULL; } @@ -759,16 +759,16 @@ void next_internal_command (dword Id, PL UnMapId (Id), (char *)(FILE_), __LINE__)); plci->internal_command = 0; - plci->internal_command_queue[0] = 0; + plci->internal_command_queue[0] = NULL; while (plci->internal_command_queue[1] != 0) { for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++) plci->internal_command_queue[i] = plci->internal_command_queue[i+1]; - plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = 0; + plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = NULL; (*(plci->internal_command_queue[0]))(Id, plci, OK); if (plci->internal_command != 0) return; - plci->internal_command_queue[0] = 0; + plci->internal_command_queue[0] = NULL; } } @@ -1085,7 +1085,7 @@ void plci_remove(PLCI * plci) plci_free_msg_in_queue (plci); plci->channels = 0; - plci->appl = 0; + plci->appl = NULL; if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT)) plci->State = OUTG_DIS_PENDING; } @@ -1715,7 +1715,7 @@ byte info_req(dword Id, word Number, DIV { word i; API_PARSE * ai; - PLCI * rc_plci = 0; + PLCI * rc_plci = NULL; API_PARSE ai_parms[5]; word Info = 0; @@ -2195,7 +2195,7 @@ byte facility_req(dword Id, word Number, relatedadapter = &adapter[MapController ((byte)(relatedPLCIvalue & 0x7f))-1]; relatedPLCIvalue >>=8; /* find PLCI PTR*/ - for(i=0,rplci=0;imax_plci;i++) + for(i=0,rplci=NULL;imax_plci;i++) { if(relatedadapter->plci[i].Id == (byte)relatedPLCIvalue) { @@ -4355,7 +4355,7 @@ void control_rc(PLCI * plci, byte req, if(rc!=OK) { Info = 0x300E; /* not supported */ - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; } sendf(rplci->appl, @@ -4376,7 +4376,7 @@ void control_rc(PLCI * plci, byte req, if(rc!=OK) { Info = 0x300E; /* not supported */ - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; } sendf(rplci->appl, @@ -4560,7 +4560,7 @@ void control_rc(PLCI * plci, byte req, if(rc!=OK) { Info = 0x300E; /* not supported */ - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; } sendf(rplci->appl, @@ -4722,7 +4722,7 @@ void control_rc(PLCI * plci, byte req, dbug(1,dprintf("Auto-Law assign failed")); a->automatic_law = 3; plci->internal_command = 0; - a->automatic_lawPLCI = 0; + a->automatic_lawPLCI = NULL; } break; } @@ -4739,7 +4739,7 @@ void control_rc(PLCI * plci, byte req, plci->internal_command = 0; sig_req(plci,REMOVE,0); send_req(plci); - a->automatic_lawPLCI = 0; + a->automatic_lawPLCI = NULL; } break; } @@ -4839,7 +4839,7 @@ void sig_ind(PLCI * plci) byte *esc_profile = ""; byte facility[256]; - PLCI * tplci = 0; + PLCI * tplci = NULL; byte chi[] = "\x02\x18\x01"; byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08"; byte resume_cau[] = "\x05\x05\x00\x02\x00\x00"; @@ -4981,7 +4981,7 @@ void sig_ind(PLCI * plci) plci->internal_command = 0; sig_req(plci,REMOVE,0); send_req(plci); - a->automatic_lawPLCI = 0; + a->automatic_lawPLCI = NULL; } } if (esc_profile[0]) @@ -5073,7 +5073,7 @@ void sig_ind(PLCI * plci) { force_mt_info = SendMultiIE(plci,Id,multi_fac_parms, FTY, 0x20, 0); force_mt_info |= SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, 0); - SendSSExtInd(0,plci,Id,multi_ssext_parms); + SendSSExtInd(NULL,plci,Id,multi_ssext_parms); SendInfo(plci,Id, parms, force_mt_info); VSwitchReqInd(plci,Id,multi_vswitch_parms); @@ -5144,7 +5144,7 @@ void sig_ind(PLCI * plci) { WRITE_WORD(&SS_Ind[4],0x300E); } - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind); break; @@ -5298,7 +5298,7 @@ void sig_ind(PLCI * plci) break; case CONF_ADD: WRITE_WORD(&CONF_Ind[1],S_CONF_ADD); - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; tplci=plci->relatedPTYPLCI; if(tplci) tplci->ptyState = CONNECTED; plci->ptyState = CONNECTED; @@ -5342,7 +5342,7 @@ void sig_ind(PLCI * plci) { plci->ptyState = IDLE; - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; } @@ -5364,7 +5364,7 @@ void sig_ind(PLCI * plci) case S_3PTY_END: plci->ptyState = IDLE; - plci->relatedPTYPLCI = 0; + plci->relatedPTYPLCI = NULL; plci->ptyState = 0; dbug(1,dprintf("3PTY OFF")); break; @@ -5904,7 +5904,7 @@ void sig_ind(PLCI * plci) /* and signal '+'.Appl must decide */ /* with connect_res if call must */ /* accepted or not */ - for(i=0, tplci=0;icodec_listen[i] && (a->codec_listen[i]->State==INC_CON_PENDING ||a->codec_listen[i]->State==INC_CON_ALERT) ){ @@ -5927,7 +5927,7 @@ void sig_ind(PLCI * plci) add_p(tplci, CAI, voice_cai); add_p(tplci, OAD, a->TelOAD); add_p(tplci, OSA, a->TelOSA); - add_p(tplci,SHIFT|6,0); + add_p(tplci,SHIFT|6,NULL); add_p(tplci,SIN,"\x02\x01\x00"); add_p(tplci,UID,"\x06\x43\x61\x70\x69\x32\x30"); sig_req(tplci,ASSIGN,DSIG_ID); @@ -6080,7 +6080,7 @@ void sig_ind(PLCI * plci) break; case SSEXT_IND: - SendSSExtInd(0,plci,Id,multi_ssext_parms); + SendSSExtInd(NULL,plci,Id,multi_ssext_parms); break; case VSWITCH_REQ: @@ -6218,7 +6218,7 @@ void SendInfo(PLCI * plci, dword Id, b Info_Number = 0x0008; Info_Mask = 0x00; cause[2] = ie[2]; - Info_Element = 0; + Info_Element = NULL; break; case 8: /* display */ dbug(1,dprintf("display(%d)",i)); @@ -7273,8 +7273,8 @@ word get_plci(DIVA_CAPI_ADAPTER * a) plci->sig_req = 0; plci->nl_req = 0; - plci->appl = 0; - plci->relatedPTYPLCI = 0; + plci->appl = NULL; + plci->relatedPTYPLCI = NULL; plci->State = IDLE; plci->SuppState = IDLE; plci->channels = 0; @@ -8899,7 +8899,7 @@ void listen_check(DIVA_CAPI_ADAPTER * add_p(plci,CAI,"\x01\xc0"); add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30"); add_p(plci,LLI,"\x01\xc4"); /* support Dummy CR FAC + MWI + SpoofNotify */ - add_p(plci,SHIFT|6,0); + add_p(plci,SHIFT|6,NULL); add_p(plci,SIN,"\x02\x00\x00"); plci->internal_command = LISTEN_SIG_ASSIGN_PEND; /* do indicate_req if OK */ sig_req(plci,ASSIGN,DSIG_ID); @@ -9216,10 +9216,10 @@ void CodecIdCheck(DIVA_CAPI_ADAPTER *a dbug(1,dprintf("remove temp codec PLCI")); plci_remove(a->AdvCodecPLCI); a->AdvCodecFLAG = 0; - a->AdvCodecPLCI = 0; - a->AdvSignalAppl = 0; + a->AdvCodecPLCI = NULL; + a->AdvSignalAppl = NULL; } - a->AdvSignalPLCI = 0; + a->AdvSignalPLCI = NULL; } } @@ -9351,7 +9351,7 @@ word CapiRelease(word Id) a->Info_Mask[Id-1] = 0; a->CIP_Mask[Id-1] = 0; a->Notification_Mask[Id-1] = 0; - a->codec_listen[Id-1] = 0; + a->codec_listen[Id-1] = NULL; a->requested_options_table[Id-1] = 0; for(j=0; jmax_plci; j++) /* and all PLCIs connected */ { /* with this application */ @@ -9386,7 +9386,7 @@ word CapiRelease(word Id) } if(plci->appl==this) { - plci->appl = 0; + plci->appl = NULL; plci_remove(plci); plci->State = IDLE; } @@ -9405,7 +9405,7 @@ word CapiRelease(word Id) add_p(plci,OAD,"\x01\xfd"); add_p(plci,CAI,"\x01\x80"); add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30"); - add_p(plci,SHIFT|6,0); + add_p(plci,SHIFT|6,NULL); add_p(plci,SIN,"\x02\x00\x00"); plci->internal_command = REM_L1_SIG_ASSIGN_PEND; sig_req(plci,ASSIGN,DSIG_ID); @@ -9424,10 +9424,10 @@ word CapiRelease(word Id) a->AdvCodecPLCI->tel = 0; a->AdvCodecPLCI->adv_nl = 0; } - a->AdvSignalAppl = 0; - a->AdvSignalPLCI = 0; + a->AdvSignalAppl = NULL; + a->AdvSignalPLCI = NULL; a->AdvCodecFLAG = 0; - a->AdvCodecPLCI = 0; + a->AdvCodecPLCI = NULL; } } } @@ -9458,7 +9458,7 @@ static word plci_remove_check(PLCI *pl plci->Id = 0; plci->State = IDLE; plci->channels = 0; - plci->appl = 0; + plci->appl = NULL; plci->notifiedcall = 0; } listen_check(plci->adapter); @@ -10265,8 +10265,8 @@ static word dtmf_parameter_restore_confi /*------------------------------------------------------------------*/ -LI_CONFIG *li_config_table = 0; -word li_total_channels = 0; +LI_CONFIG *li_config_table; +word li_total_channels; /*------------------------------------------------------------------*/ @@ -14948,7 +14948,7 @@ word CapiRegister(word id) add_p(plci,OAD,"\x01\xfd"); add_p(plci,CAI,"\x01\x80"); add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30"); - add_p(plci,SHIFT|6,0); + add_p(plci,SHIFT|6,NULL); add_p(plci,SIN,"\x02\x00\x00"); plci->internal_command = START_L1_SIG_ASSIGN_PEND; sig_req(plci,ASSIGN,DSIG_ID); @@ -15068,7 +15068,7 @@ static int diva_get_dma_descriptor (PLCI pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC; pReq->xdi_dma_descriptor_operation.info.descriptor_number = -1; - pReq->xdi_dma_descriptor_operation.info.descriptor_address = 0; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; e.user[0] = plci->adapter->Id - 1; @@ -15102,7 +15102,7 @@ static void diva_free_dma_descriptor (PL pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE; pReq->xdi_dma_descriptor_operation.info.descriptor_number = nr; - pReq->xdi_dma_descriptor_operation.info.descriptor_address = 0; + pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL; pReq->xdi_dma_descriptor_operation.info.descriptor_magic = 0; e.user[0] = plci->adapter->Id - 1; --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/mntfunc.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/mntfunc.c 2004-07-13 17:09:13.000000000 -0700 @@ -34,10 +34,10 @@ static DESCRIPTOR MaintDescriptor = extern void *diva_os_malloc_tbuffer(unsigned long flags, unsigned long size); extern void diva_os_free_tbuffer(unsigned long flags, void *ptr); -extern int diva_os_copy_to_user(void *os_handle, void *dst, +extern int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src, int length); extern int diva_os_copy_from_user(void *os_handle, void *dst, - const void *src, int length); + const void __user *src, int length); static void no_printf(unsigned char *x, ...) { @@ -102,7 +102,7 @@ static int DIVA_INIT_FUNCTION connect_di req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; req.didd_notify.info.callback = (void *)didd_callback; - req.didd_notify.info.context = 0; + req.didd_notify.info.context = NULL; DAdapter.request((ENTITY *) & req); if (req.didd_notify.e.Rc != 0xff) return (0); @@ -148,7 +148,7 @@ static void DIVA_EXIT_FUNCTION disconnec /* * read/write maint */ -int maint_read_write(void *buf, int count) +int maint_read_write(void __user *buf, int count) { byte data[128]; dword cmd, id, mask; @@ -228,7 +228,7 @@ int maint_read_write(void *buf, int coun diva_os_spin_lock_magic_t old_irql; word size; diva_dbg_entry_head_t *pmsg; - byte *pbuf = 0; + byte *pbuf = NULL; int written = 0; if (mask < 4096) { --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/os_4bri.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/os_4bri.c 2004-07-13 17:09:13.000000000 -0700 @@ -17,7 +17,7 @@ #include "mi_pc.h" #include "dsrv4bri.h" -void *diva_xdiLoadFileFile = 0; +void *diva_xdiLoadFileFile = NULL; dword diva_xdiLoadFileLength = 0; /* @@ -268,7 +268,7 @@ int diva_4bri_init_card(diva_os_xdi_adap (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) { diva_os_free(0, a->slave_adapters[0]); - a->slave_adapters[0] = 0; + a->slave_adapters[0] = NULL; diva_4bri_cleanup_adapter(a); return (-1); } @@ -277,8 +277,8 @@ int diva_4bri_init_card(diva_os_xdi_adap { diva_os_free(0, a->slave_adapters[0]); diva_os_free(0, a->slave_adapters[1]); - a->slave_adapters[0] = 0; - a->slave_adapters[1] = 0; + a->slave_adapters[0] = NULL; + a->slave_adapters[1] = NULL; diva_4bri_cleanup_adapter(a); return (-1); } @@ -300,7 +300,7 @@ int diva_4bri_init_card(diva_os_xdi_adap if (!(a->slave_list = quadro_list)) { for (i = 0; i < (tasks - 1); i++) { diva_os_free(0, a->slave_adapters[i]); - a->slave_adapters[i] = 0; + a->slave_adapters[i] = NULL; } diva_4bri_cleanup_adapter(a); return (-1); @@ -499,7 +499,7 @@ static int diva_4bri_cleanup_adapter(div && a->resources.pci.addr[bar]) { divasa_unmap_pci_bar(a->resources.pci.addr[bar]); a->resources.pci.bar[bar] = 0; - a->resources.pci.addr[bar] = 0; + a->resources.pci.addr[bar] = NULL; } } } @@ -515,12 +515,12 @@ static int diva_4bri_cleanup_adapter(div _4bri_bar_length[1], &a->port_name[0], 1); a->resources.pci.bar[1] = 0; - a->resources.pci.addr[1] = 0; + a->resources.pci.addr[1] = NULL; } if (a->slave_list) { diva_os_free(0, a->slave_list); - a->slave_list = 0; + a->slave_list = NULL; } return (0); @@ -607,14 +607,14 @@ static int diva_4bri_cleanup_slave_adapt diva_os_remove_soft_isr(&diva_current->xdi_adapter. req_soft_isr); - diva_current->xdi_adapter.isr_soft_isr.object = 0; + diva_current->xdi_adapter.isr_soft_isr.object = NULL; if (diva_current->xdi_adapter.e_tbl) { diva_os_free(0, diva_current->xdi_adapter. e_tbl); } - diva_current->xdi_adapter.e_tbl = 0; + diva_current->xdi_adapter.e_tbl = NULL; diva_current->xdi_adapter.e_max = 0; diva_current->xdi_adapter.e_count = 0; } @@ -823,7 +823,7 @@ void *xdiLoadFile(char *FileName, unsign if (FileLength) { *FileLength = diva_xdiLoadFileLength; } - diva_xdiLoadFileFile = 0; + diva_xdiLoadFileFile = NULL; diva_xdiLoadFileLength = 0; return (ret); @@ -848,7 +848,7 @@ diva_4bri_write_fpga_image(diva_os_xdi_a ret = qBri_FPGA_download(&a->xdi_adapter); - diva_xdiLoadFileFile = 0; + diva_xdiLoadFileFile = NULL; diva_xdiLoadFileLength = 0; return (ret ? 0 : -1); @@ -1116,7 +1116,7 @@ static int diva_4bri_stop_adapter(diva_o if (a->clear_interrupts_proc) { diva_4bri_clear_interrupts(a); - a->clear_interrupts_proc = 0; + a->clear_interrupts_proc = NULL; DBG_ERR(("A: A(%d) no final interrupt from 4BRI adapter", IoAdapter->ANum)) } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/os_bri.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/os_bri.c 2004-07-13 17:09:13.000000000 -0700 @@ -282,7 +282,7 @@ static int diva_bri_cleanup_adapter(diva if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) { divasa_unmap_pci_bar(a->resources.pci.addr[0]); - a->resources.pci.addr[0] = 0; + a->resources.pci.addr[0] = NULL; a->resources.pci.bar[0] = 0; } @@ -293,7 +293,7 @@ static int diva_bri_cleanup_adapter(diva a->resources.pci. length[i], &a->port_name[0], i); - a->resources.pci.addr[i] = 0; + a->resources.pci.addr[i] = NULL; a->resources.pci.bar[i] = 0; } } @@ -305,7 +305,7 @@ static int diva_bri_cleanup_adapter(diva diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr); diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr); - a->xdi_adapter.isr_soft_isr.object = 0; + a->xdi_adapter.isr_soft_isr.object = NULL; diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm"); diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm"); @@ -315,7 +315,7 @@ static int diva_bri_cleanup_adapter(diva */ if (a->xdi_adapter.e_tbl) { diva_os_free(0, a->xdi_adapter.e_tbl); - a->xdi_adapter.e_tbl = 0; + a->xdi_adapter.e_tbl = NULL; } return (0); @@ -367,7 +367,7 @@ static int diva_bri_reregister_io(diva_o diva_os_register_io_port(a, 0, a->resources.pci.bar[i], a->resources.pci.length[i], &a->port_name[0], i); - a->resources.pci.addr[i] = 0; + a->resources.pci.addr[i] = NULL; } sprintf(a->port_name, "DIVA BRI %ld", @@ -797,7 +797,7 @@ static int diva_bri_stop_adapter(diva_os } while (i-- && a->clear_interrupts_proc); if (a->clear_interrupts_proc) { diva_bri_clear_interrupts(a); - a->clear_interrupts_proc = 0; + a->clear_interrupts_proc = NULL; DBG_ERR(("A: A(%d) no final interrupt from BRI adapter", IoAdapter->ANum)) } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/os_pri.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/os_pri.c 2004-07-13 17:09:13.000000000 -0700 @@ -283,7 +283,7 @@ static int diva_pri_cleanup_adapter(diva && a->resources.pci.addr[bar]) { divasa_unmap_pci_bar(a->resources.pci.addr[bar]); a->resources.pci.bar[bar] = 0; - a->resources.pci.addr[bar] = 0; + a->resources.pci.addr[bar] = NULL; } } @@ -294,7 +294,7 @@ static int diva_pri_cleanup_adapter(diva diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr); diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr); - a->xdi_adapter.isr_soft_isr.object = 0; + a->xdi_adapter.isr_soft_isr.object = NULL; diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm"); diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm"); @@ -304,7 +304,7 @@ static int diva_pri_cleanup_adapter(diva */ if (a->xdi_adapter.e_tbl) { diva_os_free(0, a->xdi_adapter.e_tbl); - a->xdi_adapter.e_tbl = 0; + a->xdi_adapter.e_tbl = NULL; } a->xdi_adapter.Channels = 0; a->xdi_adapter.e_max = 0; @@ -316,7 +316,7 @@ static int diva_pri_cleanup_adapter(diva diva_free_dma_map(a->resources.pci.hdev, (struct _diva_dma_map_entry *) a->xdi_adapter. dma_map); - a->xdi_adapter.dma_map = 0; + a->xdi_adapter.dma_map = NULL; /* @@ -576,7 +576,7 @@ static int diva_pri_stop_adapter(diva_os if (a->clear_interrupts_proc) { diva_pri_clear_interrupts(a); - a->clear_interrupts_proc = 0; + a->clear_interrupts_proc = NULL; DBG_ERR(("A: A(%d) no final interrupt from PRI adapter", IoAdapter->ANum)) } --- linux-2.6.8-rc1/drivers/isdn/hardware/eicon/um_idi.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/isdn/hardware/eicon/um_idi.c 2004-07-13 17:09:13.000000000 -0700 @@ -188,9 +188,9 @@ static void cleanup_adapter(diva_um_idi_ ------------------------------------------------------------------------ */ static void cleanup_entity(divas_um_idi_entity_t * e) { - e->os_ref = 0; + e->os_ref = NULL; e->status = 0; - e->adapter = 0; + e->adapter = NULL; e->e.Id = 0; e->rc_count = 0; @@ -218,20 +218,20 @@ void *divas_um_idi_create_entity(dword a diva_os_malloc(0, diva_os_get_context_size()))) { DBG_LOG(("E(%08x) no memory for os context", e)); diva_os_free(0, e); - return (0); + return NULL; } memset(e->os_context, 0x00, diva_os_get_context_size()); if ((diva_data_q_init(&e->data, 2048 + 512, 16))) { diva_os_free(0, e->os_context); diva_os_free(0, e); - return (0); + return NULL; } if ((diva_data_q_init(&e->rc, sizeof(diva_um_idi_ind_hdr_t), 2))) { diva_data_q_finit(&e->data); diva_os_free(0, e->os_context); diva_os_free(0, e); - return (0); + return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_entity"); @@ -250,7 +250,7 @@ void *divas_um_idi_create_entity(dword a diva_os_free(0, e->os_context); diva_os_free(0, e); - return (0); + return NULL; } e->os_ref = file; /* link to os handle */ @@ -608,9 +608,9 @@ static int process_idi_request(divas_um_ e->e.IndCh = 0; e->e.XNum = 0; e->e.RNum = 0; - e->e.callback = 0; - e->e.X = 0; - e->e.R = 0; + e->e.callback = NULL; + e->e.X = NULL; + e->e.R = NULL; write_return_code(e, ASSIGN_RC | OUT_OF_RESOURCES); return (-2); } else { @@ -631,7 +631,7 @@ static int process_idi_rc(divas_um_idi_e if (rc != ASSIGN_OK) { DBG_ERR(("A: A(%d) E(%08x) ASSIGN failed", e->adapter->adapter_nr, e)); - e->e.callback = 0; + e->e.callback = NULL; e->e.Id = 0; e->e.Req = 0; e->e.ReqCh = 0; @@ -639,8 +639,8 @@ static int process_idi_rc(divas_um_idi_e e->e.RcCh = 0; e->e.Ind = 0; e->e.IndCh = 0; - e->e.X = 0; - e->e.R = 0; + e->e.X = NULL; + e->e.R = NULL; e->e.XNum = 0; e->e.RNum = 0; } @@ -651,7 +651,7 @@ static int process_idi_rc(divas_um_idi_e return (0); /* let us do it in the driver */ } if ((e->e.Req == REMOVE) && (!e->e.Id)) { /* REMOVE COMPLETE */ - e->e.callback = 0; + e->e.callback = NULL; e->e.Id = 0; e->e.Req = 0; e->e.ReqCh = 0; @@ -659,8 +659,8 @@ static int process_idi_rc(divas_um_idi_e e->e.RcCh = 0; e->e.Ind = 0; e->e.IndCh = 0; - e->e.X = 0; - e->e.R = 0; + e->e.X = NULL; + e->e.R = NULL; e->e.XNum = 0; e->e.RNum = 0; e->rc_count = 0; --- linux-2.6.8-rc1/drivers/isdn/hisax/avm_pci.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/hisax/avm_pci.c 2004-07-13 17:09:50.000000000 -0700 @@ -750,70 +750,70 @@ setup_avm_pcipnp(struct IsdnCard *card) cs->hw.avm.cfg_reg = card->para[1]; cs->irq = card->para[0]; cs->subtyp = AVM_FRITZ_PNP; - } else { + goto ready; + } #ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_avm_d = NULL; - if ((pnp_avm_c = pnp_find_card( + if (isapnp_present()) { + struct pnp_dev *pnp_avm_d = NULL; + if ((pnp_avm_c = pnp_find_card( + ISAPNP_VENDOR('A', 'V', 'M'), + ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { + if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; + ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { + int err; - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err<0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __FUNCTION__, err); - return(0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (!cs->irq) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return(0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PNP; - goto ready; + pnp_disable_dev(pnp_avm_d); + err = pnp_activate_dev(pnp_avm_d); + if (err<0) { + printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", + __FUNCTION__, err); + return(0); + } + cs->hw.avm.cfg_reg = + pnp_port_start(pnp_avm_d, 0); + cs->irq = pnp_irq(pnp_avm_d, 0); + if (!cs->irq) { + printk(KERN_ERR "FritzPnP:No IRQ\n"); + return(0); + } + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPnP:No IO address\n"); + return(0); } + cs->subtyp = AVM_FRITZ_PNP; + goto ready; } - } else { - printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); } + } else { + printk(KERN_INFO "FritzPnP: no ISA PnP present\n"); + } #endif #if CONFIG_PCI - if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return(0); - } - if (pci_enable_device(dev_avm)) - return(0); - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return(0); - } - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, + PCI_DEVICE_ID_AVM_A1, dev_avm))) { + cs->irq = dev_avm->irq; + if (!cs->irq) { + printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); return(0); } - cs->irq_flags |= SA_SHIRQ; + if (pci_enable_device(dev_avm)) + return(0); + cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); + if (!cs->hw.avm.cfg_reg) { + printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); + return(0); + } + cs->subtyp = AVM_FRITZ_PCI; + } else { + printk(KERN_WARNING "FritzPCI: No PCI card found\n"); + return(0); + } + cs->irq_flags |= SA_SHIRQ; #else - printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); - return (0); + printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n"); + return (0); #endif /* CONFIG_PCI */ - } ready: cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; if (!request_region(cs->hw.avm.cfg_reg, 32, --- linux-2.6.8-rc1/drivers/isdn/hisax/config.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/hisax/config.c 2004-07-13 17:09:13.000000000 -0700 @@ -618,10 +618,10 @@ struct IsdnCardState *hisax_get_card(int return NULL; } -int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) +int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) { int count, cnt; - u_char *p = buf; + u_char __user *p = buf; struct IsdnCardState *cs = hisax_findcard(id); if (cs) { @@ -633,10 +633,7 @@ int HiSax_readstatus(u_char * buf, int l count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; - if (user) - copy_to_user(p, cs->status_read, count); - else - memcpy(p, cs->status_read, count); + copy_to_user(p, cs->status_read, count); cs->status_read += count; if (cs->status_read > cs->status_end) cs->status_read = cs->status_buf; @@ -647,10 +644,7 @@ int HiSax_readstatus(u_char * buf, int l cnt = HISAX_STATUS_BUFSIZE; else cnt = count; - if (user) - copy_to_user(p, cs->status_read, cnt); - else - memcpy(p, cs->status_read, cnt); + copy_to_user(p, cs->status_read, cnt); p += cnt; cs->status_read += cnt % HISAX_STATUS_BUFSIZE; count -= cnt; @@ -1586,7 +1580,7 @@ int hisax_register(struct hisax_d_if *hi cards[i].protocol = protocol; sprintf(id, "%s%d", name, i); nrcards++; - retval = checkcard(i, id, 0, hisax_d_if->owner); + retval = checkcard(i, id, NULL, hisax_d_if->owner); if (retval == 0) { // yuck cards[i].typ = 0; nrcards--; --- linux-2.6.8-rc1/drivers/isdn/hisax/diva.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/hisax/diva.c 2004-07-13 17:09:13.000000000 -0700 @@ -1158,7 +1158,7 @@ ready: cs->writeisacfifo = &MemWriteISACfifo_IPACX; cs->BC_Read_Reg = &MemReadHSCX_IPACX; cs->BC_Write_Reg = &MemWriteHSCX_IPACX; - cs->BC_Send_Data = 0; // function located in ipacx module + cs->BC_Send_Data = NULL; // function located in ipacx module cs->irq_func = &diva_irq_ipacx_pci; printk(KERN_INFO "Diva: IPACX Design Id: %x\n", MemReadISAC_IPACX(cs, IPACX_ID) &0x3F); --- linux-2.6.8-rc1/drivers/isdn/hisax/elsa_ser.c 2004-03-10 20:41:27.000000000 -0800 +++ 25/drivers/isdn/hisax/elsa_ser.c 2004-07-13 17:09:13.000000000 -0700 @@ -401,7 +401,7 @@ static void rs_interrupt_elsa(int irq, s if (status & UART_LSR_DR) receive_chars(cs, &status); if (status & UART_LSR_THRE) - transmit_chars(cs, 0); + transmit_chars(cs, NULL); if (pass_counter++ > RS_ISR_PASS_LIMIT) { printk("rs_single loop break.\n"); break; --- linux-2.6.8-rc1/drivers/isdn/hisax/hfc_usb.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/hisax/hfc_usb.c 2004-07-13 17:09:13.000000000 -0700 @@ -133,7 +133,7 @@ static const char *hfcusb_revision = "4. /**********/ /* macros */ /**********/ -#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT) +#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT) #define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT) /*************************************************/ @@ -353,7 +353,7 @@ vendor_data vdata[]= {0x8e3, 0x0301, "Olitec USB RNIS", LED_SCHEME1, LED_NORMAL, {2,0,1,4}}, /* Olitec TA */ {0x675, 0x1688, "DrayTec USB ISDN TA", LED_SCHEME1, LED_NORMAL, {4,0,2,1}}, /* Draytec TA */ {0x7fa, 0x0846, "Bewan Modem RNIS USB", LED_SCHEME1, LED_INVERTED, {8,0x40,0x20,0x10}}, /* Bewan TA */ - {0,0,0} // EOL element + {0} // EOL element }; /***************************************************/ --- linux-2.6.8-rc1/drivers/isdn/hisax/isar.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/hisax/isar.c 2004-07-13 17:09:13.000000000 -0700 @@ -186,12 +186,12 @@ ISARVersion(struct IsdnCardState *cs, ch } int -isar_load_firmware(struct IsdnCardState *cs, u_char *buf) +isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf) { int ret, size, cnt, debug; u_char len, nom, noc; u_short sadr, left, *sp; - u_char *p = buf; + u_char __user *p = buf; u_char *msg, *tmpmsg, *mp, tmp[64]; u_long flags; struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; @@ -1856,7 +1856,7 @@ isar_auxcmd(struct IsdnCardState *cs, is ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_FCLASS1; memcpy(&adr, ic->parm.num, sizeof(ulong)); - if (isar_load_firmware(cs, (u_char *)adr)) + if (isar_load_firmware(cs, (u_char __user *)adr)) return(1); else ll_run(cs, features); --- linux-2.6.8-rc1/drivers/isdn/hisax/st5481_usb.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/isdn/hisax/st5481_usb.c 2004-07-13 17:09:24.000000000 -0700 @@ -143,9 +143,6 @@ static void usb_ctrl_complete(struct urb if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.wIndex & ~USB_DIR_IN, - (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, --- linux-2.6.8-rc1/drivers/isdn/hisax/tei.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/hisax/tei.c 2004-07-13 17:09:13.000000000 -0700 @@ -239,7 +239,7 @@ tei_id_remove(struct FsmInst *fi, int ev if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { FsmDelTimer(&st->ma.t202, 5); FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); cs = (struct IsdnCardState *) st->l1.hardware; cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); } @@ -275,7 +275,7 @@ tei_id_req_tout(struct FsmInst *fi, int FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); } else { st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); - st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0); + st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL); cs = (struct IsdnCardState *) st->l1.hardware; cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); @@ -298,7 +298,7 @@ tei_id_ver_tout(struct FsmInst *fi, int } else { st->ma.tei_m.printdebug(&st->ma.tei_m, "verify req for tei %d failed", st->l2.tei); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0); + st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); cs = (struct IsdnCardState *) st->l1.hardware; cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); FsmChangeState(fi, ST_TEI_NOP); --- linux-2.6.8-rc1/drivers/isdn/i4l/isdn_common.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/isdn/i4l/isdn_common.c 2004-07-13 17:09:13.000000000 -0700 @@ -959,7 +959,7 @@ isdn_read(struct file *file, char __user interruptible_sleep_on(&(dev->info_waitq)); } p = isdn_statstr(); - file->private_data = 0; + file->private_data = NULL; if ((len = strlen(p)) <= count) { if (copy_to_user(buf, p, len)) { retval = -EFAULT; @@ -992,7 +992,7 @@ isdn_read(struct file *file, char __user retval = -ENOMEM; goto out; } - len = isdn_readbchan(drvidx, chidx, p, 0, count, + len = isdn_readbchan(drvidx, chidx, p, NULL, count, &dev->drv[drvidx]->rcv_waitq[chidx]); *off += len; if (copy_to_user(buf,p,len)) @@ -1018,7 +1018,7 @@ isdn_read(struct file *file, char __user if (count > dev->drv[drvidx]->stavail) count = dev->drv[drvidx]->stavail; len = dev->drv[drvidx]->interface-> - readstat(buf, count, 1, drvidx, + readstat(buf, count, drvidx, isdn_minor2chan(minor)); } else { len = 0; @@ -1091,7 +1091,7 @@ isdn_write(struct file *file, const char */ if (dev->drv[drvidx]->interface->writecmd) retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); + writecmd(buf, count, drvidx, isdn_minor2chan(minor)); else retval = count; goto out; --- linux-2.6.8-rc1/drivers/isdn/i4l/isdn_net.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/isdn/i4l/isdn_net.c 2004-07-13 17:09:13.000000000 -0700 @@ -396,8 +396,8 @@ isdn_net_stat_callback(int idx, isdn_ctr if (p) { isdn_net_local *lp = p->local; #ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp -> netdev -> cprot; - struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; + struct concap_proto *cprot = lp->netdev->cprot; + struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; #endif switch (cmd) { case ISDN_STAT_BSENT: @@ -617,7 +617,7 @@ isdn_net_dial(void) s = "dial suppressed: isdn system stopped"; else s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(&p->dev, 0, s); + isdn_net_unreachable(&p->dev, NULL, s); isdn_net_hangup(&p->dev); break; } @@ -645,7 +645,7 @@ isdn_net_dial(void) if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, 0, "dial: timed out"); + isdn_net_unreachable(&p->dev, NULL, "dial: timed out"); isdn_net_hangup(&p->dev); break; } @@ -675,7 +675,7 @@ isdn_net_dial(void) if (lp->dialtimeout == 0) { lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; - isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times"); + isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times"); } isdn_net_hangup(&p->dev); break; @@ -827,8 +827,8 @@ isdn_net_hangup(struct net_device *d) isdn_net_local *lp = (isdn_net_local *) d->priv; isdn_ctrl cmd; #ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp -> netdev -> cprot; - struct concap_proto_ops *pops = cprot ? cprot -> pops : 0; + struct concap_proto *cprot = lp->netdev->cprot; + struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; #endif if (lp->flags & ISDN_NET_CONNECTED) { @@ -1416,11 +1416,10 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_l struct sk_buff *skb; skb = alloc_skb(hl + len, GFP_ATOMIC); - if (!skb) { + if (skb) + skb_reserve(skb, hl); + else printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); - return 0; - } - skb_reserve(skb, hl); return skb; } @@ -2182,7 +2181,7 @@ isdn_net_find_icall(int di, int ch, int *my_eaz == 'b' || *my_eaz == 'B') my_eaz++; /* skip to allow a match */ else - my_eaz = 0; /* force non match */ + my_eaz = NULL; /* force non match */ } else { /* it's a DATA call, check if we allow it */ if (*my_eaz == 'b' || *my_eaz == 'B') my_eaz++; /* skip to allow a match */ --- linux-2.6.8-rc1/drivers/isdn/i4l/isdn_tty.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/isdn/i4l/isdn_tty.c 2004-07-13 17:09:13.000000000 -0700 @@ -134,7 +134,7 @@ isdn_tty_readmodem(void) if (c > 0) { r = isdn_readbchan(info->isdn_driver, info->isdn_channel, tty->flip.char_buf_ptr, - tty->flip.flag_buf_ptr, c, 0); + tty->flip.flag_buf_ptr, c, NULL); /* CISCO AsyncPPP Hack */ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) memset(tty->flip.flag_buf_ptr, 0, r); @@ -1483,7 +1483,7 @@ isdn_tty_ioctl(struct tty_struct *tty, s #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); #endif - return isdn_tty_get_lsr_info(info, (uint *) arg); + return isdn_tty_get_lsr_info(info, (uint __user *) arg); default: #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); @@ -1751,7 +1751,7 @@ isdn_tty_close(struct tty_struct *tty, s tty->driver->flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - info->tty = 0; + info->tty = NULL; info->ncarrier = 0; tty->closing = 0; module_put(info->owner); @@ -1780,7 +1780,7 @@ isdn_tty_hangup(struct tty_struct *tty) isdn_tty_shutdown(info); info->count = 0; info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE); - info->tty = 0; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1959,7 +1959,7 @@ isdn_tty_modem_init(void) isdn_tty_modem_reset_regs(info, 1); info->magic = ISDN_ASYNC_MAGIC; info->line = i; - info->tty = 0; + info->tty = NULL; info->x_char = 0; info->count = 0; info->blocked_open = 0; @@ -2373,8 +2373,8 @@ isdn_tty_at_cout(char *msg, modem_info * char *p; char c; u_long flags; - struct sk_buff *skb = 0; - char *sp = 0; + struct sk_buff *skb = NULL; + char *sp = NULL; if (!msg) { printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); --- linux-2.6.8-rc1/drivers/isdn/icn/icn.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/icn/icn.c 2004-07-13 17:09:13.000000000 -0700 @@ -798,7 +798,7 @@ int slsec = sec; \ #endif static int -icn_loadboot(u_char * buffer, icn_card * card) +icn_loadboot(u_char __user * buffer, icn_card * card) { int ret; u_char *codebuf; @@ -903,9 +903,9 @@ icn_loadboot(u_char * buffer, icn_card * } static int -icn_loadproto(u_char * buffer, icn_card * card) +icn_loadproto(u_char __user * buffer, icn_card * card) { - register u_char *p = buffer; + register u_char __user *p = buffer; u_char codebuf[256]; uint left = ICN_CODE_STAGE2; uint cnt; @@ -916,7 +916,7 @@ icn_loadproto(u_char * buffer, icn_card #ifdef BOOT_DEBUG printk(KERN_DEBUG "icn_loadproto called\n"); #endif - if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2))) + if ((ret = verify_area(VERIFY_READ, buffer, ICN_CODE_STAGE2))) return ret; timer = 0; spin_lock_irqsave(&dev.devlock, flags); @@ -1007,18 +1007,15 @@ icn_loadproto(u_char * buffer, icn_card /* Read the Status-replies from the Interface */ static int -icn_readstatus(u_char * buf, int len, int user, icn_card * card) +icn_readstatus(u_char __user *buf, int len, icn_card * card) { int count; - u_char *p; + u_char __user *p; for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - if (user) - put_user(*card->msg_buf_read++, p); - else - *p = *card->msg_buf_read++; + put_user(*card->msg_buf_read++, p); if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } @@ -1163,10 +1160,12 @@ icn_command(isdn_ctrl * c, icn_card * ca char cbuf[60]; isdn_ctrl cmd; icn_cdef cdef; + char __user *arg; switch (c->command) { case ISDN_CMD_IOCTL: memcpy(&a, c->parm.num, sizeof(ulong)); + arg = (char __user *)a; switch (c->arg) { case ICN_IOCTL_SETMMIO: if (dev.memaddr != (a & 0x0ffc000)) { @@ -1230,15 +1229,15 @@ icn_command(isdn_ctrl * c, icn_card * ca case ICN_IOCTL_GETDOUBLE: return (int) card->doubleS0; case ICN_IOCTL_DEBUGVAR: - if (copy_to_user((char *)a, - (char *)&card, + if (copy_to_user(arg, + &card, sizeof(ulong))) return -EFAULT; a += sizeof(ulong); { ulong l = (ulong) & dev; - if (copy_to_user((char *)a, - (char *)&l, + if (copy_to_user(arg, + &l, sizeof(ulong))) return -EFAULT; } @@ -1249,20 +1248,20 @@ icn_command(isdn_ctrl * c, icn_card * ca dev.firstload = 0; } icn_stopcard(card); - return (icn_loadboot((u_char *) a, card)); + return (icn_loadboot(arg, card)); case ICN_IOCTL_LOADPROTO: icn_stopcard(card); - if ((i = (icn_loadproto((u_char *) a, card)))) + if ((i = (icn_loadproto(arg, card)))) return i; if (card->doubleS0) - i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other); + i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other); return i; break; case ICN_IOCTL_ADDCARD: if (!dev.firstload) return -EBUSY; - if (copy_from_user((char *)&cdef, - (char *)a, + if (copy_from_user(&cdef, + arg, sizeof(cdef))) return -EFAULT; return (icn_addcard(cdef.port, cdef.id1, cdef.id2)); @@ -1470,14 +1469,14 @@ if_command(isdn_ctrl * c) } static int -if_writecmd(const u_char * buf, int len, int user, int id, int channel) +if_writecmd(const u_char __user *buf, int len, int id, int channel) { icn_card *card = icn_findcard(id); if (card) { if (!card->flags & ICN_FLAGS_RUNNING) return -ENODEV; - return (icn_writecmd(buf, len, user, card)); + return (icn_writecmd(buf, len, 1, card)); } printk(KERN_ERR "icn: if_writecmd called with invalid driverId!\n"); @@ -1485,14 +1484,14 @@ if_writecmd(const u_char * buf, int len, } static int -if_readstatus(u_char * buf, int len, int user, int id, int channel) +if_readstatus(u_char __user *buf, int len, int id, int channel) { icn_card *card = icn_findcard(id); if (card) { if (!card->flags & ICN_FLAGS_RUNNING) return -ENODEV; - return (icn_readstatus(buf, len, user, card)); + return (icn_readstatus(buf, len, card)); } printk(KERN_ERR "icn: if_readstatus called with invalid driverId!\n"); --- linux-2.6.8-rc1/drivers/isdn/isdnloop/isdnloop.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/isdnloop/isdnloop.c 2004-07-13 17:09:13.000000000 -0700 @@ -443,18 +443,15 @@ isdnloop_sendbuf(int channel, struct sk_ * number of bytes actually transferred. */ static int -isdnloop_readstatus(u_char * buf, int len, int user, isdnloop_card * card) +isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card) { int count; - u_char *p; + u_char __user *p; for (p = buf, count = 0; count < len; p++, count++) { if (card->msg_buf_read == card->msg_buf_write) return count; - if (user) - put_user(*card->msg_buf_read++, p); - else - *p = *card->msg_buf_read++; + put_user(*card->msg_buf_read++, p); if (card->msg_buf_read > card->msg_buf_end) card->msg_buf_read = card->msg_buf; } @@ -1388,14 +1385,14 @@ if_command(isdn_ctrl * c) } static int -if_writecmd(const u_char * buf, int len, int user, int id, int channel) +if_writecmd(const u_char __user *buf, int len, int id, int channel) { isdnloop_card *card = isdnloop_findcard(id); if (card) { if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; - return (isdnloop_writecmd(buf, len, user, card)); + return (isdnloop_writecmd(buf, len, 1, card)); } printk(KERN_ERR "isdnloop: if_writecmd called with invalid driverId!\n"); @@ -1403,14 +1400,14 @@ if_writecmd(const u_char * buf, int len, } static int -if_readstatus(u_char * buf, int len, int user, int id, int channel) +if_readstatus(u_char __user *buf, int len, int id, int channel) { isdnloop_card *card = isdnloop_findcard(id); if (card) { if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; - return (isdnloop_readstatus(buf, len, user, card)); + return (isdnloop_readstatus(buf, len, card)); } printk(KERN_ERR "isdnloop: if_readstatus called with invalid driverId!\n"); --- linux-2.6.8-rc1/drivers/isdn/pcbit/drv.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/pcbit/drv.c 2004-07-13 17:09:13.000000000 -0700 @@ -57,9 +57,9 @@ static char* pcbit_devname[MAX_PCBIT_CAR */ int pcbit_command(isdn_ctrl* ctl); -int pcbit_stat(u_char* buf, int len, int user, int, int); +int pcbit_stat(u_char __user * buf, int len, int, int); int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb); -int pcbit_writecmd(const u_char*, int, int, int, int); +int pcbit_writecmd(const u_char __user *, int, int, int); static int set_protocol_running(struct pcbit_dev * dev); @@ -389,12 +389,13 @@ int pcbit_xmit(int driver, int chnum, in return len; } -int pcbit_writecmd(const u_char* buf, int len, int user, int driver, int channel) +int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel) { struct pcbit_dev * dev; int i, j; const u_char * loadbuf; u_char * ptr = NULL; + u_char *cbuf; int errstat; @@ -415,37 +416,28 @@ int pcbit_writecmd(const u_char* buf, in return -EINVAL; } - if (user) - { - u_char *cbuf = kmalloc(len, GFP_KERNEL); - if (!cbuf) - return -ENOMEM; - - if (copy_from_user(cbuf, buf, len)) { - kfree(cbuf); - return -EFAULT; - } - memcpy_toio(dev->sh_mem, cbuf, len); + cbuf = kmalloc(len, GFP_KERNEL); + if (!cbuf) + return -ENOMEM; + + if (copy_from_user(cbuf, buf, len)) { kfree(cbuf); + return -EFAULT; } - else - memcpy_toio(dev->sh_mem, buf, len); + memcpy_toio(dev->sh_mem, cbuf, len); + kfree(cbuf); return len; case L2_FWMODE: /* this is the hard part */ /* dumb board */ - if (user) { - /* get it into kernel space */ - if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) - return -ENOMEM; - if (copy_from_user(ptr, buf, len)) { - kfree(ptr); - return -EFAULT; - } - loadbuf = ptr; + /* get it into kernel space */ + if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) + return -ENOMEM; + if (copy_from_user(ptr, buf, len)) { + kfree(ptr); + return -EFAULT; } - else - loadbuf = buf; + loadbuf = ptr; errstat = 0; @@ -468,9 +460,7 @@ int pcbit_writecmd(const u_char* buf, in if (dev->loadptr > LOAD_ZONE_END) dev->loadptr = LOAD_ZONE_START; } - - if (user) - kfree(ptr); + kfree(ptr); return errstat ? errstat : len; default: @@ -723,17 +713,7 @@ static char statbuf[STATBUF_LEN]; static int stat_st = 0; static int stat_end = 0; - -static __inline void -memcpy_to_COND(int flag, char *d, const char *s, int len) { - if (flag) - copy_to_user(d, s, len); - else - memcpy(d, s, len); -} - - -int pcbit_stat(u_char* buf, int len, int user, int driver, int channel) +int pcbit_stat(u_char __user *buf, int len, int driver, int channel) { int stat_count; stat_count = stat_end - stat_st; @@ -747,24 +727,23 @@ int pcbit_stat(u_char* buf, int len, int if (stat_st < stat_end) { - memcpy_to_COND(user, buf, statbuf + stat_st, len); + copy_to_user(buf, statbuf + stat_st, len); stat_st += len; } else { if (len > STATBUF_LEN - stat_st) { - memcpy_to_COND(user, buf, statbuf + stat_st, + copy_to_user(buf, statbuf + stat_st, STATBUF_LEN - stat_st); - memcpy_to_COND(user, buf, statbuf, + copy_to_user(buf, statbuf, len - (STATBUF_LEN - stat_st)); stat_st = len - (STATBUF_LEN - stat_st); } else { - memcpy_to_COND(user, buf, statbuf + stat_st, - len); + copy_to_user(buf, statbuf + stat_st, len); stat_st += len; --- linux-2.6.8-rc1/drivers/isdn/pcbit/module.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/isdn/pcbit/module.c 2004-07-13 17:09:13.000000000 -0700 @@ -25,11 +25,11 @@ MODULE_LICENSE("GPL"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); -static int mem[MAX_PCBIT_CARDS] = {0, }; -static int irq[MAX_PCBIT_CARDS] = {0, }; +static int mem[MAX_PCBIT_CARDS]; +static int irq[MAX_PCBIT_CARDS]; static int num_boards; -struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, }; +struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; extern void pcbit_terminate(int board); extern int pcbit_init_dev(int board, int mem_base, int irq); --- linux-2.6.8-rc1/drivers/isdn/sc/command.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/sc/command.c 2004-07-13 17:09:13.000000000 -0700 @@ -117,7 +117,7 @@ int command(isdn_ctrl *cmd) scs_ioctl ioc; memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long)); - if (copy_from_user(&ioc, (scs_ioctl *)cmdptr, + if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr, sizeof(scs_ioctl))) { pr_debug("%s: Failed to verify user space 0x%x\n", sc_adapter[card]->devicename, cmdptr); @@ -215,7 +215,7 @@ int startproc(int card) status = sendmessage(card, CMPID,cmReqType2, cmReqClass0, cmReqStartProc, - 0,0,0); + 0,0,NULL); pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename); return status; --- linux-2.6.8-rc1/drivers/isdn/sc/hardware.h 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/isdn/sc/hardware.h 2004-07-13 17:09:13.000000000 -0700 @@ -105,7 +105,7 @@ */ /* Return the number of jiffies in a given number of msecs */ -#define milliseconds(x) (x/(1000/HZ)) +#define milliseconds(x) (((x)*HZ)/1000) /* Determine if a channel number is valid for the adapter */ #define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= sc_adapter[y]->channels)) --- linux-2.6.8-rc1/drivers/isdn/sc/ioctl.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/isdn/sc/ioctl.c 2004-07-13 17:09:13.000000000 -0700 @@ -72,7 +72,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Get the SRec from user space */ - if (copy_from_user(srec, (char *) data->dataptr, sizeof(srec))) { + if (copy_from_user(srec, data->dataptr, sizeof(srec))) { kfree(rcvmsg); kfree(srec); return -EFAULT; @@ -118,8 +118,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Get the switch type from user space */ - if (copy_from_user(&switchtype, (char *)data->dataptr, - sizeof(char))) { + if (copy_from_user(&switchtype, data->dataptr, sizeof(char))) { kfree(rcvmsg); return -EFAULT; } @@ -152,7 +151,7 @@ int sc_ioctl(int card, scs_ioctl *data) * Get the switch type from the board */ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, - ceReqCallGetSwitchType, 0, 0, 0, rcvmsg, SAR_TIMEOUT); + ceReqCallGetSwitchType, 0, 0, NULL, rcvmsg, SAR_TIMEOUT); if (!status && !(rcvmsg->rsp_status)) { pr_debug("%s: SCIOCGETSWITCH: command successful\n", sc_adapter[card]->devicename); @@ -169,7 +168,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Package the switch type and send to user space */ - if (copy_to_user((char *)data->dataptr, &switchtype, + if (copy_to_user(data->dataptr, &switchtype, sizeof(char))) { kfree(rcvmsg); return -EFAULT; @@ -193,7 +192,7 @@ int sc_ioctl(int card, scs_ioctl *data) * Get the spid from the board */ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID, - data->channel, 0, 0, rcvmsg, SAR_TIMEOUT); + data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); if (!status) { pr_debug("%s: SCIOCGETSPID: command successful\n", sc_adapter[card]->devicename); @@ -209,7 +208,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Package the switch type and send to user space */ - if (copy_to_user((char *)data->dataptr, spid, SCIOC_SPIDSIZE)) { + if (copy_to_user(data->dataptr, spid, SCIOC_SPIDSIZE)) { kfree(spid); kfree(rcvmsg); return -EFAULT; @@ -234,7 +233,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Get the spid from user space */ - if (copy_from_user(spid, (char *) data->dataptr, SCIOC_SPIDSIZE)) { + if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) { kfree(rcvmsg); return -EFAULT; } @@ -269,7 +268,7 @@ int sc_ioctl(int card, scs_ioctl *data) * Get the dn from the board */ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber, - data->channel, 0, 0, rcvmsg, SAR_TIMEOUT); + data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); if (!status) { pr_debug("%s: SCIOCGETDN: command successful\n", sc_adapter[card]->devicename); @@ -292,7 +291,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Package the dn and send to user space */ - if (copy_to_user((char *)data->dataptr, dn, SCIOC_DNSIZE)) { + if (copy_to_user(data->dataptr, dn, SCIOC_DNSIZE)) { kfree(dn); return -EFAULT; } @@ -313,7 +312,7 @@ int sc_ioctl(int card, scs_ioctl *data) /* * Get the spid from user space */ - if (copy_from_user(dn, (char *)data->dataptr, SCIOC_DNSIZE)) { + if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) { kfree(rcvmsg); kfree(dn); return -EFAULT; @@ -366,8 +365,7 @@ int sc_ioctl(int card, scs_ioctl *data) kfree(rcvmsg); GetStatus(card, bi); - if (copy_to_user((boardInfo *)data->dataptr, bi, - sizeof(boardInfo))) { + if (copy_to_user(data->dataptr, bi, sizeof(boardInfo))) { kfree(bi); return -EFAULT; } @@ -385,7 +383,7 @@ int sc_ioctl(int card, scs_ioctl *data) * Get the speed from the board */ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, - ceReqCallGetCallType, data->channel, 0, 0, rcvmsg, SAR_TIMEOUT); + ceReqCallGetCallType, data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); if (!status && !(rcvmsg->rsp_status)) { pr_debug("%s: SCIOCGETSPEED: command successful\n", sc_adapter[card]->devicename); @@ -405,7 +403,7 @@ int sc_ioctl(int card, scs_ioctl *data) * Package the switch type and send to user space */ - if (copy_to_user((char *) data->dataptr, &speed, sizeof(char))) + if (copy_to_user(data->dataptr, &speed, sizeof(char))) return -EFAULT; return 0; --- linux-2.6.8-rc1/drivers/isdn/sc/scioc.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/isdn/sc/scioc.h 2004-07-13 17:09:13.000000000 -0700 @@ -27,7 +27,7 @@ typedef struct { int device; int channel; unsigned long command; - void *dataptr; + void __user *dataptr; } scs_ioctl; /* Size of strings */ --- linux-2.6.8-rc1/drivers/isdn/tpam/tpam_commands.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/drivers/isdn/tpam/tpam_commands.c 2004-07-13 17:09:13.000000000 -0700 @@ -120,7 +120,7 @@ static int tpam_command_ioctl_dspload(tp dprintk("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id); /* get the IOCTL parameter from userspace */ - if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl))) + if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl))) return -EFAULT; /* if the board's firmware was started, protect against writes @@ -131,7 +131,7 @@ static int tpam_command_ioctl_dspload(tp /* write the data in the board's memory */ return copy_from_user_to_pam(card, (void *)tdl.address, - (void *)arg + sizeof(tpam_dsp_ioctl), + (void __user *)arg + sizeof(tpam_dsp_ioctl), tdl.data_len); } @@ -150,7 +150,7 @@ static int tpam_command_ioctl_dspsave(tp dprintk("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id); /* get the IOCTL parameter from userspace */ - if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl))) + if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl))) return -EFAULT; /* protect against read from unallowed memory areas */ @@ -158,7 +158,7 @@ static int tpam_command_ioctl_dspsave(tp return -EPERM; /* read the data from the board's memory */ - return copy_from_pam_to_user(card, (void *)arg + sizeof(tpam_dsp_ioctl), + return copy_from_pam_to_user(card, (void __user *)arg + sizeof(tpam_dsp_ioctl), (void *)tdl.address, tdl.data_len); } --- linux-2.6.8-rc1/drivers/isdn/tpam/tpam.h 2003-06-14 12:17:59.000000000 -0700 +++ 25/drivers/isdn/tpam/tpam.h 2004-07-13 17:09:13.000000000 -0700 @@ -173,8 +173,8 @@ extern void copy_to_pam_dword(tpam_card extern void copy_to_pam(tpam_card *, void *, const void *, u32); extern u32 copy_from_pam_dword(tpam_card *, const void *); extern void copy_from_pam(tpam_card *, void *, const void *, u32); -extern int copy_from_pam_to_user(tpam_card *, void *, const void *, u32); -extern int copy_from_user_to_pam(tpam_card *, void *, const void *, u32); +extern int copy_from_pam_to_user(tpam_card *, void __user *, const void *, u32); +extern int copy_from_user_to_pam(tpam_card *, void *, const void __user *, u32); extern int tpam_verify_area(u32, u32); /* Function prototypes from tpam_nco.c */ --- linux-2.6.8-rc1/drivers/isdn/tpam/tpam_memory.c 2003-06-14 12:18:05.000000000 -0700 +++ 25/drivers/isdn/tpam/tpam_memory.c 2004-07-13 17:09:13.000000000 -0700 @@ -125,7 +125,7 @@ void copy_from_pam(tpam_card *card, void * * Return: 0 if OK, <0 if error. */ -int copy_from_pam_to_user(tpam_card *card, void *to, const void *from, u32 n) { +int copy_from_pam_to_user(tpam_card *card, void __user *to, const void *from, u32 n) { void *page; u32 count; @@ -171,7 +171,7 @@ int copy_from_pam_to_user(tpam_card *car * * Return: 0 if OK, <0 if error. */ -int copy_from_user_to_pam(tpam_card *card, void *to, const void *from, u32 n) { +int copy_from_user_to_pam(tpam_card *card, void *to, const void __user *from, u32 n) { void *page; u32 count; --- linux-2.6.8-rc1/drivers/Makefile 2004-04-03 20:39:11.000000000 -0800 +++ 25/drivers/Makefile 2004-07-13 17:09:33.745142832 -0700 @@ -37,9 +37,9 @@ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ +obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_PHONE) += telephony/ @@ -49,4 +49,5 @@ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_PERFCTR) += perfctr/ obj-y += firmware/ --- linux-2.6.8-rc1/drivers/md/dm.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/md/dm.c 2004-07-13 17:09:43.000000000 -0700 @@ -15,15 +15,13 @@ #include #include #include +#include static const char *_name = DM_NAME; static unsigned int major = 0; static unsigned int _major = 0; -static int realloc_minor_bits(unsigned long requested_minor); -static void free_minor_bits(void); - /* * One of these is allocated per bio. */ @@ -113,19 +111,11 @@ static int __init local_init(void) return -ENOMEM; } - r = realloc_minor_bits(1024); - if (r < 0) { - kmem_cache_destroy(_tio_cache); - kmem_cache_destroy(_io_cache); - return r; - } - _major = major; r = register_blkdev(_major, _name); if (r < 0) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); return r; } @@ -139,7 +129,6 @@ static void local_exit(void) { kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); - free_minor_bits(); if (unregister_blkdev(_major, _name) < 0) DMERR("devfs_unregister_blkdev failed"); @@ -597,6 +586,21 @@ static int dm_request(request_queue_t *q return 0; } +static int dm_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + int ret = -ENXIO; + + if (map) { + ret = dm_table_flush_all(md->map); + dm_table_put(map); + } + + return ret; +} + static void dm_unplug_all(request_queue_t *q) { struct mapped_device *md = q->queuedata; @@ -624,59 +628,15 @@ static int dm_any_congested(void *conges } /*----------------------------------------------------------------- - * A bitset is used to keep track of allocated minor numbers. + * An IDR is used to keep track of allocated minor numbers. *---------------------------------------------------------------*/ static DECLARE_MUTEX(_minor_lock); -static unsigned long *_minor_bits = NULL; -static unsigned long _max_minors = 0; - -#define MINORS_SIZE(minors) ((minors / BITS_PER_LONG) * sizeof(unsigned long)) - -static int realloc_minor_bits(unsigned long requested_minor) -{ - unsigned long max_minors; - unsigned long *minor_bits, *tmp; - - if (requested_minor < _max_minors) - return -EINVAL; - - /* Round up the requested minor to the next power-of-2. */ - max_minors = 1 << fls(requested_minor - 1); - if (max_minors > (1 << MINORBITS)) - return -EINVAL; - - minor_bits = kmalloc(MINORS_SIZE(max_minors), GFP_KERNEL); - if (!minor_bits) - return -ENOMEM; - memset(minor_bits, 0, MINORS_SIZE(max_minors)); - - /* Copy the existing bit-set to the new one. */ - if (_minor_bits) - memcpy(minor_bits, _minor_bits, MINORS_SIZE(_max_minors)); - - tmp = _minor_bits; - _minor_bits = minor_bits; - _max_minors = max_minors; - if (tmp) - kfree(tmp); - - return 0; -} - -static void free_minor_bits(void) -{ - down(&_minor_lock); - kfree(_minor_bits); - _minor_bits = NULL; - _max_minors = 0; - up(&_minor_lock); -} +static DEFINE_IDR(_minor_idr); static void free_minor(unsigned int minor) { down(&_minor_lock); - if (minor < _max_minors) - clear_bit(minor, _minor_bits); + idr_remove(&_minor_idr, minor); up(&_minor_lock); } @@ -685,24 +645,37 @@ static void free_minor(unsigned int mino */ static int specific_minor(unsigned int minor) { - int r = 0; + int r, m; if (minor > (1 << MINORBITS)) return -EINVAL; down(&_minor_lock); - if (minor >= _max_minors) { - r = realloc_minor_bits(minor); - if (r) { - up(&_minor_lock); - return r; - } + + if (idr_find(&_minor_idr, minor)) { + r = -EBUSY; + goto out; + } + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new_above(&_minor_idr, specific_minor, minor, &m); + if (r) { + goto out; } - if (test_and_set_bit(minor, _minor_bits)) + if (m != minor) { + idr_remove(&_minor_idr, m); r = -EBUSY; - up(&_minor_lock); + goto out; + } +out: + up(&_minor_lock); return r; } @@ -712,21 +685,29 @@ static int next_free_minor(unsigned int unsigned int m; down(&_minor_lock); - m = find_first_zero_bit(_minor_bits, _max_minors); - if (m >= _max_minors) { - r = realloc_minor_bits(_max_minors * 2); - if (r) { - up(&_minor_lock); - return r; - } - m = find_first_zero_bit(_minor_bits, _max_minors); + + r = idr_pre_get(&_minor_idr, GFP_KERNEL); + if (!r) { + r = -ENOMEM; + goto out; + } + + r = idr_get_new(&_minor_idr, next_free_minor, &m); + if (r) { + goto out; + } + + if (m > (1 << MINORBITS)) { + idr_remove(&_minor_idr, m); + r = -ENOSPC; + goto out; } - set_bit(m, _minor_bits); *minor = m; - up(&_minor_lock); - return 0; +out: + up(&_minor_lock); + return r; } static struct block_device_operations dm_blk_dops; @@ -764,6 +745,7 @@ static struct mapped_device *alloc_dev(u md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); md->queue->unplug_fn = dm_unplug_all; + md->queue->issue_flush_fn = dm_flush_all; md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab, mempool_free_slab, _io_cache); --- linux-2.6.8-rc1/drivers/md/dm.h 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/md/dm.h 2004-07-13 17:09:31.628464616 -0700 @@ -113,6 +113,7 @@ void dm_table_suspend_targets(struct dm_ void dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); void dm_table_unplug_all(struct dm_table *t); +int dm_table_flush_all(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. --- linux-2.6.8-rc1/drivers/md/dm-table.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/md/dm-table.c 2004-07-13 17:09:31.629464464 -0700 @@ -900,6 +900,28 @@ void dm_table_unplug_all(struct dm_table } } +int dm_table_flush_all(struct dm_table *t) +{ + struct list_head *d, *devices = dm_table_get_devices(t); + int ret = 0; + + for (d = devices->next; d != devices; d = d->next) { + struct dm_dev *dd = list_entry(d, struct dm_dev, list); + request_queue_t *q = bdev_get_queue(dd->bdev); + int err; + + if (!q->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL); + + if (!ret) + ret = err; + } + + return ret; +} + EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); @@ -908,3 +930,4 @@ EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); EXPORT_SYMBOL(dm_table_unplug_all); +EXPORT_SYMBOL(dm_table_flush_all); --- linux-2.6.8-rc1/drivers/md/kcopyd.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/md/kcopyd.c 2004-07-13 17:09:13.363241352 -0700 @@ -84,7 +84,7 @@ static int kcopyd_get_pages(struct kcopy ; kc->pages = pl->next; - pl->next = 0; + pl->next = NULL; spin_unlock(&kc->lock); --- linux-2.6.8-rc1/drivers/md/linear.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/md/linear.c 2004-07-13 17:09:31.784440904 -0700 @@ -47,7 +47,6 @@ static inline dev_info_t *which_dev(mdde return hash->dev0; } - /** * linear_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue @@ -93,6 +92,27 @@ static void linear_unplug(request_queue_ } } +static int linear_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + linear_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; i < mddev->raid_disks; i++) { + struct block_device *bdev = conf->disks[i].rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} static int linear_run (mddev_t *mddev) { @@ -200,6 +220,7 @@ static int linear_run (mddev_t *mddev) blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; + mddev->queue->issue_flush_fn = linear_issue_flush; return 0; out: --- linux-2.6.8-rc1/drivers/md/md.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/md/md.c 2004-07-13 17:09:31.787440448 -0700 @@ -154,6 +154,39 @@ static spinlock_t all_mddevs_lock = SPIN tmp = tmp->next;}) \ ) +int md_flush_mddev(mddev_t *mddev, sector_t *error_sector) +{ + struct list_head *tmp; + mdk_rdev_t *rdev; + int ret = 0; + + /* + * this list iteration is done without any locking in md?! + */ + ITERATE_RDEV(mddev, rdev, tmp) { + request_queue_t *r_queue = bdev_get_queue(rdev->bdev); + int err; + + if (!r_queue->unplug_fn) + err = -EOPNOTSUPP; + else + err = r_queue->issue_flush_fn(r_queue, rdev->bdev->bd_disk, error_sector); + + if (!ret) + ret = err; + } + + return ret; +} + +static int md_flush_all(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + + return md_flush_mddev(mddev, error_sector); +} + static int md_fail_request (request_queue_t *q, struct bio *bio) { bio_io_error(bio, bio->bi_size); @@ -1645,6 +1678,7 @@ static int do_md_run(mddev_t * mddev) */ mddev->queue->queuedata = mddev; mddev->queue->make_request_fn = mddev->pers->make_request; + mddev->queue->issue_flush_fn = md_flush_all; mddev->changed = 1; return 0; --- linux-2.6.8-rc1/drivers/md/multipath.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/md/multipath.c 2004-07-13 17:09:31.788440296 -0700 @@ -216,6 +216,31 @@ static void multipath_status (struct seq seq_printf (seq, "]"); } +static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + multipath_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->multipaths[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} /* * Careful, this can execute in IRQ contexts as well! @@ -430,6 +455,8 @@ static int multipath_run (mddev_t *mddev mddev->queue->unplug_fn = multipath_unplug; + mddev->queue->issue_flush_fn = multipath_issue_flush; + conf->working_disks = 0; ITERATE_RDEV(mddev,rdev,tmp) { disk_idx = rdev->raid_disk; --- linux-2.6.8-rc1/drivers/md/raid0.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/md/raid0.c 2004-07-13 17:09:31.788440296 -0700 @@ -40,6 +40,31 @@ static void raid0_unplug(request_queue_t } } +static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t **devlist = conf->strip_zone[0].dev; + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + struct block_device *bdev = devlist[i]->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + return ret; +} + + static int create_strip_zones (mddev_t *mddev) { int i, c, j; @@ -219,6 +244,8 @@ static int create_strip_zones (mddev_t * mddev->queue->unplug_fn = raid0_unplug; + mddev->queue->issue_flush_fn = raid0_issue_flush; + printk("raid0: done.\n"); return 0; abort: --- linux-2.6.8-rc1/drivers/md/raid1.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/md/raid1.c 2004-07-13 17:09:31.791439840 -0700 @@ -481,6 +481,32 @@ static void raid1_unplug(request_queue_t unplug_slaves(q->queuedata); } +static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + conf_t *conf = mddev_to_conf(mddev); + unsigned long flags; + int i, ret = 0; + + spin_lock_irqsave(&conf->device_lock, flags); + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->mirrors[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue = bdev_get_queue(bdev); + + if (r_queue->issue_flush_fn) { + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + } + spin_unlock_irqrestore(&conf->device_lock, flags); + return ret; +} + /* * Throttle resync depth, so that we can both get proper overlapping of * requests, but are still able to handle normal requests quickly. @@ -1168,6 +1194,7 @@ static int run(mddev_t *mddev) mddev->queue->unplug_fn = raid1_unplug; + mddev->queue->issue_flush_fn = raid1_issue_flush; ITERATE_RDEV(mddev, rdev, tmp) { disk_idx = rdev->raid_disk; --- linux-2.6.8-rc1/drivers/md/raid5.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/md/raid5.c 2004-07-13 17:09:31.794439384 -0700 @@ -1339,6 +1339,39 @@ static void raid5_unplug_device(request_ unplug_slaves(mddev); } +static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid5_plug_device(raid5_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1545,6 +1578,7 @@ static int run (mddev_t *mddev) atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid5_unplug_device; + mddev->queue->issue_flush_fn = raid5_issue_flush; PRINTK("raid5: run(%s) called.\n", mdname(mddev)); --- linux-2.6.8-rc1/drivers/md/raid6main.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/md/raid6main.c 2004-07-13 17:09:31.796439080 -0700 @@ -1501,6 +1501,39 @@ static void raid6_unplug_device(request_ unplug_slaves(mddev); } +static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + mddev_t *mddev = q->queuedata; + raid6_conf_t *conf = mddev_to_conf(mddev); + int i, ret = 0; + + for (i=0; iraid_disks; i++) { + mdk_rdev_t *rdev = conf->disks[i].rdev; + if (rdev && !rdev->faulty) { + struct block_device *bdev = rdev->bdev; + request_queue_t *r_queue; + + if (!bdev) + continue; + + r_queue = bdev_get_queue(bdev); + if (!r_queue) + continue; + + if (!r_queue->issue_flush_fn) { + ret = -EOPNOTSUPP; + break; + } + + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); + if (ret) + break; + } + } + return ret; +} + static inline void raid6_plug_device(raid6_conf_t *conf) { spin_lock_irq(&conf->device_lock); @@ -1708,6 +1741,7 @@ static int run (mddev_t *mddev) atomic_set(&conf->preread_active_stripes, 0); mddev->queue->unplug_fn = raid6_unplug_device; + mddev->queue->issue_flush_fn = raid6_issue_flush; PRINTK("raid6: run(%s) called.\n", mdname(mddev)); --- linux-2.6.8-rc1/drivers/media/common/saa7146_vbi.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/media/common/saa7146_vbi.c 2004-07-13 17:09:13.000000000 -0700 @@ -459,7 +459,7 @@ static void vbi_irq_done(struct saa7146_ spin_unlock(&dev->slock); } -static ssize_t vbi_read(struct file *file, char *data, size_t count, loff_t *ppos) +static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; --- linux-2.6.8-rc1/drivers/media/common/saa7146_video.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/common/saa7146_video.c 2004-07-13 17:35:10.000000000 -0700 @@ -1,9 +1,9 @@ #include -static int memory = 32; +static int max_memory = 32; -MODULE_PARM(memory,"i"); -MODULE_PARM_DESC(memory, "maximum memory usage for capture buffers (default: 32Mb)"); +MODULE_PARM(max_memory,"i"); +MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); #define IS_CAPTURE_ACTIVE(fh) \ (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) @@ -1331,9 +1331,9 @@ static int buffer_setup(struct file *fil *size = fh->video_fmt.sizeimage; - /* check if we exceed the "memory" parameter */ - if( (*count * *size) > (memory*1048576) ) { - *count = (memory*1048576) / *size; + /* check if we exceed the "max_memory" parameter */ + if( (*count * *size) > (max_memory*1048576) ) { + *count = (max_memory*1048576) / *size; } DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); @@ -1450,7 +1450,7 @@ static void video_irq_done(struct saa714 spin_unlock(&dev->slock); } -static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *ppos) +static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; --- linux-2.6.8-rc1/drivers/media/dvb/b2c2/skystar2.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/b2c2/skystar2.c 2004-07-13 17:09:13.000000000 -0700 @@ -208,7 +208,7 @@ static int flex_i2c_write4(struct adapte i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command); - return i2c_main_write_for_flex2(adapter, command, 0, 100000); + return i2c_main_write_for_flex2(adapter, command, NULL, 100000); } static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret) @@ -1681,7 +1681,7 @@ static void init_dma_queue(struct adapte adapter->dmaq1.head = 0; adapter->dmaq1.tail = 0; - adapter->dmaq1.buffer = 0; + adapter->dmaq1.buffer = NULL; adapter->dmaq1.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA1 + 0x80, &dma_addr); @@ -1707,7 +1707,7 @@ static void init_dma_queue(struct adapte adapter->dmaq2.head = 0; adapter->dmaq2.tail = 0; - adapter->dmaq2.buffer = 0; + adapter->dmaq2.buffer = NULL; adapter->dmaq2.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA2 + 0x80, &dma_addr); @@ -1738,7 +1738,7 @@ static void free_dma_queue(struct adapte adapter->dmaq1.head = 0; adapter->dmaq1.tail = 0; adapter->dmaq1.buffer_size = 0; - adapter->dmaq1.buffer = 0; + adapter->dmaq1.buffer = NULL; } if (adapter->dmaq2.buffer != 0) { @@ -1748,7 +1748,7 @@ static void free_dma_queue(struct adapte adapter->dmaq2.head = 0; adapter->dmaq2.tail = 0; adapter->dmaq2.buffer_size = 0; - adapter->dmaq2.buffer = 0; + adapter->dmaq2.buffer = NULL; } } @@ -2272,7 +2272,7 @@ static int skystar2_probe(struct pci_dev dvbdemux->feednum = N_PID_SLOTS; dvbdemux->start_feed = dvb_start_feed; dvbdemux->stop_feed = dvb_stop_feed; - dvbdemux->write_to_decoder = 0; + dvbdemux->write_to_decoder = NULL; dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); dvb_dmx_init(&adapter->demux); --- linux-2.6.8-rc1/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2004-07-13 17:09:13.000000000 -0700 @@ -205,7 +205,7 @@ static struct dvb_bt8xx_card *dvb_bt8xx_ if (NULL == dev) { /* shoudn't happen with 2.6.0-test7 + newer */ printk("attach: Huh? i2c adapter not in sysfs tree?\n"); - return 0; + return NULL; } pci = to_pci_dev(dev); list_for_each(item, &card_list) { --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dmxdev.c 2003-07-02 14:53:14.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dmxdev.c 2004-07-13 17:09:13.368240592 -0700 @@ -54,7 +54,7 @@ dvb_dmxdev_file_to_dvr(struct dmxdev *dm static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) { - buffer->data=0; + buffer->data=NULL; buffer->size=8192; buffer->pread=0; buffer->pwrite=0; @@ -97,7 +97,7 @@ static inline int dvb_dmxdev_buffer_writ } static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src, - int non_blocking, char *buf, size_t count, loff_t *ppos) + int non_blocking, char __user *buf, size_t count, loff_t *ppos) { unsigned long todo=count; int split, avail, error; @@ -162,12 +162,12 @@ static struct dmx_frontend * get_fe(stru head=demux->get_frontends(demux); if (!head) - return 0; + return NULL; list_for_each(pos, head) if (DMX_FE_ENTRY(pos)->source==type) return DMX_FE_ENTRY(pos); - return 0; + return NULL; } static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state) @@ -244,7 +244,7 @@ static int dvb_dvr_release(struct inode void *mem=dmxdev->dvr_buffer.data; mb(); spin_lock_irq(&dmxdev->lock); - dmxdev->dvr_buffer.data=0; + dmxdev->dvr_buffer.data=NULL; spin_unlock_irq(&dmxdev->lock); vfree(mem); } @@ -253,7 +253,7 @@ static int dvb_dvr_release(struct inode return 0; } -static ssize_t dvb_dvr_write(struct file *file, const char *buf, +static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; @@ -271,7 +271,7 @@ static ssize_t dvb_dvr_write(struct file return ret; } -static ssize_t dvb_dvr_read(struct file *file, char *buf, size_t count, +static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; @@ -304,7 +304,7 @@ static int dvb_dmxdev_set_buffer_size(st return -EBUSY; spin_lock_irq(&dmxdevfilter->dev->lock); mem=buf->data; - buf->data=0; + buf->data=NULL; buf->size=size; buf->pwrite=buf->pread=0; spin_unlock_irq(&dmxdevfilter->dev->lock); @@ -497,7 +497,7 @@ static int dvb_dmxdev_filter_stop(struct release_filter(dmxdevfilter->feed.sec, dmxdevfilter->filter.sec); dvb_dmxdev_feed_restart(dmxdevfilter); - dmxdevfilter->feed.sec=0; + dmxdevfilter->feed.sec=NULL; break; case DMXDEV_TYPE_PES: if (!dmxdevfilter->feed.ts) @@ -506,7 +506,7 @@ static int dvb_dmxdev_filter_stop(struct dmxdevfilter->dev->demux-> release_ts_feed(dmxdevfilter->dev->demux, dmxdevfilter->feed.ts); - dmxdevfilter->feed.ts=0; + dmxdevfilter->feed.ts=NULL; break; default: if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) @@ -558,8 +558,8 @@ static int dvb_dmxdev_filter_start(struc struct dmx_section_filter **secfilter=&filter->filter.sec; struct dmx_section_feed **secfeed=&filter->feed.sec; - *secfilter=0; - *secfeed=0; + *secfilter=NULL; + *secfeed=NULL; /* find active filter/feed with same PID */ for (i=0; ifilternum; i++) { @@ -640,7 +640,7 @@ static int dvb_dmxdev_filter_start(struc enum dmx_ts_pes ts_pes; struct dmx_ts_feed **tsfeed = &filter->feed.ts; - filter->feed.ts = 0; + filter->feed.ts = NULL; otype=para->output; ts_pes=(enum dmx_ts_pes) para->pes_type; @@ -717,7 +717,7 @@ static int dvb_demux_open(struct inode * dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); dmxdevfilter->type=DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - dmxdevfilter->feed.ts=0; + dmxdevfilter->feed.ts=NULL; init_timer(&dmxdevfilter->timer); up(&dmxdev->mutex); @@ -742,7 +742,7 @@ static int dvb_dmxdev_filter_free(struct void *mem=dmxdevfilter->buffer.data; spin_lock_irq(&dmxdev->lock); - dmxdevfilter->buffer.data=0; + dmxdevfilter->buffer.data=NULL; spin_unlock_irq(&dmxdev->lock); vfree(mem); } @@ -806,7 +806,7 @@ static int dvb_dmxdev_pes_filter_set(str } static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, - struct file *file, char *buf, size_t count, loff_t *ppos) + struct file *file, char __user *buf, size_t count, loff_t *ppos) { int result, hcount; int done=0; @@ -845,7 +845,7 @@ static ssize_t dvb_dmxdev_read_sec(struc ssize_t -dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos) +dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); int ret=0; @@ -1006,7 +1006,7 @@ static struct file_operations dvb_demux_ }; static struct dvb_device dvbdev_demux = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_demux_fops @@ -1077,7 +1077,7 @@ static struct file_operations dvb_dvr_fo }; static struct dvb_device dvbdev_dvr = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_dvr_fops @@ -1106,10 +1106,10 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, s spin_lock_init(&dmxdev->lock); for (i=0; ifilternum; i++) { dmxdev->filter[i].dev=dmxdev; - dmxdev->filter[i].buffer.data=0; + dmxdev->filter[i].buffer.data=NULL; dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dmxdev->dvr[i].dev=dmxdev; - dmxdev->dvr[i].buffer.data=0; + dmxdev->dvr[i].buffer.data=NULL; dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); } @@ -1128,11 +1128,11 @@ dvb_dmxdev_release(struct dmxdev *dmxdev dvb_unregister_device(dmxdev->dvr_dvbdev); if (dmxdev->filter) { vfree(dmxdev->filter); - dmxdev->filter=0; + dmxdev->filter=NULL; } if (dmxdev->dvr) { vfree(dmxdev->dvr); - dmxdev->dvr=0; + dmxdev->dvr=NULL; } dmxdev->demux->close(dmxdev->demux); } --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-07-13 17:09:13.370240288 -0700 @@ -621,7 +621,7 @@ static int dvb_ca_en50221_read_data(stru /* OK, add it to the receive buffer, or copy into external buffer if supplied */ if (ebuf == NULL) { - dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read, 0); + dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); } else { memcpy(ebuf, buf, bytes_read); } @@ -1188,7 +1188,7 @@ static int dvb_ca_en50221_io_ioctl(struc * * @return Number of bytes read, or <0 on error. */ -static ssize_t dvb_ca_en50221_io_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; @@ -1303,7 +1303,7 @@ nextslot: * * @return Number of bytes read, or <0 on error. */ -static ssize_t dvb_ca_en50221_io_read(struct file *file, char *buf, size_t count, loff_t *ppos) +static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; @@ -1494,7 +1494,7 @@ static struct file_operations dvb_ca_fop }; static struct dvb_device dvbdev_ca = { - priv: 0, + priv: NULL, users: 1, readers: 1, writers: 1, --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_demux.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_demux.c 2004-07-13 17:09:13.371240136 -0700 @@ -160,7 +160,7 @@ static inline int dvb_dmx_swfilter_paylo feed->peslen += count; - return feed->cb.ts (&buf[p], count, 0, 0, &feed->feed.ts, DMX_OK); + return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); } @@ -183,7 +183,7 @@ static int dvb_dmx_swfilter_sectionfilte return 0; return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen, - 0, 0, &f->filter, DMX_OK); + NULL, 0, &f->filter, DMX_OK); } @@ -373,7 +373,7 @@ static inline void dvb_dmx_swfilter_pack if (feed->ts_type & TS_PAYLOAD_ONLY) dvb_dmx_swfilter_payload(feed, buf); else - feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); } if (feed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder) @@ -422,7 +422,7 @@ void dvb_dmx_swfilter_packet(struct dvb_ } if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); } } @@ -637,7 +637,7 @@ static int dmx_ts_feed_set (struct dmx_t if (feed->buffer_size) { #ifdef NOBUFS - feed->buffer=0; + feed->buffer=NULL; #else feed->buffer = vmalloc(feed->buffer_size); if (!feed->buffer) { @@ -736,11 +736,11 @@ static int dvbdmx_allocate_ts_feed (stru feed->demux = demux; feed->pid = 0xffff; feed->peslen = 0xfffa; - feed->buffer = 0; + feed->buffer = NULL; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; - (*ts_feed)->priv = 0; + (*ts_feed)->priv = NULL; (*ts_feed)->is_filtering = 0; (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; @@ -820,7 +820,7 @@ static int dmx_section_feed_allocate_fil spin_lock_irq(&dvbdemux->lock); *filter=&dvbdmxfilter->filter; (*filter)->parent=feed; - (*filter)->priv=0; + (*filter)->priv=NULL; dvbdmxfilter->feed=dvbdmxfeed; dvbdmxfilter->type=DMX_TYPE_SEC; dvbdmxfilter->state=DMX_STATE_READY; @@ -858,7 +858,7 @@ static int dmx_section_feed_set(struct d dvbdmxfeed->feed.sec.check_crc=check_crc; #ifdef NOBUFS - dvbdmxfeed->buffer=0; + dvbdmxfeed->buffer=NULL; #else dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); if (!dvbdmxfeed->buffer) { @@ -1015,13 +1015,13 @@ static int dvbdmx_allocate_section_feed( dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; - dvbdmxfeed->filter=0; - dvbdmxfeed->buffer=0; + dvbdmxfeed->filter=NULL; + dvbdmxfeed->buffer=NULL; (*feed)=&dvbdmxfeed->feed.sec; (*feed)->is_filtering=0; (*feed)->parent=demux; - (*feed)->priv=0; + (*feed)->priv=NULL; (*feed)->set=dmx_section_feed_set; (*feed)->allocate_filter=dmx_section_feed_allocate_filter; @@ -1223,7 +1223,7 @@ int dvb_dmx_init(struct dvb_demux *dvbde if (!dvbdemux->memcopy) dvbdemux->memcopy = dvb_dmx_memcopy; - dmx->frontend=0; + dmx->frontend=NULL; dmx->reg_list.prev = dmx->reg_list.next = &dmx->reg_list; dmx->priv=(void *) dvbdemux; dmx->open=dvbdmx_open; --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvbdev.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvbdev.c 2004-07-13 17:09:13.375239528 -0700 @@ -191,7 +191,7 @@ int dvb_register_device(struct dvb_adapt if ((id = dvbdev_get_free_id (adap, type)) < 0) { up (&dvbdev_register_lock); - *pdvbdev = 0; + *pdvbdev = NULL; printk ("%s: could get find free device id...\n", __FUNCTION__); return -ENFILE; } --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_functions.c 2003-10-08 15:07:08.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_functions.c 2004-07-13 17:09:13.372239984 -0700 @@ -36,7 +36,7 @@ int dvb_usercopy(struct inode *inode, st /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: - parg = (void *)arg; + parg = NULL; break; case _IOC_READ: /* some v4l ioctls are marked wrong ... */ case _IOC_WRITE: @@ -52,7 +52,7 @@ int dvb_usercopy(struct inode *inode, st } err = -EFAULT; - if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) goto out; break; } @@ -69,7 +69,7 @@ int dvb_usercopy(struct inode *inode, st { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) err = -EFAULT; break; } --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_net.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_net.c 2004-07-13 17:09:13.373239832 -0700 @@ -677,7 +677,7 @@ static int dvb_net_filter_sec_set(struct struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv; int ret; - *secfilter=0; + *secfilter=NULL; ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter); if (ret<0) { printk("%s: could not get filter\n", dev->name); @@ -726,9 +726,9 @@ static int dvb_net_feed_start(struct net if (priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) printk("%s: BUG %d\n", __FUNCTION__, __LINE__); - priv->secfeed=0; - priv->secfilter=0; - priv->tsfeed = 0; + priv->secfeed=NULL; + priv->secfilter=NULL; + priv->tsfeed = NULL; if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { dprintk("%s: alloc secfeed\n", __FUNCTION__); @@ -744,7 +744,7 @@ static int dvb_net_feed_start(struct net if (ret<0) { printk("%s: could not set section feed\n", dev->name); priv->demux->release_section_feed(priv->demux, priv->secfeed); - priv->secfeed=0; + priv->secfeed=NULL; return ret; } @@ -799,7 +799,7 @@ static int dvb_net_feed_start(struct net if (ret < 0) { printk("%s: could not set ts feed\n", dev->name); priv->demux->release_ts_feed(priv->demux, priv->tsfeed); - priv->tsfeed = 0; + priv->tsfeed = NULL; return ret; } @@ -828,7 +828,7 @@ static int dvb_net_feed_stop(struct net_ dprintk("%s: release secfilter\n", __FUNCTION__); priv->secfeed->release_filter(priv->secfeed, priv->secfilter); - priv->secfilter=0; + priv->secfilter=NULL; } for (i=0; imulti_num; i++) { @@ -837,12 +837,12 @@ static int dvb_net_feed_stop(struct net_ __FUNCTION__, i); priv->secfeed->release_filter(priv->secfeed, priv->multi_secfilter[i]); - priv->multi_secfilter[i]=0; + priv->multi_secfilter[i]=NULL; } } priv->demux->release_section_feed(priv->demux, priv->secfeed); - priv->secfeed=0; + priv->secfeed=NULL; } else printk("%s: no feed to stop\n", dev->name); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { @@ -852,7 +852,7 @@ static int dvb_net_feed_stop(struct net_ priv->tsfeed->stop_filtering(priv->tsfeed); } priv->demux->release_ts_feed(priv->demux, priv->tsfeed); - priv->tsfeed = 0; + priv->tsfeed = NULL; } else printk("%s: no ts feed to stop\n", dev->name); @@ -1178,16 +1178,13 @@ static int dvb_net_ioctl(struct inode *i static struct file_operations dvb_net_fops = { .owner = THIS_MODULE, - .read = 0, - .write = 0, .ioctl = dvb_net_ioctl, .open = dvb_generic_open, .release = dvb_generic_release, - .poll = 0, }; static struct dvb_device dvbdev_net = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_net_fops, --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_ringbuffer.c 2004-07-13 17:09:13.374239680 -0700 @@ -133,8 +133,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_r -ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, - size_t len, int usermem) +ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) { size_t todo = len; size_t split; @@ -142,28 +141,18 @@ ssize_t dvb_ringbuffer_write(struct dvb_ split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; if (split > 0) { - if (!usermem) - memcpy(rbuf->data+rbuf->pwrite, buf, split); - else - if (copy_from_user(rbuf->data+rbuf->pwrite, - buf, split)) - return -EFAULT; + memcpy(rbuf->data+rbuf->pwrite, buf, split); buf += split; todo -= split; rbuf->pwrite = 0; } - if (!usermem) - memcpy(rbuf->data+rbuf->pwrite, buf, todo); - else - if (copy_from_user(rbuf->data+rbuf->pwrite, buf, todo)) - return -EFAULT; - + memcpy(rbuf->data+rbuf->pwrite, buf, todo); rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; return len; } -ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len, int usermem) +ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) { int status; ssize_t oldpwrite = rbuf->pwrite; @@ -171,7 +160,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); - status = dvb_ringbuffer_write(rbuf, buf, len, usermem); + status = dvb_ringbuffer_write(rbuf, buf, len); if (status < 0) rbuf->pwrite = oldpwrite; return status; --- linux-2.6.8-rc1/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/dvb-core/dvb_ringbuffer.h 2004-07-13 17:09:13.375239528 -0700 @@ -53,7 +53,7 @@ struct dvb_ringbuffer { ** *** write bytes *** ** free = dvb_ringbuffer_free(rbuf); ** if (free >= buflen) -** count = dvb_ringbuffer_write(rbuf, buffer, buflen, 0); +** count = dvb_ringbuffer_write(rbuf, buffer, buflen); ** else ** ... ** @@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struc ** returns number of bytes transferred or -EFAULT */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, - size_t len, int usermem); + size_t len); /** @@ -130,11 +130,10 @@ extern ssize_t dvb_ringbuffer_write(stru * Ringbuffer to write to. * Buffer to write. * Length of buffer (currently limited to 65535 bytes max). - * Set to 1 if is in userspace. * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. */ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, - size_t len, int usermem); + size_t len); /** * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this --- linux-2.6.8-rc1/drivers/media/dvb/frontends/alps_tdlb7.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/frontends/alps_tdlb7.c 2004-07-13 17:09:53.000000000 -0700 @@ -56,9 +56,6 @@ static int debug = 0; /* starting point for firmware in file 'Sc_main.mc' */ #define SP8870_FIRMWARE_OFFSET 0x0A - -static int errno; - static struct dvb_frontend_info tdlb7_info = { .name = "Alps TDLB7", .type = FE_OFDM, --- linux-2.6.8-rc1/drivers/media/dvb/frontends/sp887x.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/frontends/sp887x.c 2004-07-13 17:09:55.000000000 -0700 @@ -68,8 +68,6 @@ struct dvb_frontend_info sp887x_info = { FE_CAN_RECOVER }; -static int errno; - static int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len) { --- linux-2.6.8-rc1/drivers/media/dvb/frontends/tda1004x.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/dvb/frontends/tda1004x.c 2004-07-13 17:09:55.000000000 -0700 @@ -190,8 +190,6 @@ static int tda10045h_fwinfo_count = size static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} }; static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo); -static int errno; - static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data) { @@ -538,7 +536,7 @@ static int tda1004x_fwupload(struct dvb_ static int tda10045h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state) { - struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0 }; + struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 }; static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; dprintk("%s\n", __FUNCTION__); @@ -576,7 +574,7 @@ static int tda10045h_init(struct dvb_i2c static int tda10046h_init(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state) { - struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0 }; + struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 }; static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; dprintk("%s\n", __FUNCTION__); @@ -1393,7 +1391,7 @@ static int tda1004x_attach(struct dvb_i2 int tuner_type = -1; struct tda1004x_state tda_state; struct tda1004x_state* ptda_state; - struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=0, .len=0 }; + struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=NULL, .len=0 }; static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab }; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab }; --- linux-2.6.8-rc1/drivers/media/dvb/ttpci/av7110_av.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/ttpci/av7110_av.c 2004-07-13 17:09:13.000000000 -0700 @@ -109,7 +109,7 @@ int av7110_record_cb(struct dvb_filter_p if (buf[3] == 0xe0) // video PES do not have a length in TS buf[4] = buf[5] = 0; if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - return dvbdmxfeed->cb.ts(buf, len, 0, 0, + return dvbdmxfeed->cb.ts(buf, len, NULL, 0, &dvbdmxfeed->feed.ts, DMX_OK); else return dvb_filter_pes2ts(p2t, buf, len, 1); @@ -121,7 +121,7 @@ static int dvb_filter_pes2ts_cb(void *pr // DEB_EE(("dvb_demux_feed:%p\n", dvbdmxfeed)); - dvbdmxfeed->cb.ts(data, 188, 0, 0, + dvbdmxfeed->cb.ts(data, 188, NULL, 0, &dvbdmxfeed->feed.ts, DMX_OK); return 0; } @@ -393,7 +393,7 @@ static inline long aux_ring_buffer_write free = dvb_ringbuffer_free(rbuf); if (free > todo) free = todo; - dvb_ringbuffer_write(rbuf, buf, free, 0); + dvb_ringbuffer_write(rbuf, buf, free); todo -= free; buf += free; } @@ -424,8 +424,8 @@ static void play_audio_cb(u8 *buf, int c #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) -static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf, - unsigned long count, int nonblock, int type, int umem) +static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf, + unsigned long count, int nonblock, int type) { unsigned long todo = count, n; DEB_EE(("av7110: %p\n", av7110)); @@ -447,22 +447,47 @@ static ssize_t dvb_play(struct av7110 *a n = todo; if (n > IPACKS * 2) n = IPACKS * 2; - if (umem) { - if (copy_from_user(av7110->kbuf[type], buf, n)) - return -EFAULT; - av7110_ipack_instant_repack(av7110->kbuf[type], n, - &av7110->ipack[type]); - } else { - av7110_ipack_instant_repack(buf, n, - &av7110->ipack[type]); + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + DEB_EE(("av7110: %p\n", av7110)); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); todo -= n; buf += n; } return count - todo; } -static ssize_t dvb_aplay(struct av7110 *av7110, const u8 *buf, +static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf, unsigned long count, int nonblock, int type) { unsigned long todo = count, n; @@ -733,7 +758,7 @@ static void p_to_t(u8 const *buf, long i memcpy(obuf + l, buf + c, TS_SIZE - l); c = length; } - feed->cb.ts(obuf, 188, 0, 0, &feed->feed.ts, DMX_OK); + feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); pes_start = 0; } } @@ -871,7 +896,7 @@ static unsigned int dvb_video_poll(struc return mask; } -static ssize_t dvb_video_write(struct file *file, const char *buf, +static ssize_t dvb_video_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; @@ -885,7 +910,7 @@ static ssize_t dvb_video_write(struct fi if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) return -EPERM; - return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1, 1); + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); } static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) @@ -907,7 +932,7 @@ static unsigned int dvb_audio_poll(struc return mask; } -static ssize_t dvb_audio_write(struct file *file, const char *buf, +static ssize_t dvb_audio_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; @@ -926,7 +951,7 @@ u8 iframe_header[] = { 0x00, 0x00, 0x01, #define MIN_IFRAME 400000 -static int play_iframe(struct av7110 *av7110, u8 *buf, unsigned int len, int nonblock) +static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock) { int i, n; @@ -942,10 +967,10 @@ static int play_iframe(struct av7110 *av n = MIN_IFRAME / len + 1; /* FIXME: nonblock? */ - dvb_play(av7110, iframe_header, sizeof(iframe_header), 0, 1, 0); + dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); for (i = 0; i < n; i++) - dvb_play(av7110, buf, len, 0, 1, 1); + dvb_play(av7110, buf, len, 0, 1); av7110_ipack_flush(&av7110->ipack[1]); return 0; @@ -1347,7 +1372,7 @@ static struct file_operations dvb_video_ }; static struct dvb_device dvbdev_video = { - .priv = 0, + .priv = NULL, .users = 6, .readers = 5, /* arbitrary */ .writers = 1, @@ -1365,7 +1390,7 @@ static struct file_operations dvb_audio_ }; static struct dvb_device dvbdev_audio = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_audio_fops, --- linux-2.6.8-rc1/drivers/media/dvb/ttpci/av7110.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/ttpci/av7110.c 2004-07-13 17:09:13.000000000 -0700 @@ -320,7 +320,7 @@ static void debiirq (unsigned long data) case DATA_PIPING: if (av7110->handle2filter[handle]) DvbDmxFilterCallback((u8 *)av7110->debi_virt, - av7110->debilen, 0, 0, + av7110->debilen, NULL, 0, av7110->handle2filter[handle], DMX_OK, av7110); spin_lock(&av7110->debilock); @@ -651,7 +651,7 @@ static struct file_operations dvb_osd_fo }; static struct dvb_device dvbdev_osd = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_osd_fops, @@ -928,7 +928,7 @@ static int av7110_stop_feed(struct dvb_d !demux->pesfilter[feed->pes_type]) return -EINVAL; demux->pids[feed->pes_type] |= 0x8000; - demux->pesfilter[feed->pes_type] = 0; + demux->pesfilter[feed->pes_type] = NULL; } if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) { @@ -1402,7 +1402,7 @@ static int av7110_attach(struct saa7146_ /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); - av7110->arm_thread=0; + av7110->arm_thread=NULL; /* allocate and init buffers */ av7110->debi_virt = pci_alloc_consistent(dev->pci, 8192, --- linux-2.6.8-rc1/drivers/media/dvb/ttpci/av7110_ca.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/media/dvb/ttpci/av7110_ca.c 2004-07-13 17:09:13.000000000 -0700 @@ -85,7 +85,7 @@ void ci_get_data(struct dvb_ringbuffer * DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); - dvb_ringbuffer_write(cibuf, data, len, 0); + dvb_ringbuffer_write(cibuf, data, len); wake_up_interruptible(&cibuf->queue); } @@ -110,9 +110,9 @@ void ci_ll_flush(struct dvb_ringbuffer * void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) { vfree(cirbuf->data); - cirbuf->data = 0; + cirbuf->data = NULL; vfree(ciwbuf->data); - ciwbuf->data = 0; + ciwbuf->data = NULL; } int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, @@ -133,7 +133,7 @@ int ci_ll_reset(struct dvb_ringbuffer *c for (i = 0; i < 2; i++) { if (slots & (1 << i)) { msg[2] = i; - dvb_ringbuffer_write(cibuf, msg, 8, 0); + dvb_ringbuffer_write(cibuf, msg, 8); slot[i].flags = 0; } } @@ -142,30 +142,46 @@ int ci_ll_reset(struct dvb_ringbuffer *c } static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, - const char *buf, size_t count, loff_t *ppos) + const char __user *buf, size_t count, loff_t *ppos) { int free; int non_blocking = file->f_flags & O_NONBLOCK; + char *page = (char *)__get_free_page(GFP_USER); + int res; + if (!page) + return -ENOMEM; + + res = -EINVAL; if (count > 2048) - return -EINVAL; + goto out; + + res = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + free = dvb_ringbuffer_free(cibuf); if (count + 2 > free) { + res = -EWOULDBLOCK; if (non_blocking) - return -EWOULDBLOCK; + goto out; + res = -ERESTARTSYS; if (wait_event_interruptible(cibuf->queue, (dvb_ringbuffer_free(cibuf) >= count + 2))) - return -ERESTARTSYS; + goto out; } DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); - return dvb_ringbuffer_write(cibuf, buf, count, 1); + res = dvb_ringbuffer_write(cibuf, page, count); +out: + free_page((unsigned long)page); + return res; } static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, - char *buf, size_t count, loff_t *ppos) + char __user *buf, size_t count, loff_t *ppos) { int avail; int non_blocking = file->f_flags & O_NONBLOCK; @@ -301,7 +317,7 @@ static int dvb_ca_ioctl(struct inode *in return 0; } -static ssize_t dvb_ca_write(struct file *file, const char *buf, +static ssize_t dvb_ca_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; @@ -311,7 +327,7 @@ static ssize_t dvb_ca_write(struct file return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); } -static ssize_t dvb_ca_read(struct file *file, char *buf, +static ssize_t dvb_ca_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; @@ -334,7 +350,7 @@ static struct file_operations dvb_ca_fop }; static struct dvb_device dvbdev_ca = { - .priv = 0, + .priv = NULL, .users = 1, .writers = 1, .fops = &dvb_ca_fops, --- linux-2.6.8-rc1/drivers/media/dvb/ttpci/av7110_hw.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/ttpci/av7110_hw.c 2004-07-13 17:09:13.000000000 -0700 @@ -737,7 +737,7 @@ static enum av7110_window_display_type b }; static inline int LoadBitmap(struct av7110 *av7110, u16 format, - u16 dx, u16 dy, int inc, u8* data) + u16 dx, u16 dy, int inc, u8 __user * data) { int bpp; int i; @@ -887,7 +887,7 @@ static int OSDSetPalette(struct av7110 * } static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, - int x1, int y1, int inc, u8 *data) + int x1, int y1, int inc, u8 __user *data) { uint w, h, bpp, bpl, size, lpb, bnum, brest; int i; @@ -953,17 +953,32 @@ int av7110_osd_cmd(struct av7110 *av7110 return 0; case OSD_SetPalette: { + int len = dc->x0-dc->color+1; + void *buf; + if (len <= 0) + return 0; + + buf = kmalloc(len * 4, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, dc->data, len * 4)) { + kfree(buf); + return -EFAULT; + } + if (FW_VERSION(av7110->arm_app) >= 0x2618) - OSDSetPalette(av7110, (u32 *)dc->data, dc->color, dc->x0); + OSDSetPalette(av7110, buf, dc->color, dc->x0); else { - int i, len = dc->x0-dc->color+1; - u8 *colors = (u8 *)dc->data; + int i; + u8 *colors = buf; for (i = 0; icolor + i, colors[i * 4], colors[i * 4 + 1], colors[i * 4 + 2], colors[i * 4 + 3]); } + kfree(buf); return 0; } case OSD_SetTrans: --- linux-2.6.8-rc1/drivers/media/dvb/ttpci/av7110_ir.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/media/dvb/ttpci/av7110_ir.c 2004-07-13 17:09:13.000000000 -0700 @@ -138,7 +138,7 @@ static void input_repeat_key(unsigned lo } -static int av7110_ir_write_proc (struct file *file, const char *buffer, +static int av7110_ir_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { char *page; --- linux-2.6.8-rc1/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2004-07-13 17:09:13.000000000 -0700 @@ -1125,7 +1125,7 @@ static int ttusb_probe(struct usb_interf ttusb->dvb_demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - ttusb->dvb_demux.priv = 0; + ttusb->dvb_demux.priv = NULL; #ifdef TTUSB_HWSECTIONS ttusb->dvb_demux.filternum = TTUSB_MAXFILTER; #else @@ -1134,7 +1134,7 @@ static int ttusb_probe(struct usb_interf ttusb->dvb_demux.feednum = TTUSB_MAXCHANNEL; ttusb->dvb_demux.start_feed = ttusb_start_feed; ttusb->dvb_demux.stop_feed = ttusb_stop_feed; - ttusb->dvb_demux.write_to_decoder = 0; + ttusb->dvb_demux.write_to_decoder = NULL; if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", --- linux-2.6.8-rc1/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-05-09 21:07:23.000000000 -0700 +++ 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-07-13 17:09:13.000000000 -0700 @@ -314,7 +314,7 @@ static int ttusb_dec_audio_pes2ts_cb(voi { struct ttusb_dec *dec = (struct ttusb_dec *)priv; - dec->audio_filter->feed->cb.ts(data, 188, 0, 0, + dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, &dec->audio_filter->feed->feed.ts, DMX_OK); @@ -325,7 +325,7 @@ static int ttusb_dec_video_pes2ts_cb(voi { struct ttusb_dec *dec = (struct ttusb_dec *)priv; - dec->video_filter->feed->cb.ts(data, 188, 0, 0, + dec->video_filter->feed->cb.ts(data, 188, NULL, 0, &dec->video_filter->feed->feed.ts, DMX_OK); @@ -378,7 +378,7 @@ static void ttusb_dec_process_pva(struct u16 v_pes_payload_length; if (output_pva) { - dec->video_filter->feed->cb.ts(pva, length, 0, 0, + dec->video_filter->feed->cb.ts(pva, length, NULL, 0, &dec->video_filter->feed->feed.ts, DMX_OK); return; } @@ -439,7 +439,7 @@ static void ttusb_dec_process_pva(struct case 0x02: /* MainAudioStream */ if (output_pva) { - dec->audio_filter->feed->cb.ts(pva, length, 0, 0, + dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, &dec->audio_filter->feed->feed.ts, DMX_OK); return; } --- linux-2.6.8-rc1/drivers/media/radio/miropcm20-radio.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/drivers/media/radio/miropcm20-radio.c 2004-07-13 17:09:13.000000000 -0700 @@ -61,7 +61,7 @@ static int pcm20_setfreq(struct pcm20_de freql = freq & 0xff; freqh = freq >> 8; - aci_rds_cmd(RDS_RESET, 0, 0); + aci_rds_cmd(RDS_RESET, NULL, 0); pcm20_stereo(dev, 1); return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh); --- linux-2.6.8-rc1/drivers/media/radio/miropcm20-rds.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/drivers/media/radio/miropcm20-rds.c 2004-07-13 17:09:13.000000000 -0700 @@ -53,7 +53,7 @@ static void print_matrix(char *ch, char } } -static ssize_t rds_f_read(struct file *file, char *buffer, size_t length, loff_t *offset) +static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { // i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset); --- linux-2.6.8-rc1/drivers/media/radio/radio-cadet.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/radio/radio-cadet.c 2004-07-13 17:09:13.000000000 -0700 @@ -323,7 +323,7 @@ void cadet_handler(unsigned long data) -static ssize_t cadet_read(struct file *file, char *data, +static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { int i=0; --- linux-2.6.8-rc1/drivers/media/radio/radio-gemtek.c 2003-06-14 12:17:55.000000000 -0700 +++ 25/drivers/media/radio/radio-gemtek.c 2004-07-13 17:09:13.000000000 -0700 @@ -194,7 +194,7 @@ static int gemtek_do_ioctl(struct inode } case VIDIOCGAUDIO: { - struct video_audio *v = 0; + struct video_audio *v = arg; memset(v,0, sizeof(*v)); v->flags|=VIDEO_AUDIO_MUTABLE; v->volume=1; --- linux-2.6.8-rc1/drivers/media/video/bttv-cards.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/bttv-cards.c 2004-07-13 17:09:13.000000000 -0700 @@ -4063,7 +4063,7 @@ static void PXC200_muxsel(struct bttv *b return; } - rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),0); + rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); if (!(rc & PX_CFG_PXC200F)) { printk(KERN_DEBUG "bttv%d: PXC200_muxsel: not PXC200F rc:%d \n", btv->c.nr,rc); return; --- linux-2.6.8-rc1/drivers/media/video/bttv-driver.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/bttv-driver.c 2004-07-13 17:09:13.000000000 -0700 @@ -1068,7 +1068,7 @@ static void init_bt848(struct bttv *btv) init_irqreg(btv); } -extern void bttv_reinit_bt848(struct bttv *btv) +void bttv_reinit_bt848(struct bttv *btv) { unsigned long flags; @@ -2261,7 +2261,7 @@ static int bttv_do_ioctl(struct inode *i w2.w.width = win->width; w2.w.height = win->height; w2.clipcount = win->clipcount; - w2.clips = (struct v4l2_clip*)win->clips; + w2.clips = (struct v4l2_clip __user *)win->clips; retval = setup_window(fh, btv, &w2, 0); if (0 == retval) { /* on v4l1 this ioctl affects the read() size too */ @@ -2821,7 +2821,7 @@ static int bttv_ioctl(struct inode *inod } } -static ssize_t bttv_read(struct file *file, char *data, +static ssize_t bttv_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct bttv_fh *fh = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/bw-qcam.c 2004-02-17 20:48:43.000000000 -0800 +++ 25/drivers/media/video/bw-qcam.c 2004-07-13 17:09:13.000000000 -0700 @@ -599,7 +599,7 @@ static inline int qc_readbytes(struct qc * n=2^(bit depth)-1. Ask me for more details if you don't understand * this. */ -long qc_capture(struct qcam_device * q, char *buf, unsigned long len) +long qc_capture(struct qcam_device * q, char __user *buf, unsigned long len) { int i, j, k, yield; int bytes; @@ -660,7 +660,7 @@ long qc_capture(struct qcam_device * q, } pixels_read += bytes; } - (void) qc_readbytes(q, 0); /* reset state machine */ + (void) qc_readbytes(q, NULL); /* reset state machine */ /* Grabbing an entire frame from the quickcam is a lengthy process. We don't (usually) want to busy-block the @@ -855,7 +855,7 @@ static int qcam_ioctl(struct inode *inod return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl); } -static ssize_t qcam_read(struct file *file, char *buf, +static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *v = video_devdata(file); --- linux-2.6.8-rc1/drivers/media/video/cpia.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/media/video/cpia.c 2004-07-13 17:09:13.000000000 -0700 @@ -585,7 +585,7 @@ static unsigned long int value(char **bu return ret; } -static int cpia_write_proc(struct file *file, const char *buf, +static int cpia_write_proc(struct file *file, const char __user *buf, unsigned long count, void *data) { struct cam_data *cam = data; @@ -1400,7 +1400,7 @@ static void destroy_proc_cpia_cam(struct static void proc_cpia_create(void) { - cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0); + cpia_proc_root = create_proc_entry("cpia", S_IFDIR, NULL); if (cpia_proc_root) cpia_proc_root->owner = THIS_MODULE; @@ -1410,7 +1410,7 @@ static void proc_cpia_create(void) static void __exit proc_cpia_destroy(void) { - remove_proc_entry("cpia", 0); + remove_proc_entry("cpia", NULL); } #endif /* CONFIG_PROC_FS */ @@ -1624,7 +1624,7 @@ static int free_frame_buf(struct cam_dat int i; rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE); - cam->frame_buf = 0; + cam->frame_buf = NULL; for (i=0; i < FRAME_NUM; i++) cam->frame[i].data = NULL; @@ -3299,7 +3299,7 @@ static int cpia_close(struct inode *inod return 0; } -static ssize_t cpia_read(struct file *file, char *buf, +static ssize_t cpia_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/c-qcam.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/media/video/c-qcam.c 2004-07-13 17:09:13.000000000 -0700 @@ -358,7 +358,7 @@ get_fragment: #define BUFSZ 150 -static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) +static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len) { unsigned lines, pixelsperline, bitsperxfer; unsigned int is_bi_dir = q->bidirectional; @@ -667,7 +667,7 @@ static int qcam_ioctl(struct inode *inod return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl); } -static ssize_t qcam_read(struct file *file, char *buf, +static ssize_t qcam_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *v = video_devdata(file); --- linux-2.6.8-rc1/drivers/media/video/cx88/cx88-video.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/cx88/cx88-video.c 2004-07-13 17:09:13.000000000 -0700 @@ -1279,7 +1279,7 @@ static int video_open(struct inode *inod } static ssize_t -video_read(struct file *file, char *data, size_t count, loff_t *ppos) +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct cx8800_fh *fh = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/dpc7146.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/video/dpc7146.c 2004-07-13 17:09:13.000000000 -0700 @@ -91,7 +91,7 @@ struct dpc /* fixme: add vbi stuff here */ static int dpc_probe(struct saa7146_dev* dev) { - struct dpc* dpc = 0; + struct dpc* dpc = NULL; struct i2c_client *client; struct list_head *item; --- linux-2.6.8-rc1/drivers/media/video/hexium_orion.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/video/hexium_orion.c 2004-07-13 17:09:13.000000000 -0700 @@ -212,7 +212,7 @@ static struct saa7146_standard hexium_st without eeprom */ static int hexium_probe(struct saa7146_dev *dev) { - struct hexium *hexium = 0; + struct hexium *hexium = NULL; union i2c_smbus_data data; int err = 0; --- linux-2.6.8-rc1/drivers/media/video/meye.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/meye.c 2004-07-13 17:09:13.000000000 -0700 @@ -203,7 +203,7 @@ static int ptable_alloc(void) { PAGE_SIZE, meye.mchip_ptable_toc, meye.mchip_dmahandle); - meye.mchip_ptable_toc = 0; + meye.mchip_ptable_toc = NULL; meye.mchip_dmahandle = 0; return -1; } @@ -232,7 +232,7 @@ static void ptable_free(void) { meye.mchip_dmahandle); memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - meye.mchip_ptable_toc = 0; + meye.mchip_ptable_toc = NULL; meye.mchip_dmahandle = 0; } --- linux-2.6.8-rc1/drivers/media/video/mxb.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/video/mxb.c 2004-07-13 17:09:13.000000000 -0700 @@ -150,7 +150,7 @@ static struct saa7146_extension extensio static int mxb_probe(struct saa7146_dev* dev) { - struct mxb* mxb = 0; + struct mxb* mxb = NULL; struct i2c_client *client; struct list_head *item; int result; --- linux-2.6.8-rc1/drivers/media/video/pms.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/media/video/pms.c 2004-07-13 17:09:13.000000000 -0700 @@ -625,7 +625,7 @@ static void pms_vcrinput(short input) } -static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count) +static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int count) { int y; int dw = 2*dev->width; @@ -865,7 +865,7 @@ static int pms_ioctl(struct inode *inode return video_usercopy(inode, file, cmd, arg, pms_do_ioctl); } -static int pms_read(struct file *file, char *buf, +static int pms_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *v = video_devdata(file); --- linux-2.6.8-rc1/drivers/media/video/saa5246a.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/saa5246a.c 2004-07-13 17:09:13.000000000 -0700 @@ -485,73 +485,76 @@ static inline int saa5246a_get_status(st static inline int saa5246a_get_page(struct saa5246a_device *t, vtx_pagereq_t *req) { - int start, end; + int start, end, size; + char *buf; + int err; if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 || req->start > req->end || req->end >= VTX_PAGESIZE) return -EINVAL; - /* Read "normal" part of page */ - end = min(req->end, VTX_PAGESIZE - 1); - if (i2c_senddata(t, SAA5246A_REGISTER_R8, - req->pgbuf | - R8_DO_NOT_CLEAR_MEMORY, + buf = kmalloc(VTX_PAGESIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; - ROW(req->start), + /* Read "normal" part of page */ + err = -EIO; - COLUMN(req->start), + end = min(req->end, VTX_PAGESIZE - 1); + if (i2c_senddata(t, SAA5246A_REGISTER_R8, + req->pgbuf | R8_DO_NOT_CLEAR_MEMORY, + ROW(req->start), COLUMN(req->start), COMMAND_END)) + goto out; + if (i2c_getdata(t, end - req->start + 1, buf)) + goto out; + err = -EFAULT; + if (copy_to_user(req->buffer, buf, end - req->start + 1)) + goto out; - COMMAND_END) || - i2c_getdata(t, end - req->start + 1, req->buffer)) - { - return -EIO; - } /* Always get the time from buffer 4, since this stupid SAA5246A only * updates the currently displayed buffer... */ - if (REQ_CONTAINS_TIME(req)) - { + if (REQ_CONTAINS_TIME(req)) { start = max(req->start, POS_TIME_START); end = min(req->end, POS_TIME_END); + size = end - start + 1; + err = -EINVAL; + if (size < 0) + goto out; + err = -EIO; if (i2c_senddata(t, SAA5246A_REGISTER_R8, - - R8_ACTIVE_CHAPTER_4 | - R8_DO_NOT_CLEAR_MEMORY, - - R9_CURSER_ROW_0, - - start, - - COMMAND_END) || - i2c_getdata(t, end - start + 1, - req->buffer + start - req->start)) - { - return -EIO; - } + R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY, + R9_CURSER_ROW_0, start, COMMAND_END)) + goto out; + if (i2c_getdata(t, size, buf)) + goto out; + err = -EFAULT; + if (copy_to_user(req->buffer + start - req->start, buf, size)) + goto out; } /* Insert the header from buffer 4 only, if acquisition circuit is still searching for a page */ - if (REQ_CONTAINS_HEADER(req) && t->is_searching[req->pgbuf]) - { + if (REQ_CONTAINS_HEADER(req) && t->is_searching[req->pgbuf]) { start = max(req->start, POS_HEADER_START); end = min(req->end, POS_HEADER_END); + size = end - start + 1; + err = -EINVAL; + if (size < 0) + goto out; + err = -EIO; if (i2c_senddata(t, SAA5246A_REGISTER_R8, - - R8_ACTIVE_CHAPTER_4 | - R8_DO_NOT_CLEAR_MEMORY, - - R9_CURSER_ROW_0, - - start, - - COMMAND_END) || - i2c_getdata(t, end - start + 1, - req->buffer + start - req->start)) - { - return -EIO; - } + R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY, + R9_CURSER_ROW_0, start, COMMAND_END)) + goto out; + if (i2c_getdata(t, end - start + 1, buf)) + goto out; + err = -EFAULT; + if (copy_to_user(req->buffer + start - req->start, buf, size)) + goto out; } - - return 0; + err = 0; +out: + kfree(buf); + return err; } /* Stops the acquisition circuit given in dau_no. The page buffer associated --- linux-2.6.8-rc1/drivers/media/video/saa7134/saa7134-oss.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/saa7134/saa7134-oss.c 2004-07-13 17:09:13.000000000 -0700 @@ -281,7 +281,7 @@ static int dsp_release(struct inode *ino return 0; } -static ssize_t dsp_read(struct file *file, char *buffer, +static ssize_t dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct saa7134_dev *dev = file->private_data; @@ -354,7 +354,7 @@ static ssize_t dsp_read(struct file *fil return ret; } -static ssize_t dsp_write(struct file *file, const char *buffer, +static ssize_t dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { return -EINVAL; @@ -364,25 +364,27 @@ static int dsp_ioctl(struct inode *inode unsigned int cmd, unsigned long arg) { struct saa7134_dev *dev = file->private_data; + void __user *argp = (void __user *) arg; + int __user *p = argp; int val = 0; if (oss_debug > 1) saa7134_print_ioctl(dev->name,cmd); switch (cmd) { case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *)arg); + return put_user(SOUND_VERSION, p); case SNDCTL_DSP_GETCAPS: return 0; case SNDCTL_DSP_SPEED: - if (get_user(val, (int*)arg)) + if (get_user(val, p)) return -EFAULT; /* fall through */ case SOUND_PCM_READ_RATE: - return put_user(dev->oss.rate, (int*)arg); + return put_user(dev->oss.rate, p); case SNDCTL_DSP_STEREO: - if (get_user(val, (int*)arg)) + if (get_user(val, p)) return -EFAULT; down(&dev->oss.lock); dev->oss.channels = val ? 2 : 1; @@ -391,10 +393,10 @@ static int dsp_ioctl(struct inode *inode dsp_rec_start(dev); } up(&dev->oss.lock); - return put_user(dev->oss.channels-1, (int *)arg); + return put_user(dev->oss.channels-1, p); case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int*)arg)) + if (get_user(val, p)) return -EFAULT; if (val != 1 && val != 2) return -EINVAL; @@ -407,15 +409,15 @@ static int dsp_ioctl(struct inode *inode up(&dev->oss.lock); /* fall through */ case SOUND_PCM_READ_CHANNELS: - return put_user(dev->oss.channels, (int *)arg); + return put_user(dev->oss.channels, p); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ return put_user(AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE | - AFMT_S16_LE | AFMT_S16_BE, (int*)arg); + AFMT_S16_LE | AFMT_S16_BE, p); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, (int*)arg)) + if (get_user(val, p)) return -EFAULT; switch (val) { case AFMT_QUERY: @@ -434,7 +436,7 @@ static int dsp_ioctl(struct inode *inode dsp_rec_start(dev); } up(&dev->oss.lock); - return put_user(dev->oss.afmt,(int*)arg); + return put_user(dev->oss.afmt, p); default: return -EINVAL; } @@ -443,12 +445,12 @@ static int dsp_ioctl(struct inode *inode switch (dev->oss.afmt) { case AFMT_U8: case AFMT_S8: - return put_user(8, (int*)arg); + return put_user(8, p); case AFMT_U16_LE: case AFMT_U16_BE: case AFMT_S16_LE: case AFMT_S16_BE: - return put_user(16, (int*)arg); + return put_user(16, p); default: return -EINVAL; } @@ -464,15 +466,16 @@ static int dsp_ioctl(struct inode *inode up(&dev->oss.lock); return 0; case SNDCTL_DSP_GETBLKSIZE: - return put_user(dev->oss.blksize,(int*)arg); + return put_user(dev->oss.blksize, p); case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (int*)arg)) + if (get_user(val, p)) return -EFAULT; if (dev->oss.recording_on) return -EBUSY; dsp_buffer_free(dev); - dsp_buffer_conf(dev,1 << (val & 0xffff), (arg >> 16) & 0xffff); + /* used to be arg >> 16 instead of val >> 16; fixed */ + dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff); dsp_buffer_init(dev); return 0; @@ -487,7 +490,7 @@ static int dsp_ioctl(struct inode *inode info.fragstotal = dev->oss.blocks; info.bytes = dev->oss.read_count; info.fragments = info.bytes / info.fragsize; - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; } @@ -648,12 +651,14 @@ static int mixer_ioctl(struct inode *ino struct saa7134_dev *dev = file->private_data; enum saa7134_audio_in input; int val,ret; + void __user *argp = (void __user *) arg; + int __user *p = argp; if (oss_debug > 1) saa7134_print_ioctl(dev->name,cmd); switch (cmd) { case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *)arg); + return put_user(SOUND_VERSION, p); case SOUND_MIXER_INFO: { mixer_info info; @@ -661,7 +666,7 @@ static int mixer_ioctl(struct inode *ino strlcpy(info.id, "TV audio", sizeof(info.id)); strlcpy(info.name, dev->name, sizeof(info.name)); info.modify_counter = dev->oss.count; - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; } @@ -671,23 +676,23 @@ static int mixer_ioctl(struct inode *ino memset(&info,0,sizeof(info)); strlcpy(info.id, "TV audio", sizeof(info.id)); strlcpy(info.name, dev->name, sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; } case MIXER_READ(SOUND_MIXER_CAPS): - return put_user(SOUND_CAP_EXCL_INPUT,(int*)arg); + return put_user(SOUND_CAP_EXCL_INPUT, p); case MIXER_READ(SOUND_MIXER_STEREODEVS): - return put_user(0,(int*)arg); + return put_user(0, p); case MIXER_READ(SOUND_MIXER_RECMASK): case MIXER_READ(SOUND_MIXER_DEVMASK): val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; if (32000 == dev->oss.rate) val |= SOUND_MASK_VIDEO; - return put_user(val,(int*)arg); + return put_user(val, p); case MIXER_WRITE(SOUND_MIXER_RECSRC): - if (get_user(val, (int *)arg)) + if (get_user(val, p)) return -EFAULT; input = dev->oss.input; if (32000 == dev->oss.rate && @@ -707,16 +712,16 @@ static int mixer_ioctl(struct inode *ino case LINE2: ret = SOUND_MASK_LINE2; break; default: ret = 0; } - return put_user(ret,(int*)arg); + return put_user(ret, p); case MIXER_WRITE(SOUND_MIXER_VIDEO): case MIXER_READ(SOUND_MIXER_VIDEO): if (32000 != dev->oss.rate) return -EINVAL; - return put_user(100 | 100 << 8,(int*)arg); + return put_user(100 | 100 << 8, p); case MIXER_WRITE(SOUND_MIXER_LINE1): - if (get_user(val, (int *)arg)) + if (get_user(val, p)) return -EFAULT; val &= 0xff; val = (val <= 50) ? 50 : 100; @@ -724,11 +729,10 @@ static int mixer_ioctl(struct inode *ino mixer_level(dev,LINE1,dev->oss.line1); /* fall throuth */ case MIXER_READ(SOUND_MIXER_LINE1): - return put_user(dev->oss.line1 | dev->oss.line1 << 8, - (int*)arg); + return put_user(dev->oss.line1 | dev->oss.line1 << 8, p); case MIXER_WRITE(SOUND_MIXER_LINE2): - if (get_user(val, (int *)arg)) + if (get_user(val, p)) return -EFAULT; val &= 0xff; val = (val <= 50) ? 50 : 100; @@ -736,8 +740,7 @@ static int mixer_ioctl(struct inode *ino mixer_level(dev,LINE2,dev->oss.line2); /* fall throuth */ case MIXER_READ(SOUND_MIXER_LINE2): - return put_user(dev->oss.line2 | dev->oss.line2 << 8, - (int*)arg); + return put_user(dev->oss.line2 | dev->oss.line2 << 8, p); default: return -EINVAL; --- linux-2.6.8-rc1/drivers/media/video/saa7134/saa7134-ts.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/saa7134/saa7134-ts.c 2004-07-13 17:09:13.000000000 -0700 @@ -241,7 +241,7 @@ static int ts_release(struct inode *inod } static ssize_t -ts_read(struct file *file, char *data, size_t count, loff_t *ppos) +ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7134_dev *dev = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/saa7134/saa7134-video.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/saa7134/saa7134-video.c 2004-07-13 17:09:13.000000000 -0700 @@ -1238,7 +1238,7 @@ static int video_open(struct inode *inod } static ssize_t -video_read(struct file *file, char *data, size_t count, loff_t *ppos) +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct saa7134_fh *fh = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/stradis.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/media/video/stradis.c 2004-07-13 17:09:13.000000000 -0700 @@ -1322,7 +1322,7 @@ static int saa_ioctl(struct inode *inode unsigned int cmd, unsigned long argl) { struct saa7146 *saa = file->private_data; - void *arg = (void *)argl; + void __user *arg = (void __user *)argl; switch (cmd) { case VIDIOCGCAP: @@ -1580,7 +1580,7 @@ static int saa_ioctl(struct inode *inode vu.radio = VIDEO_NO_UNIT; vu.audio = VIDEO_NO_UNIT; vu.teletext = VIDEO_NO_UNIT; - if (copy_to_user((void *) arg, (void *) &vu, sizeof(vu))) + if (copy_to_user(arg, &vu, sizeof(vu))) return -EFAULT; return 0; } @@ -1754,16 +1754,14 @@ static int saa_ioctl(struct inode *inode struct video_code ucode; __u8 *udata; int i; - if (copy_from_user((void *) &ucode, arg, - sizeof(ucode))) + if (copy_from_user(&ucode, arg, sizeof(ucode))) return -EFAULT; if (ucode.datasize > 65536 || ucode.datasize < 1024 || strncmp(ucode.loadwhat, "dec", 3)) return -EINVAL; if ((udata = vmalloc(ucode.datasize)) == NULL) return -ENOMEM; - if (copy_from_user((void *) udata, ucode.data, - ucode.datasize)) { + if (copy_from_user(udata, ucode.data, ucode.datasize)) { vfree(udata); return -EFAULT; } @@ -1814,13 +1812,13 @@ static int saa_mmap(struct file *file, s return -EINVAL; } -static ssize_t saa_read(struct file *file, char *buf, +static ssize_t saa_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return -EINVAL; } -static ssize_t saa_write(struct file *file, const char *buf, +static ssize_t saa_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct saa7146 *saa = file->private_data; --- linux-2.6.8-rc1/drivers/media/video/tea6415c.c 2003-10-25 14:45:45.000000000 -0700 +++ 25/drivers/media/video/tea6415c.c 2004-07-13 17:35:11.000000000 -0700 @@ -57,7 +57,7 @@ static int tea6415c_id = 0; /* this function is called by i2c_probe */ static int tea6415c_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *client = 0; + struct i2c_client *client = NULL; int err = 0; /* let's see whether this adapter can support what we need */ @@ -217,13 +217,12 @@ static struct i2c_driver driver = { .command = tea6415c_command, }; -static int tea6415c_init_module(void) +static int __init tea6415c_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tea6415c_cleanup_module(void) +static void __exit tea6415c_cleanup_module(void) { i2c_del_driver(&driver); } --- linux-2.6.8-rc1/drivers/media/video/tea6420.c 2003-10-25 14:45:45.000000000 -0700 +++ 25/drivers/media/video/tea6420.c 2004-07-13 17:35:11.000000000 -0700 @@ -197,13 +197,12 @@ static struct i2c_driver driver = { .command = tea6420_command, }; -static int tea6420_init_module(void) +static int __init tea6420_init_module(void) { - i2c_add_driver(&driver); - return 0; + return i2c_add_driver(&driver); } -static void tea6420_cleanup_module(void) +static void __exit tea6420_cleanup_module(void) { i2c_del_driver(&driver); } --- linux-2.6.8-rc1/drivers/media/video/tvmixer.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/video/tvmixer.c 2004-07-13 17:09:13.000000000 -0700 @@ -77,6 +77,8 @@ static int tvmixer_ioctl(struct inode *i int left,right,ret,val = 0; struct TVMIXER *mix = file->private_data; struct i2c_client *client = mix->dev; + void __user *argp = (void __user *)arg; + int __user *p = argp; if (NULL == client) return -ENODEV; @@ -86,7 +88,7 @@ static int tvmixer_ioctl(struct inode *i strlcpy(info.id, "tv card", sizeof(info.id)); strlcpy(info.name, i2c_clientname(client), sizeof(info.name)); info.modify_counter = 42 /* FIXME */; - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; } @@ -94,15 +96,15 @@ static int tvmixer_ioctl(struct inode *i _old_mixer_info info; strlcpy(info.id, "tv card", sizeof(info.id)); strlcpy(info.name, i2c_clientname(client), sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *)arg); + return put_user(SOUND_VERSION, p); if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (get_user(val, (int *)arg)) + if (get_user(val, p)) return -EFAULT; /* read state */ @@ -168,7 +170,7 @@ static int tvmixer_ioctl(struct inode *i default: return -EINVAL; } - if (put_user(ret, (int *)arg)) + if (put_user(ret, p)) return -EFAULT; return 0; } --- linux-2.6.8-rc1/drivers/media/video/v4l1-compat.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/media/video/v4l1-compat.c 2004-07-13 17:09:13.412233904 -0700 @@ -490,7 +490,7 @@ v4l_compat_translate_ioctl(struct inode fmt2->fmt.win.w.width = win->width; fmt2->fmt.win.w.height = win->height; fmt2->fmt.win.chromakey = win->chromakey; - fmt2->fmt.win.clips = (void *)win->clips; + fmt2->fmt.win.clips = (void __user *)win->clips; fmt2->fmt.win.clipcount = win->clipcount; err2 = drv(inode, file, VIDIOC_S_FMT, fmt2); if (err2 < 0) --- linux-2.6.8-rc1/drivers/media/video/video-buf.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/media/video/video-buf.c 2004-07-13 17:09:13.000000000 -0700 @@ -735,7 +735,7 @@ int videobuf_streamoff(struct file *file static ssize_t videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q, - char *data, size_t count, loff_t *ppos) + char __user *data, size_t count, loff_t *ppos) { enum v4l2_field field; unsigned long flags; @@ -777,7 +777,7 @@ videobuf_read_zerocopy(struct file *file } ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, - char *data, size_t count, loff_t *ppos) + char __user *data, size_t count, loff_t *ppos) { enum v4l2_field field; unsigned long flags; @@ -901,7 +901,7 @@ void videobuf_read_stop(struct file *fil } ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, - char *data, size_t count, loff_t *ppos, + char __user *data, size_t count, loff_t *ppos, int vbihack) { unsigned int *fc, bytes; --- linux-2.6.8-rc1/drivers/media/video/videocodec.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/media/video/videocodec.c 2004-07-13 17:09:13.000000000 -0700 @@ -458,7 +458,7 @@ videocodec_init (void) videocodec_buf = NULL; videocodec_bufsize = 0; - videocodec_proc_entry = create_proc_entry("videocodecs", 0, 0); + videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL); if (videocodec_proc_entry) { videocodec_proc_entry->read_proc = videocodec_info; videocodec_proc_entry->write_proc = NULL; @@ -475,7 +475,7 @@ static void __exit videocodec_exit (void) { #ifdef CONFIG_PROC_FS - remove_proc_entry("videocodecs", 0); + remove_proc_entry("videocodecs", NULL); if (videocodec_buf) kfree(videocodec_buf); #endif --- linux-2.6.8-rc1/drivers/media/video/videodev.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/media/video/videodev.c 2004-07-13 17:09:55.000000000 -0700 @@ -183,7 +183,7 @@ video_usercopy(struct inode *inode, stru /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: - parg = (void *)arg; + parg = NULL; break; case _IOC_READ: case _IOC_WRITE: @@ -200,7 +200,7 @@ video_usercopy(struct inode *inode, stru err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) - if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) goto out; break; } @@ -217,7 +217,7 @@ video_usercopy(struct inode *inode, stru { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) err = -EFAULT; break; } @@ -231,7 +231,7 @@ out: /* * open/release helper functions -- handle exclusive opens */ -extern int video_exclusive_open(struct inode *inode, struct file *file) +int video_exclusive_open(struct inode *inode, struct file *file) { struct video_device *vfl = video_devdata(file); int retval = 0; @@ -246,7 +246,7 @@ extern int video_exclusive_open(struct i return retval; } -extern int video_exclusive_release(struct inode *inode, struct file *file) +int video_exclusive_release(struct inode *inode, struct file *file) { struct video_device *vfl = video_devdata(file); @@ -254,7 +254,7 @@ extern int video_exclusive_release(struc return 0; } -extern struct file_operations video_fops; +static struct file_operations video_fops; /** * video_register_device - register video4linux devices --- linux-2.6.8-rc1/drivers/media/video/w9966.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/media/video/w9966.c 2004-07-13 17:09:13.000000000 -0700 @@ -179,7 +179,7 @@ static int w9966_i2c_rbyte(struct w9966_ static int w9966_v4l_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static ssize_t w9966_v4l_read(struct file *file, char *buf, +static ssize_t w9966_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static struct file_operations w9966_fops = { @@ -555,6 +555,14 @@ static inline void w9966_i2c_setsda(stru udelay(5); } +// Get peripheral clock line +// Expects a claimed pdev. +static inline int w9966_i2c_getscl(struct w9966_dev* cam) +{ + const unsigned char state = w9966_rReg(cam, 0x18); + return ((state & W9966_I2C_R_CLOCK) > 0); +} + // Sets the clock line on the i2c bus. // Expects a claimed pdev. -1 on error static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state) @@ -588,14 +596,6 @@ static inline int w9966_i2c_getsda(struc return ((state & W9966_I2C_R_DATA) > 0); } -// Get peripheral clock line -// Expects a claimed pdev. -static inline int w9966_i2c_getscl(struct w9966_dev* cam) -{ - const unsigned char state = w9966_rReg(cam, 0x18); - return ((state & W9966_I2C_R_CLOCK) > 0); -} - // Write a byte with ack to the i2c bus. // Expects a claimed pdev. -1 on error static int w9966_i2c_wbyte(struct w9966_dev* cam, int data) @@ -867,13 +867,13 @@ static int w9966_v4l_ioctl(struct inode } // Capture data -static ssize_t w9966_v4l_read(struct file *file, char *buf, +static ssize_t w9966_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *vdev = video_devdata(file); struct w9966_dev *cam = (struct w9966_dev *)vdev->priv; unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 - unsigned char* dest = (unsigned char*)buf; + unsigned char __user *dest = (unsigned char __user *)buf; unsigned long dleft = count; unsigned char *tbuf; --- linux-2.6.8-rc1/drivers/media/video/zoran_driver.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/media/video/zoran_driver.c 2004-07-13 17:09:13.000000000 -0700 @@ -424,17 +424,15 @@ v4l_fbuffer_alloc (struct file *file) ZR_DEVNAME(zr), size >> 10); return -ENOBUFS; } - fh->v4l_buffers.buffer[0].fbuffer = 0; - fh->v4l_buffers.buffer[0].fbuffer_phys = - pmem; - fh->v4l_buffers.buffer[0].fbuffer_bus = - pmem; + fh->v4l_buffers.buffer[0].fbuffer = NULL; + fh->v4l_buffers.buffer[0].fbuffer_phys = pmem; + fh->v4l_buffers.buffer[0].fbuffer_bus = pmem; dprintk(4, KERN_INFO "%s: v4l_fbuffer_alloc() - using %d KB high memory\n", ZR_DEVNAME(zr), size >> 10); } else { - fh->v4l_buffers.buffer[i].fbuffer = 0; + fh->v4l_buffers.buffer[i].fbuffer = NULL; fh->v4l_buffers.buffer[i].fbuffer_phys = pmem + i * fh->v4l_buffers.buffer_size; fh->v4l_buffers.buffer[i].fbuffer_bus = @@ -1472,7 +1470,7 @@ zoran_close (struct inode *inode, static ssize_t zoran_read (struct file *file, - char *data, + char __user *data, size_t count, loff_t *ppos) { @@ -1483,7 +1481,7 @@ zoran_read (struct file *file, static ssize_t zoran_write (struct file *file, - const char *data, + const char __user *data, size_t count, loff_t *ppos) { @@ -1569,9 +1567,9 @@ setup_window (struct file *file, int y, int width, int height, - struct video_clip *clips, + struct video_clip __user *clips, int clipcount, - void *bitmap) + void __user *bitmap) { struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; @@ -2873,7 +2871,7 @@ zoran_do_ioctl (struct inode *inode, fmt->fmt.win.w.top, fmt->fmt.win.w.width, fmt->fmt.win.w.height, - (struct video_clip *) + (struct video_clip __user *) fmt->fmt.win.clips, fmt->fmt.win.clipcount, fmt->fmt.win.bitmap); --- linux-2.6.8-rc1/drivers/media/video/zoran_procfs.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/media/video/zoran_procfs.c 2004-07-13 17:09:13.000000000 -0700 @@ -196,7 +196,7 @@ zoran_read_proc (char *buffer, static int zoran_write_proc (struct file *file, - const char *buffer, + const char __user *buffer, unsigned long count, void *data) { @@ -252,7 +252,7 @@ zoran_proc_init (struct zoran *zr) char name[8]; snprintf(name, 7, "zoran%d", zr->id); - if ((zr->zoran_proc = create_proc_entry(name, 0, 0))) { + if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) { zr->zoran_proc->read_proc = zoran_read_proc; zr->zoran_proc->write_proc = zoran_write_proc; zr->zoran_proc->data = zr; @@ -278,7 +278,7 @@ zoran_proc_cleanup (struct zoran *zr) snprintf(name, 7, "zoran%d", zr->id); if (zr->zoran_proc) { - remove_proc_entry(name, 0); + remove_proc_entry(name, NULL); } zr->zoran_proc = NULL; #endif --- linux-2.6.8-rc1/drivers/message/fusion/mptbase.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/fusion/mptbase.c 2004-07-13 17:09:24.000000000 -0700 @@ -1337,7 +1337,6 @@ mptbase_probe(struct pci_dev *pdev, cons printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", ioc->name, __irq_itoa(pdev->irq)); #endif - Q_DEL_ITEM(ioc); list_del(&ioc->list); iounmap(mem); kfree(ioc); @@ -1369,7 +1368,6 @@ mptbase_probe(struct pci_dev *pdev, cons ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); - Q_DEL_ITEM(ioc); list_del(&ioc->list); free_irq(ioc->pci_irq, ioc); iounmap(mem); @@ -2416,7 +2414,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF } } else { printk(MYIOC_s_ERR_FMT - "Invalid IOC facts reply, msgLength=%d offsetof=%d!\n", + "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32))); return -66; --- linux-2.6.8-rc1/drivers/message/fusion/mptbase.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/fusion/mptbase.h 2004-07-13 17:09:24.000000000 -0700 @@ -85,8 +85,8 @@ #define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.01.09" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.09" +#define MPT_LINUX_VERSION_COMMON "3.01.10" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.10" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -523,6 +523,7 @@ typedef struct _MPT_IOCTL { u8 target; /* target for reset */ void *tmPtr; struct timer_list TMtimer; /* timer function for this adapter */ + struct semaphore sem_ioc; } MPT_IOCTL; /* @@ -676,6 +677,7 @@ typedef struct _MPT_ADAPTER u8 reload_fw; /* Force a FW Reload on next reset */ u8 pad1[5]; struct list_head list; + struct net_device *netdev; } MPT_ADAPTER; --- linux-2.6.8-rc1/drivers/message/fusion/mptctl.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/fusion/mptctl.c 2004-07-13 17:09:24.000000000 -0700 @@ -111,7 +111,6 @@ MODULE_LICENSE("GPL"); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mptctl_id = -1; -static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS]; static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); @@ -140,6 +139,9 @@ static int mptctl_do_reset(unsigned long static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); static int mptctl_hp_targetinfo(unsigned long arg); +static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); +static void mptctl_remove(struct pci_dev *); + /* * Private function calls. */ @@ -208,10 +210,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in } if (nonblock) { - if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id])) + if (down_trylock(&ioc->ioctl->sem_ioc)) rc = -EAGAIN; } else { - if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + if (down_interruptible(&ioc->ioctl->sem_ioc)) rc = -ERESTARTSYS; } dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); @@ -630,8 +632,7 @@ mptctl_ioctl(struct inode *inode, struct else ret = -EINVAL; - - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -2738,7 +2739,7 @@ compat_mptfwxfer_ioctl(unsigned int fd, ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } @@ -2792,55 +2793,91 @@ compat_mpt_command(unsigned int fd, unsi */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - up(&mptctl_syscall_sem_ioc[iocp->id]); + up(&iocp->ioctl->sem_ioc); return ret; } #endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int __init mptctl_init(void) +/* + * mptctl_probe - Installs ioctl devices per bus. + * @pdev: Pointer to pci_dev structure + * + * Returns 0 for success, non-zero for failure. + * + */ + +static int +mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; - int i; - int where = 1; int sz; u8 *mem; - MPT_ADAPTER *ioc = NULL; - int iocnum; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - show_mptmod_ver(my_NAME, my_VERSION); + /* + * Allocate and inite a MPT_IOCTL structure + */ + sz = sizeof (MPT_IOCTL); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) { + err = -ENOMEM; + goto out_fail; + } - for (i=0; iioctl = (MPT_IOCTL *) mem; + ioc->ioctl->ioc = ioc; + init_timer (&ioc->ioctl->timer); + ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->timer.function = mptctl_timer_expired; + init_timer (&ioc->ioctl->TMtimer); + ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; + ioc->ioctl->TMtimer.function = mptctl_timer_expired; + sema_init(&ioc->ioctl->sem_ioc, 1); + return 0; - ioc = NULL; - if (((iocnum = mpt_verify_adapter(i, &ioc)) < 0) || - (ioc == NULL)) { - continue; - } - else { - /* This adapter instance is found. - * Allocate and inite a MPT_IOCTL structure - */ - sz = sizeof (MPT_IOCTL); - mem = kmalloc(sz, GFP_KERNEL); - if (mem == NULL) { - err = -ENOMEM; - goto out_fail; - } - - memset(mem, 0, sz); - ioc->ioctl = (MPT_IOCTL *) mem; - ioc->ioctl->ioc = ioc; - init_timer (&ioc->ioctl->timer); - ioc->ioctl->timer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->timer.function = mptctl_timer_expired; - init_timer (&ioc->ioctl->TMtimer); - ioc->ioctl->TMtimer.data = (unsigned long) ioc->ioctl; - ioc->ioctl->TMtimer.function = mptctl_timer_expired; - } +out_fail: + + mptctl_remove(pdev); + return err; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptctl_remove - Removed ioctl devices + * @pdev: Pointer to pci_dev structure + * + * + */ +static void +mptctl_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + kfree ( ioc->ioctl ); +} + +static struct mpt_pci_driver mptctl_driver = { + .probe = mptctl_probe, + .remove = mptctl_remove, +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init mptctl_init(void) +{ + int err; + int where = 1; + + show_mptmod_ver(my_NAME, my_VERSION); + + if(mpt_device_driver_register(&mptctl_driver, + MPTCTL_DRIVER) != 0 ) { + dprintk((KERN_INFO MYNAM + ": failed to register dd callbacks\n")); } #ifdef CONFIG_COMPAT @@ -2922,29 +2959,14 @@ out_fail: unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } + mpt_device_driver_deregister(MPTCTL_DRIVER); + return err; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ void mptctl_exit(void) { - int i; - MPT_ADAPTER *ioc; - int iocnum; - misc_deregister(&mptctl_miscdev); printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); @@ -2957,6 +2979,8 @@ void mptctl_exit(void) mpt_deregister(mptctl_id); printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + mpt_device_driver_deregister(MPTCTL_DRIVER); + #ifdef CONFIG_COMPAT unregister_ioctl32_conversion(MPTIOCINFO); unregister_ioctl32_conversion(MPTIOCINFO1); @@ -2973,20 +2997,6 @@ void mptctl_exit(void) unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif - /* Free allocated memory */ - for (i=0; iioctl) { - kfree ( ioc->ioctl ); - ioc->ioctl = NULL; - } - } - } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ --- linux-2.6.8-rc1/drivers/message/fusion/mptlan.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/fusion/mptlan.c 2004-07-13 17:09:24.000000000 -0700 @@ -177,11 +177,9 @@ static int LanCtx = -1; static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; -static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; - #ifdef QLOGIC_NAA_WORKAROUND static struct NAA_Hosed *mpt_bad_naa = NULL; -rwlock_t bad_naa_lock; +rwlock_t bad_naa_lock = RW_LOCK_UNLOCKED; #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -203,7 +201,7 @@ extern int mpt_lan_index; static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; int FreeReqFrame = 0; dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", @@ -336,7 +334,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_H static int mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - struct net_device *dev = mpt_landev[ioc->id]; + struct net_device *dev = ioc->netdev; struct mpt_lan_priv *priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", @@ -1451,20 +1449,74 @@ mpt_register_lan_device (MPT_ADAPTER *mp return dev; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int __init mpt_lan_init (void) +static int +mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct net_device *dev; - MPT_ADAPTER *p; - int i, j; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev; + int i; + + for (i = 0; i < ioc->facts.NumberOfPorts; i++) { + printk(KERN_INFO MYNAM ": %s: PortNum=%x, " + "ProtocolFlags=%02Xh (%c%c%c%c)\n", + ioc->name, ioc->pfacts[i].PortNumber, + ioc->pfacts[i].ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c( + ioc->pfacts[i].ProtocolFlags)); + + if (!(ioc->pfacts[i].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN)) { + printk(KERN_INFO MYNAM ": %s: Hmmm... LAN protocol " + "seems to be disabled on this adapter port!\n", + ioc->name); + continue; + } - show_mptmod_ver(LANAME, LANVER); + dev = mpt_register_lan_device(ioc, i); + if (!dev) { + printk(KERN_ERR MYNAM ": %s: Unable to register " + "port%d as a LAN device\n", ioc->name, + ioc->pfacts[i].PortNumber); + continue; + } + + printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " + "registered as '%s'\n", ioc->name, dev->name); + printk(KERN_INFO MYNAM ": %s/%s: " + "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + ioc->netdev = dev; -#ifdef QLOGIC_NAA_WORKAROUND - /* Init the global r/w lock for the bad_naa list. We want to do this - before any boards are initialized and may be used. */ - rwlock_init(&bad_naa_lock); -#endif + return 0; + } + + return -ENODEV; +} + +static void +mptlan_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct net_device *dev = ioc->netdev; + + if(dev != NULL) { + unregister_netdev(dev); + free_netdev(dev); + } +} + +static struct mpt_pci_driver mptlan_driver = { + .probe = mptlan_probe, + .remove = mptlan_remove, +}; + +static int __init mpt_lan_init (void) +{ + show_mptmod_ver(LANAME, LANVER); if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); @@ -1476,88 +1528,32 @@ static int __init mpt_lan_init (void) dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); - if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset) == 0) { - dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); - } else { + if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) { printk(KERN_ERR MYNAM ": Eieee! unable to register a reset " "handler with mptbase! The world is at an end! " "Everything is fading to black! Goodbye.\n"); return -EBUSY; } - for (j = 0; j < MPT_MAX_ADAPTERS; j++) { - mpt_landev[j] = NULL; - } - - list_for_each_entry(p, &ioc_list, list) { - for (i = 0; i < p->facts.NumberOfPorts; i++) { - printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", - p->name, - p->pfacts[i].PortNumber, - p->pfacts[i].ProtocolFlags, - MPT_PROTOCOL_FLAGS_c_c_c_c(p->pfacts[i].ProtocolFlags)); - - if (!(p->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { - printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", - p->name); - continue; - } - - dev = mpt_register_lan_device (p, i); - if (!dev) { - printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", - p->name, - p->pfacts[i].PortNumber); - } - printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", - p->name, dev->name); - printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); -// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", -// IOC_AND_NETDEV_NAMES_s_s(dev), -// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); - j = p->id; - mpt_landev[j] = dev; - dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", - dev, j, mpt_landev[j])); - - } - } - + dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n")); + + if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER)) + dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n")); return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static void __exit mpt_lan_exit(void) { - int i; - + mpt_device_driver_deregister(MPTLAN_DRIVER); mpt_reset_deregister(LanCtx); - for (i = 0; mpt_landev[i] != NULL; i++) { - struct net_device *dev = mpt_landev[i]; - - printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n", - IOC_AND_NETDEV_NAMES_s_s(dev)); - unregister_netdev(dev); - free_netdev(dev); - mpt_landev[i] = NULL; - } - if (LanCtx >= 0) { mpt_deregister(LanCtx); LanCtx = -1; mpt_lan_index = 0; } - - /* deregister any send/receive handler structs. I2Oism? */ } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - module_init(mpt_lan_init); module_exit(mpt_lan_exit); --- linux-2.6.8-rc1/drivers/message/fusion/mptscsih.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/fusion/mptscsih.c 2004-07-13 17:09:24.000000000 -0700 @@ -99,7 +99,7 @@ MODULE_LICENSE("GPL"); /* Set string for command line args from insmod */ #ifdef MODULE -char *mptscsih = 0; +char *mptscsih = NULL; #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3058,19 +3058,14 @@ mptscsih_bios_param(struct scsi_device * int heads; int sectors; sector_t cylinders; -#ifdef CONFIG_LBD ulong dummy; -#endif heads = 64; sectors = 32; -#ifdef CONFIG_LBD + dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif /* * Handle extended translation size for logical drives @@ -3079,13 +3074,9 @@ mptscsih_bios_param(struct scsi_device * if ((ulong)capacity >= 0x200000) { heads = 255; sectors = 63; -#ifdef CONFIG_LBD dummy = heads * sectors; cylinders = capacity; sector_div(cylinders,dummy); -#else - cylinders = (ulong)capacity / (heads * sectors); -#endif } /* return result */ --- linux-2.6.8-rc1/drivers/message/i2o/i2o_config.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/message/i2o/i2o_config.c 2004-07-13 17:09:13.000000000 -0700 @@ -857,7 +857,7 @@ static int ioctl_passthru(unsigned long u32 sg_count = 0; int sg_index = 0; u32 i = 0; - void *p = 0; + void *p = NULL; unsigned int iop; if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg)) --- linux-2.6.8-rc1/drivers/message/i2o/i2o_proc.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/message/i2o/i2o_proc.c 2004-07-13 17:09:13.000000000 -0700 @@ -3337,7 +3337,7 @@ static int create_i2o_procfs(void) struct i2o_controller *pctrl = NULL; int i; - i2o_proc_dir_root = proc_mkdir("i2o", 0); + i2o_proc_dir_root = proc_mkdir("i2o", NULL); if(!i2o_proc_dir_root) return -1; i2o_proc_dir_root->owner = THIS_MODULE; @@ -3371,7 +3371,7 @@ static int __exit destroy_i2o_procfs(voi } if(!atomic_read(&i2o_proc_dir_root->count)) - remove_proc_entry("i2o", 0); + remove_proc_entry("i2o", NULL); else return -1; --- linux-2.6.8-rc1/drivers/net/3c59x.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/3c59x.c 2004-07-13 17:35:09.000000000 -0700 @@ -568,7 +568,7 @@ static struct vortex_chip_info { {"3c920B-EMB-WNM Tornado", PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, - {0,}, /* 0 terminated list. */ + {NULL,}, /* NULL terminated list. */ }; @@ -1695,7 +1695,7 @@ vortex_up(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ vp->rx_ring[i].status = 0; for (i = 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] = 0; + vp->tx_skbuff[i] = NULL; outl(0, ioaddr + DownListPtr); } /* Set receiver mode: presumably accept b-case and phys addr only. */ @@ -1760,7 +1760,7 @@ vortex_open(struct net_device *dev) for (j = 0; j < i; j++) { if (vp->rx_skbuff[j]) { dev_kfree_skb(vp->rx_skbuff[j]); - vp->rx_skbuff[j] = 0; + vp->rx_skbuff[j] = NULL; } } retval = -ENOMEM; @@ -1938,9 +1938,9 @@ static void vortex_tx_timeout(struct net unsigned long flags; local_irq_save(flags); if (vp->full_bus_master_tx) - boomerang_interrupt(dev->irq, dev, 0); + boomerang_interrupt(dev->irq, dev, NULL); else - vortex_interrupt(dev->irq, dev, 0); + vortex_interrupt(dev->irq, dev, NULL); local_irq_restore(flags); } } @@ -2419,7 +2419,7 @@ boomerang_interrupt(int irq, void *dev_i le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); #endif dev_kfree_skb_irq(skb); - vp->tx_skbuff[entry] = 0; + vp->tx_skbuff[entry] = NULL; } else { printk(KERN_DEBUG "boomerang_interrupt: no skb!\n"); } @@ -2724,7 +2724,7 @@ vortex_close(struct net_device *dev) pci_unmap_single( VORTEX_PCI(vp), le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); dev_kfree_skb(vp->rx_skbuff[i]); - vp->rx_skbuff[i] = 0; + vp->rx_skbuff[i] = NULL; } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ @@ -2743,7 +2743,7 @@ vortex_close(struct net_device *dev) pci_unmap_single(VORTEX_PCI(vp), le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); #endif dev_kfree_skb(skb); - vp->tx_skbuff[i] = 0; + vp->tx_skbuff[i] = NULL; } } } --- linux-2.6.8-rc1/drivers/net/appletalk/ltpc.c 2004-02-17 20:48:43.000000000 -0800 +++ 25/drivers/net/appletalk/ltpc.c 2004-07-13 17:09:13.000000000 -0700 @@ -501,7 +501,7 @@ static void idle(struct net_device *dev) /* FIXME This is initialized to shut the warning up, but I need to * think this through again. */ - struct xmitQel *q=0; + struct xmitQel *q = NULL; int oops; int i; int base = dev->base_addr; @@ -1203,7 +1203,7 @@ struct net_device * __init ltpc_probe(vo if (err) goto out4; - return 0; + return NULL; out4: del_timer_sync(<pc_timer); if (dev->irq) --- linux-2.6.8-rc1/drivers/net/dgrs.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/net/dgrs.c 2004-07-13 17:09:13.000000000 -0700 @@ -1311,8 +1311,8 @@ dgrs_found_device( *privN = *priv; /* ... and zero out VM areas */ - privN->vmem = 0; - privN->vplxdma = 0; + privN->vmem = NULL; + privN->vplxdma = NULL; /* ... and zero out IRQ */ devN->irq = 0; /* ... and base MAC address off address of 1st port */ --- linux-2.6.8-rc1/drivers/net/e1000/e1000_main.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/e1000/e1000_main.c 2004-07-13 17:09:33.000000000 -0700 @@ -2865,6 +2865,8 @@ e1000_suspend(struct pci_dev *pdev, uint } } + pci_disable_device(pdev); + state = (state > 0) ? 3 : 0; pci_set_power_state(pdev, state); @@ -2879,6 +2881,7 @@ e1000_resume(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev->priv; uint32_t manc; + pci_enable_device(pdev); pci_set_power_state(pdev, 0); pci_restore_state(pdev, adapter->pci_state); --- linux-2.6.8-rc1/drivers/net/e100.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/e100.c 2004-07-13 17:09:23.000000000 -0700 @@ -87,9 +87,8 @@ * cb_to_use is the next CB to use for queuing a command; cb_to_clean * is the next CB to check for completion; cb_to_send is the first * CB to start on in case of a previous failure to resume. CB clean - * up happens in interrupt context in response to a CU interrupt, or - * in dev->poll in the case where NAPI is enabled. cbs_avail keeps - * track of number of free CB resources available. + * up happens in interrupt context in response to a CU interrupt. + * cbs_avail keeps track of number of free CB resources available. * * Hardware padding of short packets to minimum packet size is * enabled. 82557 pads with 7Eh, while the later controllers pad @@ -112,9 +111,8 @@ * replacement RFDs cannot be allocated, or the RU goes non-active, * the RU must be restarted. Frame arrival generates an interrupt, * and Rx indication and re-allocation happen in the same context, - * therefore no locking is required. If NAPI is enabled, this work - * happens in dev->poll. A software-generated interrupt is gen- - * erated from the watchdog to recover from a failed allocation + * therefore no locking is required. A software-generated interrupt + * is generated from the watchdog to recover from a failed allocation * senario where all Rx resources have been indicated and none re- * placed. * @@ -126,8 +124,6 @@ * supported. Tx Scatter/Gather is not supported. Jumbo Frames is * not supported (hardware limitation). * - * NAPI support is enabled with CONFIG_E100_NAPI. - * * MagicPacket(tm) WoL support is enabled/disabled via ethtool. * * Thanks to JC (jchapman@katalix.com) for helping with @@ -158,7 +154,7 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.18" +#define DRV_VERSION "3.0.22-NAPI" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -1463,11 +1459,7 @@ static inline int e100_rx_indicate(struc nic->net_stats.rx_packets++; nic->net_stats.rx_bytes += actual_size; nic->netdev->last_rx = jiffies; -#ifdef CONFIG_E100_NAPI netif_receive_skb(skb); -#else - netif_rx(skb); -#endif if(work_done) (*work_done)++; } @@ -1562,20 +1554,12 @@ static irqreturn_t e100_intr(int irq, vo if(stat_ack & stat_ack_rnr) nic->ru_running = 0; -#ifdef CONFIG_E100_NAPI e100_disable_irq(nic); netif_rx_schedule(netdev); -#else - if(stat_ack & stat_ack_rx) - e100_rx_clean(nic, NULL, 0); - if(stat_ack & stat_ack_tx) - e100_tx_clean(nic); -#endif return IRQ_HANDLED; } -#ifdef CONFIG_E100_NAPI static int e100_poll(struct net_device *netdev, int *budget) { struct nic *nic = netdev_priv(netdev); @@ -1598,7 +1582,6 @@ static int e100_poll(struct net_device * return 1; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER static void e100_netpoll(struct net_device *netdev) @@ -2135,10 +2118,8 @@ static int __devinit e100_probe(struct p SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; -#ifdef CONFIG_E100_NAPI netdev->poll = e100_poll; netdev->weight = E100_NAPI_WEIGHT; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif --- linux-2.6.8-rc1/drivers/net/epic100.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/epic100.c 2004-07-13 17:09:23.000000000 -0700 @@ -80,8 +80,6 @@ These may be modified when a driver module is loaded.*/ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 32; /* Used to pass the full-duplex flag, etc. */ #define MAX_UNITS 8 /* More are supported, limit only on options */ @@ -99,9 +97,9 @@ static int rx_copybreak; Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 32 +#define TX_RING_SIZE 256 +#define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 256 #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) @@ -152,12 +150,10 @@ MODULE_DESCRIPTION("SMC 83c170 EPIC seri MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)"); -MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt"); MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex"); MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)"); @@ -289,6 +285,12 @@ enum CommandBits { StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, }; +#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */ + +#define EpicNapiEvent (TxEmpty | TxDone | \ + RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) +#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) + static u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -327,9 +329,12 @@ struct epic_private { /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ + spinlock_t napi_lock; + unsigned int reschedule_in_poll; unsigned int cur_tx, dirty_tx; unsigned int cur_rx, dirty_rx; + u32 irq_mask; unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct pci_dev *pci_dev; /* PCI bus location. */ @@ -356,7 +361,8 @@ static void epic_timer(unsigned long dat static void epic_tx_timeout(struct net_device *dev); static void epic_init_ring(struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int epic_rx(struct net_device *dev); +static int epic_rx(struct net_device *dev, int budget); +static int epic_poll(struct net_device *dev, int *budget); static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; @@ -375,7 +381,7 @@ static int __devinit epic_init_one (stru int irq; struct net_device *dev; struct epic_private *ep; - int i, option = 0, duplex = 0; + int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; @@ -389,29 +395,33 @@ static int __devinit epic_init_one (stru card_idx++; - i = pci_enable_device(pdev); - if (i) - return i; + ret = pci_enable_device(pdev); + if (ret) + goto out; irq = pdev->irq; if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); - return -ENODEV; + ret = -ENODEV; + goto err_out_disable; } pci_set_master(pdev); + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_out_disable; + + ret = -ENOMEM; + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); - return -ENOMEM; + goto err_out_free_res; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_free_netdev; - #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); #else @@ -419,7 +429,7 @@ static int __devinit epic_init_one (stru ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); - goto err_out_free_res; + goto err_out_free_netdev; } #endif @@ -456,7 +466,9 @@ static int __devinit epic_init_one (stru dev->base_addr = ioaddr; dev->irq = irq; - spin_lock_init (&ep->lock); + spin_lock_init(&ep->lock); + spin_lock_init(&ep->napi_lock); + ep->reschedule_in_poll = 0; /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); @@ -486,6 +498,9 @@ static int __devinit epic_init_one (stru ep->pci_dev = pdev; ep->chip_id = chip_idx; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + ep->irq_mask = + (ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) + | CntFull | TxUnderrun | EpicNapiEvent; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but @@ -540,10 +555,12 @@ static int __devinit epic_init_one (stru dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + dev->poll = epic_poll; + dev->weight = 64; - i = register_netdev(dev); - if (i) - goto err_out_unmap_tx; + ret = register_netdev(dev); + if (ret < 0) + goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); @@ -551,19 +568,24 @@ static int __devinit epic_init_one (stru printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]); - return 0; +out: + return ret; +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); err_out_iounmap: #ifndef USE_IO_OPS iounmap(ioaddr); -err_out_free_res: -#endif - pci_release_regions(pdev); err_out_free_netdev: +#endif free_netdev(dev); - return -ENODEV; +err_out_free_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + goto out; } /* Serial EEPROM section. */ @@ -589,6 +611,38 @@ err_out_free_netdev: #define EE_READ256_CMD (6 << 8) #define EE_ERASE_CMD (7 << 6) +static void epic_disable_int(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(0x00000000, ioaddr + INTMASK); +} + +static inline void __epic_pci_commit(long ioaddr) +{ +#ifndef USE_IO_OPS + inl(ioaddr + INTMASK); +#endif +} + +static inline void epic_napi_irq_off(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK); + __epic_pci_commit(ioaddr); +} + +static inline void epic_napi_irq_on(struct net_device *dev, + struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + + /* No need to commit possible posted write */ + outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK); +} + static int __devinit read_eeprom(long ioaddr, int location) { int i; @@ -749,9 +803,8 @@ static int epic_open(struct net_device * /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); if (debug > 1) printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " @@ -792,7 +845,7 @@ static void epic_pause(struct net_device } /* Remove the packets on the Rx queue. */ - epic_rx(dev); + epic_rx(dev, RX_RING_SIZE); } static void epic_restart(struct net_device *dev) @@ -838,9 +891,9 @@ static void epic_restart(struct net_devi /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) - | CntFull | TxUnderrun | TxDone | TxEmpty - | RxError | RxOverflow | RxFull | RxHeader | RxDone, - ioaddr + INTMASK); + | CntFull | TxUnderrun + | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK); + printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), @@ -926,7 +979,6 @@ static void epic_init_ring(struct net_de int i; ep->tx_full = 0; - ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->dirty_tx = ep->cur_tx = 0; ep->cur_rx = ep->dirty_rx = 0; ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); @@ -1026,6 +1078,76 @@ static int epic_start_xmit(struct sk_buf return 0; } +static void epic_tx_error(struct net_device *dev, struct epic_private *ep, + int status) +{ + struct net_device_stats *stats = &ep->stats; + +#ifndef final_version + /* There was an major error, log it. */ + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + stats->tx_errors++; + if (status & 0x1050) + stats->tx_aborted_errors++; + if (status & 0x0008) + stats->tx_carrier_errors++; + if (status & 0x0040) + stats->tx_window_errors++; + if (status & 0x0010) + stats->tx_fifo_errors++; +} + +static void epic_tx(struct net_device *dev, struct epic_private *ep) +{ + unsigned int dirty_tx, cur_tx; + + /* + * Note: if this lock becomes a problem we can narrow the locked + * region at the cost of occasionally grabbing the lock more times. + */ + cur_tx = ep->cur_tx; + for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + + if (txstatus & DescOwn) + break; /* It still hasn't been Txed */ + + if (likely(txstatus & 0x0001)) { + ep->stats.collisions += (txstatus >> 8) & 15; + ep->stats.tx_packets++; + ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; + } else + epic_tx_error(dev, ep, txstatus); + + /* Free the original skb. */ + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + ep->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_WARNING + "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, cur_tx, ep->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + ep->dirty_tx = dirty_tx; + if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, allow new TX entries. */ + ep->tx_full = 0; + netif_wake_queue(dev); + } +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) @@ -1033,135 +1155,71 @@ static irqreturn_t epic_interrupt(int ir struct net_device *dev = dev_instance; struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int status, boguscnt = max_interrupt_work; unsigned int handled = 0; + int status; - do { - status = inl(ioaddr + INTSTAT); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(status & 0x00007fff, ioaddr + INTSTAT); - - if (debug > 4) - printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " - "intstat=%#8.8x.\n", - dev->name, status, (int)inl(ioaddr + INTSTAT)); - - if ((status & IntrSummary) == 0) - break; - handled = 1; + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & EpicNormalEvent, ioaddr + INTSTAT); - if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow)) - epic_rx(dev); + if (debug > 4) { + printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " + "intstat=%#8.8x.\n", dev->name, status, + (int)inl(ioaddr + INTSTAT)); + } - if (status & (TxEmpty | TxDone)) { - unsigned int dirty_tx, cur_tx; + if ((status & IntrSummary) == 0) + goto out; - /* Note: if this lock becomes a problem we can narrow the locked - region at the cost of occasionally grabbing the lock more - times. */ - spin_lock(&ep->lock); - cur_tx = ep->cur_tx; - dirty_tx = ep->dirty_tx; - for (; cur_tx - dirty_tx > 0; dirty_tx++) { - struct sk_buff *skb; - int entry = dirty_tx % TX_RING_SIZE; - int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); + handled = 1; - if (txstatus & DescOwn) - break; /* It still hasn't been Txed */ + if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { + spin_lock(&ep->napi_lock); + if (netif_rx_schedule_prep(dev)) { + epic_napi_irq_off(dev, ep); + __netif_rx_schedule(dev); + } else + ep->reschedule_in_poll++; + spin_unlock(&ep->napi_lock); + } + status &= ~EpicNapiEvent; - if ( ! (txstatus & 0x0001)) { - /* There was an major error, log it. */ -#ifndef final_version - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); -#endif - ep->stats.tx_errors++; - if (txstatus & 0x1050) ep->stats.tx_aborted_errors++; - if (txstatus & 0x0008) ep->stats.tx_carrier_errors++; - if (txstatus & 0x0040) ep->stats.tx_window_errors++; - if (txstatus & 0x0010) ep->stats.tx_fifo_errors++; - } else { - ep->stats.collisions += (txstatus >> 8) & 15; - ep->stats.tx_packets++; - ep->stats.tx_bytes += ep->tx_skbuff[entry]->len; - } - - /* Free the original skb. */ - skb = ep->tx_skbuff[entry]; - pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - ep->tx_skbuff[entry] = 0; - } + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) { + if (status == EpicRemoved) + goto out; -#ifndef final_version - if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, cur_tx, ep->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - ep->dirty_tx = dirty_tx; - if (ep->tx_full - && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, allow new TX entries. */ - ep->tx_full = 0; - spin_unlock(&ep->lock); - netif_wake_queue(dev); - } else - spin_unlock(&ep->lock); - } + /* Always update the error counts to avoid overhead later. */ + ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); + ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); + ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - /* Check uncommon events all at once. */ - if (status & (CntFull | TxUnderrun | RxOverflow | RxFull | - PCIBusErr170 | PCIBusErr175)) { - if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ - break; - /* Always update the error counts to avoid overhead later. */ - ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); - ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); - ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT); - - if (status & TxUnderrun) { /* Tx FIFO underflow. */ - ep->stats.tx_fifo_errors++; - outl(ep->tx_threshold += 128, ioaddr + TxThresh); - /* Restart the transmit process. */ - outl(RestartTx, ioaddr + COMMAND); - } - if (status & RxOverflow) { /* Missed a Rx frame. */ - ep->stats.rx_errors++; - } - if (status & (RxOverflow | RxFull)) - outw(RxQueued, ioaddr + COMMAND); - if (status & PCIBusErr170) { - printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", - dev->name, status); - epic_pause(dev); - epic_restart(dev); - } - /* Clear all error sources. */ - outl(status & 0x7f18, ioaddr + INTSTAT); + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + ep->stats.tx_fifo_errors++; + outl(ep->tx_threshold += 128, ioaddr + TxThresh); + /* Restart the transmit process. */ + outl(RestartTx, ioaddr + COMMAND); } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, " - "IntrStatus=0x%8.8x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0x0001ffff, ioaddr + INTSTAT); - break; + if (status & PCIBusErr170) { + printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n", + dev->name, status); + epic_pause(dev); + epic_restart(dev); } - } while (1); + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } - if (debug > 3) - printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, status); +out: + if (debug > 3) { + printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n", + dev->name, status); + } return IRQ_RETVAL(handled); } -static int epic_rx(struct net_device *dev) +static int epic_rx(struct net_device *dev, int budget) { struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; @@ -1171,6 +1229,10 @@ static int epic_rx(struct net_device *de if (debug > 4) printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); + + if (rx_work_limit > budget) + rx_work_limit = budget; + /* If we own the next entry, it's a new packet. Send it up. */ while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); @@ -1226,7 +1288,7 @@ static int epic_rx(struct net_device *de ep->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; @@ -1254,6 +1316,65 @@ static int epic_rx(struct net_device *de return work_done; } +static void epic_rx_err(struct net_device *dev, struct epic_private *ep) +{ + long ioaddr = dev->base_addr; + int status; + + status = inl(ioaddr + INTSTAT); + + if (status == EpicRemoved) + return; + if (status & RxOverflow) /* Missed a Rx frame. */ + ep->stats.rx_errors++; + if (status & (RxOverflow | RxFull)) + outw(RxQueued, ioaddr + COMMAND); +} + +static int epic_poll(struct net_device *dev, int *budget) +{ + struct epic_private *ep = dev->priv; + int work_done, orig_budget; + long ioaddr = dev->base_addr; + + orig_budget = (*budget > dev->quota) ? dev->quota : *budget; + +rx_action: + + epic_tx(dev, ep); + + work_done = epic_rx(dev, *budget); + + epic_rx_err(dev, ep); + + *budget -= work_done; + dev->quota -= work_done; + + if (netif_running(dev) && (work_done < orig_budget)) { + unsigned long flags; + int more; + + /* A bit baroque but it avoids a (space hungry) spin_unlock */ + + spin_lock_irqsave(&ep->napi_lock, flags); + + more = ep->reschedule_in_poll; + if (!more) { + __netif_rx_complete(dev); + outl(EpicNapiEvent, ioaddr + INTSTAT); + epic_napi_irq_on(dev, ep); + } else + ep->reschedule_in_poll--; + + spin_unlock_irqrestore(&ep->napi_lock, flags); + + if (more) + goto rx_action; + } + + return (work_done >= orig_budget); +} + static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1268,9 +1389,13 @@ static int epic_close(struct net_device dev->name, (int)inl(ioaddr + INTSTAT)); del_timer_sync(&ep->timer); - epic_pause(dev); + + epic_disable_int(dev, ep); + free_irq(dev->irq, dev); + epic_pause(dev); + /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { skb = ep->rx_skbuff[i]; @@ -1491,6 +1616,7 @@ static void __devexit epic_remove_one (s #endif pci_release_regions(pdev); free_netdev(dev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); /* pci_power_off(pdev, -1); */ } --- linux-2.6.8-rc1/drivers/net/forcedeth.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/forcedeth.c 2004-07-13 17:09:23.000000000 -0700 @@ -10,8 +10,11 @@ * trademarks of NVIDIA Corporation in the United States and other * countries. * - * Copyright (C) 2003 Manfred Spraul + * Copyright (C) 2003,4 Manfred Spraul * Copyright (C) 2004 Andrew de Quincey (wol support) + * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane + * IRQ rate fixes, bigendian fixes, cleanups, verification) + * Copyright (c) 2004 NVIDIA Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,15 +63,18 @@ * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac * addresses, really stop rx if already running * in nv_start_rx, clean up a bit. - * (C) Carl-Daniel Hailfinger * 0.20: 07 Dec 2003: alloc fixes * 0.21: 12 Jan 2004: additional alloc fix, nic polling fix. * 0.22: 19 Jan 2004: reprogram timer to a sane rate, avoid lockup - * on close. - * (C) Carl-Daniel Hailfinger, Manfred Spraul + * on close. * 0.23: 26 Jan 2004: various small cleanups * 0.24: 27 Feb 2004: make driver even less anonymous in backtraces * 0.25: 09 Mar 2004: wol support + * 0.26: 03 Jun 2004: netdriver specific annotation, sparse-related fixes + * 0.27: 19 Jun 2004: Gigabit support, new descriptor rings, + * added CK804/MCP04 device IDs, code fixes + * for registers, link status and other minor fixes. + * 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -80,7 +86,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.25" +#define FORCEDETH_VERSION "0.28" #define DRV_NAME "forcedeth" #include @@ -124,6 +130,7 @@ enum { #define NVREG_IRQSTAT_MIIEVENT 0x040 #define NVREG_IRQSTAT_MASK 0x1ff NvRegIrqMask = 0x004, +#define NVREG_IRQ_RX_ERROR 0x0001 #define NVREG_IRQ_RX 0x0002 #define NVREG_IRQ_RX_NOBUF 0x0004 #define NVREG_IRQ_TX_ERR 0x0008 @@ -133,7 +140,7 @@ enum { #define NVREG_IRQ_TX1 0x0100 #define NVREG_IRQMASK_WANTED_1 0x005f #define NVREG_IRQMASK_WANTED_2 0x0147 -#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -160,7 +167,7 @@ enum { NvRegOffloadConfig = 0x90, #define NVREG_OFFLOAD_HOMEPHY 0x601 -#define NVREG_OFFLOAD_NORMAL 0x5ee +#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE NvRegReceiverControl = 0x094, #define NVREG_RCVCTL_START 0x01 NvRegReceiverStatus = 0x98, @@ -169,6 +176,8 @@ enum { NvRegRandomSeed = 0x9c, #define NVREG_RNDSEED_MASK 0x00ff #define NVREG_RNDSEED_FORCE 0x7f00 +#define NVREG_RNDSEED_FORCE2 0x2d00 +#define NVREG_RNDSEED_FORCE3 0x7400 NvRegUnknownSetupReg1 = 0xA0, #define NVREG_UNKSETUP1_VAL 0x16070f @@ -182,6 +191,9 @@ enum { NvRegMulticastMaskA = 0xB8, NvRegMulticastMaskB = 0xBC, + NvRegPhyInterface = 0xC0, +#define PHY_RGMII 0x10000000 + NvRegTxRingPhysAddr = 0x100, NvRegRxRingPhysAddr = 0x104, NvRegRingSizes = 0x108, @@ -190,12 +202,12 @@ enum { NvRegUnknownTransmitterReg = 0x10c, NvRegLinkSpeed = 0x110, #define NVREG_LINKSPEED_FORCE 0x10000 -#define NVREG_LINKSPEED_10 10 +#define NVREG_LINKSPEED_10 1000 #define NVREG_LINKSPEED_100 100 -#define NVREG_LINKSPEED_1000 1000 +#define NVREG_LINKSPEED_1000 50 NvRegUnknownSetupReg5 = 0x130, #define NVREG_UNKSETUP5_BIT31 (1<<31) - NvRegUnknownSetupReg3 = 0x134, + NvRegUnknownSetupReg3 = 0x13c, #define NVREG_UNKSETUP3_VAL1 0x200010 NvRegTxRxControl = 0x144, #define NVREG_TXRXCTL_KICK 0x0001 @@ -214,15 +226,15 @@ enum { NvRegAdapterControl = 0x188, #define NVREG_ADAPTCTL_START 0x02 #define NVREG_ADAPTCTL_LINKUP 0x04 -#define NVREG_ADAPTCTL_PHYVALID 0x4000 +#define NVREG_ADAPTCTL_PHYVALID 0x40000 #define NVREG_ADAPTCTL_RUNNING 0x100000 #define NVREG_ADAPTCTL_PHYSHIFT 24 NvRegMIISpeed = 0x18c, #define NVREG_MIISPEED_BIT8 (1<<8) #define NVREG_MIIDELAY 5 NvRegMIIControl = 0x190, -#define NVREG_MIICTL_INUSE 0x10000 -#define NVREG_MIICTL_WRITE 0x08000 +#define NVREG_MIICTL_INUSE 0x08000 +#define NVREG_MIICTL_WRITE 0x00400 #define NVREG_MIICTL_ADDRSHIFT 5 NvRegMIIData = 0x194, NvRegWakeUpFlags = 0x200, @@ -254,34 +266,63 @@ enum { #define NVREG_POWERSTATE_D3 0x0003 }; +/* Big endian: should work, but is untested */ struct ring_desc { u32 PacketBuffer; - u16 Length; - u16 Flags; + u32 FlagLen; }; -#define NV_TX_LASTPACKET (1<<0) -#define NV_TX_RETRYERROR (1<<3) -#define NV_TX_LASTPACKET1 (1<<8) -#define NV_TX_DEFERRED (1<<10) -#define NV_TX_CARRIERLOST (1<<11) -#define NV_TX_LATECOLLISION (1<<12) -#define NV_TX_UNDERFLOW (1<<13) -#define NV_TX_ERROR (1<<14) -#define NV_TX_VALID (1<<15) - -#define NV_RX_DESCRIPTORVALID (1<<0) -#define NV_RX_MISSEDFRAME (1<<1) -#define NV_RX_SUBSTRACT1 (1<<3) -#define NV_RX_ERROR1 (1<<7) -#define NV_RX_ERROR2 (1<<8) -#define NV_RX_ERROR3 (1<<9) -#define NV_RX_ERROR4 (1<<10) -#define NV_RX_CRCERR (1<<11) -#define NV_RX_OVERFLOW (1<<12) -#define NV_RX_FRAMINGERR (1<<13) -#define NV_RX_ERROR (1<<14) -#define NV_RX_AVAIL (1<<15) +#define FLAG_MASK_V1 0xffff0000 +#define FLAG_MASK_V2 0xffffc000 +#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1) +#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2) + +#define NV_TX_LASTPACKET (1<<16) +#define NV_TX_RETRYERROR (1<<19) +#define NV_TX_LASTPACKET1 (1<<24) +#define NV_TX_DEFERRED (1<<26) +#define NV_TX_CARRIERLOST (1<<27) +#define NV_TX_LATECOLLISION (1<<28) +#define NV_TX_UNDERFLOW (1<<29) +#define NV_TX_ERROR (1<<30) +#define NV_TX_VALID (1<<31) + +#define NV_TX2_LASTPACKET (1<<29) +#define NV_TX2_RETRYERROR (1<<18) +#define NV_TX2_LASTPACKET1 (1<<23) +#define NV_TX2_DEFERRED (1<<25) +#define NV_TX2_CARRIERLOST (1<<26) +#define NV_TX2_LATECOLLISION (1<<27) +#define NV_TX2_UNDERFLOW (1<<28) +/* error and valid are the same for both */ +#define NV_TX2_ERROR (1<<30) +#define NV_TX2_VALID (1<<31) + +#define NV_RX_DESCRIPTORVALID (1<<16) +#define NV_RX_MISSEDFRAME (1<<17) +#define NV_RX_SUBSTRACT1 (1<<18) +#define NV_RX_ERROR1 (1<<23) +#define NV_RX_ERROR2 (1<<24) +#define NV_RX_ERROR3 (1<<25) +#define NV_RX_ERROR4 (1<<26) +#define NV_RX_CRCERR (1<<27) +#define NV_RX_OVERFLOW (1<<28) +#define NV_RX_FRAMINGERR (1<<29) +#define NV_RX_ERROR (1<<30) +#define NV_RX_AVAIL (1<<31) + +#define NV_RX2_DESCRIPTORVALID (1<<29) +#define NV_RX2_SUBSTRACT1 (1<<25) +#define NV_RX2_ERROR1 (1<<18) +#define NV_RX2_ERROR2 (1<<19) +#define NV_RX2_ERROR3 (1<<20) +#define NV_RX2_ERROR4 (1<<21) +#define NV_RX2_CRCERR (1<<22) +#define NV_RX2_OVERFLOW (1<<23) +#define NV_RX2_FRAMINGERR (1<<24) +/* error and avail are the same for both */ +#define NV_RX2_ERROR (1<<30) +#define NV_RX2_AVAIL (1<<31) /* Miscelaneous hardware related defines: */ #define NV_PCI_REGSZ 0x270 @@ -307,28 +348,66 @@ struct ring_desc { /* General driver defaults */ #define NV_WATCHDOG_TIMEO (5*HZ) -#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */ #define RX_RING 128 -#define TX_RING 16 -/* limited to 1 packet until we understand NV_TX_LASTPACKET */ -#define TX_LIMIT_STOP 10 -#define TX_LIMIT_START 5 +#define TX_RING 64 +/* + * If your nic mysteriously hangs then try to reduce the limits + * to 1/0: It might be required to set NV_TX_LASTPACKET in the + * last valid ring entry. But this would be impossible to + * implement - probably a disassembly error. + */ +#define TX_LIMIT_STOP 63 +#define TX_LIMIT_START 62 /* rx/tx mac addr + type + vlan + align + slack*/ -#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64) +#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64) /* even more slack */ -#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128) +#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128) #define OOM_REFILL (1+HZ/20) #define POLL_WAIT (1+HZ/100) +#define DESC_VER_1 0x0 +#define DESC_VER_2 0x02100 + +/* PHY defines */ +#define PHY_OUI_MARVELL 0x5043 +#define PHY_OUI_CICADA 0x03f1 +#define PHYID1_OUI_MASK 0x03ff +#define PHYID1_OUI_SHFT 6 +#define PHYID2_OUI_MASK 0xfc00 +#define PHYID2_OUI_SHFT 10 +#define PHY_INIT1 0x0f000 +#define PHY_INIT2 0x0e00 +#define PHY_INIT3 0x01000 +#define PHY_INIT4 0x0200 +#define PHY_INIT5 0x0004 +#define PHY_INIT6 0x02000 +#define PHY_GIGABIT 0x0100 + +#define PHY_TIMEOUT 0x1 +#define PHY_ERROR 0x2 + +#define PHY_100 0x1 +#define PHY_1000 0x2 +#define PHY_HALF 0x100 + +/* FIXME: MII defines that should be added to */ +#define MII_1000BT_CR 0x09 +#define MII_1000BT_SR 0x0a +#define ADVERTISE_1000FULL 0x0200 +#define ADVERTISE_1000HALF 0x0100 +#define LPA_1000FULL 0x0800 +#define LPA_1000HALF 0x0400 + + /* * SMP locking: * All hardware access under dev->priv->lock, except the performance * critical parts: * - rx is (pseudo-) lockless: it relies on the single-threading provided - * by the arch code for interrupts. + * by the arch code for interrupts. * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission * needs dev->priv->lock :-( * - set_multicast_list: preparation lockless, relies on dev->xmit_lock. @@ -346,12 +425,15 @@ struct fe_priv { int duplex; int phyaddr; int wolenabled; + unsigned int phy_oui; + u16 gigabit; /* General data: RO fields */ dma_addr_t ring_addr; struct pci_dev *pci_dev; u32 orig_mac[2]; u32 irqmask; + u32 desc_ver; /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); @@ -371,7 +453,7 @@ struct fe_priv { unsigned int next_tx, nic_tx; struct sk_buff *tx_skbuff[TX_RING]; dma_addr_t tx_dma[TX_RING]; - u16 tx_flags; + u32 tx_flags; }; /* @@ -396,6 +478,12 @@ static inline void pci_push(u8 * base) readl(base); } +static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v) +{ + return le32_to_cpu(prd->FlagLen) + & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); +} + static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, int delay, int delaymax, const char *msg) { @@ -422,24 +510,18 @@ static int reg_delay(struct net_device * static int mii_rw(struct net_device *dev, int addr, int miireg, int value) { u8 *base = get_hwbase(dev); - int was_running; u32 reg; int retval; writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); - was_running = 0; - reg = readl(base + NvRegAdapterControl); - if (reg & NVREG_ADAPTCTL_RUNNING) { - was_running = 1; - writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); - } + reg = readl(base + NvRegMIIControl); if (reg & NVREG_MIICTL_INUSE) { writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl); udelay(NV_MIIBUSY_DELAY); } - reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; + reg = (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; if (value != MII_READ) { writel(value, base + NvRegMIIData); reg |= NVREG_MIICTL_WRITE; @@ -461,19 +543,117 @@ static int mii_rw(struct net_device *dev dev->name, miireg, addr); retval = -1; } else { - /* FIXME: why is that required? */ - udelay(50); retval = readl(base + NvRegMIIData); dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n", dev->name, miireg, addr, retval); } - if (was_running) { - reg = readl(base + NvRegAdapterControl); - writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); - } + return retval; } +static int phy_reset(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u32 miicontrol; + unsigned int tries = 0; + + miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + miicontrol |= BMCR_RESET; + if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) { + return -1; + } + + /* wait for 500ms */ + msleep(500); + + /* must wait till reset is deasserted */ + while (miicontrol & BMCR_RESET) { + msleep(10); + miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + /* FIXME: 100 tries seem excessive */ + if (tries++ > 100) + return -1; + } + return 0; +} + +static int phy_init(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; + + /* set advertise register */ + reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|0x800|0x400); + if (mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg)) { + printk(KERN_INFO "%s: phy write to advertise failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + + /* get phy interface type */ + phyinterface = readl(base + NvRegPhyInterface); + + /* see if gigabit phy */ + mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + if (mii_status & PHY_GIGABIT) { + np->gigabit = PHY_GIGABIT; + mii_control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ); + mii_control_1000 &= ~ADVERTISE_1000HALF; + if (phyinterface & PHY_RGMII) + mii_control_1000 |= ADVERTISE_1000FULL; + else + mii_control_1000 &= ~ADVERTISE_1000FULL; + + if (mii_rw(dev, np->phyaddr, MII_1000BT_CR, mii_control_1000)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } + else + np->gigabit = 0; + + /* reset the phy */ + if (phy_reset(dev)) { + printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + + /* phy vendor specific configuration */ + if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) { + phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ); + phy_reserved &= ~(PHY_INIT1 | PHY_INIT2); + phy_reserved |= (PHY_INIT3 | PHY_INIT4); + if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ); + phy_reserved |= PHY_INIT5; + if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } + if (np->phy_oui == PHY_OUI_CICADA) { + phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ); + phy_reserved |= PHY_INIT6; + if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) { + printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev)); + return PHY_ERROR; + } + } + + /* restart auto negotiation */ + mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE); + if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { + return PHY_ERROR; + } + + return 0; +} + static void nv_start_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -488,6 +668,8 @@ static void nv_start_rx(struct net_devic writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); + dprintk(KERN_DEBUG "%s: nv_start_rx to duplex %d, speed 0x%08x.\n", + dev->name, np->duplex, np->linkspeed); pci_push(base); } @@ -498,8 +680,8 @@ static void nv_stop_rx(struct net_device dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); writel(0, base + NvRegReceiverControl); reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, - NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, - KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); + NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, + KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); udelay(NV_RXSTOP_DELAY2); writel(0, base + NvRegLinkSpeed); @@ -521,8 +703,8 @@ static void nv_stop_tx(struct net_device dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); writel(0, base + NvRegTransmitterControl); reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, - NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, - KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); + NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, + KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); udelay(NV_TXSTOP_DELAY2); writel(0, base + NvRegUnknownTransmitterReg); @@ -530,13 +712,14 @@ static void nv_stop_tx(struct net_device static void nv_txrx_reset(struct net_device *dev) { + struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); - writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); - writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl); pci_push(base); } @@ -651,11 +834,12 @@ static int nv_alloc_rx(struct net_device { struct fe_priv *np = get_nvpriv(dev); unsigned int refill_rx = np->refill_rx; + int nr; while (np->cur_rx != refill_rx) { - int nr = refill_rx % RX_RING; struct sk_buff *skb; + nr = refill_rx % RX_RING; if (np->rx_skbuff[nr] == NULL) { skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); @@ -670,10 +854,9 @@ static int nv_alloc_rx(struct net_device np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); - np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); wmb(); - np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); - dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", + np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL); + dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; } @@ -704,15 +887,13 @@ static int nv_init_ring(struct net_devic int i; np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) { - np->tx_ring[i].Flags = 0; - } + for (i = 0; i < TX_RING; i++) + np->tx_ring[i].FlagLen = 0; np->cur_rx = RX_RING; np->refill_rx = 0; - for (i = 0; i < RX_RING; i++) { - np->rx_ring[i].Flags = 0; - } + for (i = 0; i < RX_RING; i++) + np->rx_ring[i].FlagLen = 0; return nv_alloc_rx(dev); } @@ -721,7 +902,7 @@ static void nv_drain_tx(struct net_devic struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < TX_RING; i++) { - np->tx_ring[i].Flags = 0; + np->tx_ring[i].FlagLen = 0; if (np->tx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->tx_dma[i], np->tx_skbuff[i]->len, @@ -738,7 +919,7 @@ static void nv_drain_rx(struct net_devic struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < RX_RING; i++) { - np->rx_ring[i].Flags = 0; + np->rx_ring[i].FlagLen = 0; wmb(); if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], @@ -770,11 +951,10 @@ static int nv_start_xmit(struct sk_buff PCI_DMA_TODEVICE); np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring[nr].Length = cpu_to_le16(skb->len-1); spin_lock_irq(&np->lock); wmb(); - np->tx_ring[nr].Flags = np->tx_flags; + np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", dev->name, np->next_tx); { @@ -793,7 +973,7 @@ static int nv_start_xmit(struct sk_buff if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) netif_stop_queue(dev); spin_unlock_irq(&np->lock); - writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); return 0; } @@ -806,27 +986,42 @@ static int nv_start_xmit(struct sk_buff static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); + u32 Flags; + int i; - while (np->nic_tx < np->next_tx) { - struct ring_desc *prd; - int i = np->nic_tx % TX_RING; + while (np->nic_tx != np->next_tx) { + i = np->nic_tx % TX_RING; - prd = &np->tx_ring[i]; + Flags = le32_to_cpu(np->tx_ring[i].FlagLen); dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", - dev->name, np->nic_tx, prd->Flags); - if (prd->Flags & cpu_to_le16(NV_TX_VALID)) + dev->name, np->nic_tx, Flags); + if (Flags & NV_TX_VALID) break; - if (prd->Flags & cpu_to_le16(NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (prd->Flags & cpu_to_le16(NV_TX_UNDERFLOW)) - np->stats.tx_fifo_errors++; - if (prd->Flags & cpu_to_le16(NV_TX_CARRIERLOST)) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; + if (np->desc_ver == DESC_VER_1) { + if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (Flags & NV_TX_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += np->tx_skbuff[i]->len; + } } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (Flags & NV_TX2_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX2_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += np->tx_skbuff[i]->len; + } } pci_unmap_single(np->pci_dev, np->tx_dma[i], np->tx_skbuff[i]->len, @@ -876,9 +1071,9 @@ static void nv_tx_timeout(struct net_dev static void nv_rx_process(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); + u32 Flags; for (;;) { - struct ring_desc *prd; struct sk_buff *skb; int len; int i; @@ -886,11 +1081,13 @@ static void nv_rx_process(struct net_dev break; /* we scanned the whole ring - do not continue */ i = np->cur_rx % RX_RING; - prd = &np->rx_ring[i]; + Flags = le32_to_cpu(np->rx_ring[i].FlagLen); + len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver); + dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", - dev->name, np->cur_rx, prd->Flags); + dev->name, np->cur_rx, Flags); - if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) + if (Flags & NV_RX_AVAIL) break; /* still owned by hardware, */ /* @@ -904,7 +1101,7 @@ static void nv_rx_process(struct net_dev { int j; - dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",prd->Flags); + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags); for (j=0; j<64; j++) { if ((j%16) == 0) dprintk("\n%03x:", j); @@ -913,41 +1110,69 @@ static void nv_rx_process(struct net_dev dprintk("\n"); } /* look at what we actually got: */ - if (!(prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID))) - goto next_pkt; - - - len = le16_to_cpu(prd->Length); + if (np->desc_ver == DESC_VER_1) { + if (!(Flags & NV_RX_DESCRIPTORVALID)) + goto next_pkt; - if (prd->Flags & cpu_to_le16(NV_RX_MISSEDFRAME)) { - np->stats.rx_missed_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (prd->Flags & cpu_to_le16(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (prd->Flags & cpu_to_le16(NV_RX_CRCERR)) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (prd->Flags & cpu_to_le16(NV_RX_OVERFLOW)) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (prd->Flags & cpu_to_le16(NV_RX_ERROR)) { - /* framing errors are soft errors, the rest is fatal. */ - if (prd->Flags & cpu_to_le16(NV_RX_FRAMINGERR)) { - if (prd->Flags & cpu_to_le16(NV_RX_SUBSTRACT1)) { - len--; + if (Flags & NV_RX_MISSEDFRAME) { + np->stats.rx_missed_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_CRCERR) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_OVERFLOW) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_ERROR) { + /* framing errors are soft errors, the rest is fatal. */ + if (Flags & NV_RX_FRAMINGERR) { + if (Flags & NV_RX_SUBSTRACT1) { + len--; + } + } else { + np->stats.rx_errors++; + goto next_pkt; } - } else { + } + } else { + if (!(Flags & NV_RX2_DESCRIPTORVALID)) + goto next_pkt; + + if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) { np->stats.rx_errors++; goto next_pkt; } + if (Flags & NV_RX2_CRCERR) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX2_OVERFLOW) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX2_ERROR) { + /* framing errors are soft errors, the rest is fatal. */ + if (Flags & NV_RX2_FRAMINGERR) { + if (Flags & NV_RX2_SUBSTRACT1) { + len--; + } + } else { + np->stats.rx_errors++; + goto next_pkt; + } + } } /* got a valid packet - forward it to the network core */ skb = np->rx_skbuff[i]; @@ -972,7 +1197,7 @@ next_pkt: */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - if (new_mtu > DEFAULT_MTU) + if (new_mtu > ETH_DATA_LEN) return -EINVAL; dev->mtu = new_mtu; return 0; @@ -1036,6 +1261,8 @@ static void nv_set_multicast(struct net_ writel(mask[0], base + NvRegMulticastMaskA); writel(mask[1], base + NvRegMulticastMaskB); writel(pff, base + NvRegPacketFilterFlags); + dprintk(KERN_INFO "%s: reconfiguration for multicast lists.\n", + dev->name); nv_start_rx(dev); spin_unlock_irq(&np->lock); } @@ -1043,16 +1270,62 @@ static void nv_set_multicast(struct net_ static int nv_update_linkspeed(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); - int adv, lpa, newls, newdup; + u8 *base = get_hwbase(dev); + int adv, lpa; + int newls = np->linkspeed; + int newdup = np->duplex; + int mii_status; + int retval = 0; + u32 control_1000, status_1000, phyreg; + + /* BMSR_LSTATUS is latched, read it twice: + * we want the current value. + */ + mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + + if (!(mii_status & BMSR_LSTATUS)) { + dprintk(KERN_DEBUG "%s: no link detected by phy - falling back to 10HD.\n", + dev->name); + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + retval = 0; + goto set_speed; + } + + /* check auto negotiation is complete */ + if (!(mii_status & BMSR_ANEGCOMPLETE)) { + /* still in autonegotiation - configure nic for 10 MBit HD and wait. */ + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + retval = 0; + dprintk(KERN_DEBUG "%s: autoneg not completed - falling back to 10HD.\n", dev->name); + goto set_speed; + } + + retval = 1; + if (np->gigabit == PHY_GIGABIT) { + control_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ); + status_1000 = mii_rw(dev, np->phyaddr, MII_1000BT_SR, MII_READ); + + if ((control_1000 & ADVERTISE_1000FULL) && + (status_1000 & LPA_1000FULL)) { + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n", + dev->name); + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000; + newdup = 1; + goto set_speed; + } + } adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); - /* FIXME: handle parallel detection properly, handle gigabit ethernet */ + /* FIXME: handle parallel detection properly */ lpa = lpa & adv; - if (lpa & LPA_100FULL) { + if (lpa & LPA_100FULL) { newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; newdup = 1; } else if (lpa & LPA_100HALF) { @@ -1069,47 +1342,75 @@ static int nv_update_linkspeed(struct ne newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; newdup = 0; } - if (np->duplex != newdup || np->linkspeed != newls) { - np->duplex = newdup; - np->linkspeed = newls; - return 1; - } - return 0; + +set_speed: + if (np->duplex == newdup && np->linkspeed == newls) + return retval; + + dprintk(KERN_INFO "%s: changing link setting from %d/%d to %d/%d.\n", + dev->name, np->linkspeed, np->duplex, newls, newdup); + + np->duplex = newdup; + np->linkspeed = newls; + + if (np->gigabit == PHY_GIGABIT) { + phyreg = readl(base + NvRegRandomSeed); + phyreg &= ~(0x3FF00); + if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10) + phyreg |= NVREG_RNDSEED_FORCE3; + else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) + phyreg |= NVREG_RNDSEED_FORCE2; + else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) + phyreg |= NVREG_RNDSEED_FORCE; + writel(phyreg, base + NvRegRandomSeed); + } + + phyreg = readl(base + NvRegPhyInterface); + phyreg &= ~(PHY_HALF|PHY_100|PHY_1000); + if (np->duplex == 0) + phyreg |= PHY_HALF; + if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) + phyreg |= PHY_100; + else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) + phyreg |= PHY_1000; + writel(phyreg, base + NvRegPhyInterface); + + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + pci_push(base); + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + + return retval; } static void nv_link_irq(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); u32 miistat; - int miival; miistat = readl(base + NvRegMIIStatus); writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); - printk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + dprintk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); - miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); - if (miival & BMSR_ANEGCOMPLETE) { - nv_update_linkspeed(dev); - - if (netif_carrier_ok(dev)) { - nv_stop_rx(dev); + if (miistat & (NVREG_MIISTAT_LINKCHANGE)) { + if (nv_update_linkspeed(dev)) { + if (netif_carrier_ok(dev)) { + nv_stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + nv_start_rx(dev); } else { - netif_carrier_on(dev); - printk(KERN_INFO "%s: link up.\n", dev->name); - } - writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), - base + NvRegMisc1); - nv_start_rx(dev); - } else { - if (netif_carrier_ok(dev)) { - netif_carrier_off(dev); - printk(KERN_INFO "%s: link down.\n", dev->name); - nv_stop_rx(dev); + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + nv_stop_rx(dev); + } } - writel(np->linkspeed, base + NvRegLinkSpeed); - pci_push(base); } + dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); } static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) @@ -1136,7 +1437,7 @@ static irqreturn_t nv_nic_irq(int foo, v spin_unlock(&np->lock); } - if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { + if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { nv_rx_process(dev); if (nv_alloc_rx(dev)) { spin_lock(&np->lock); @@ -1158,7 +1459,7 @@ static irqreturn_t nv_nic_irq(int foo, v if (events & (NVREG_IRQ_UNKNOWN)) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); - } + } if (i > max_interrupt_work) { spin_lock(&np->lock); /* disable interrupts on the nic */ @@ -1211,21 +1512,27 @@ static int nv_open(struct net_device *de writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(0, base + NvRegPacketFilterFlags); + + writel(0, base + NvRegTransmitterControl); + writel(0, base + NvRegReceiverControl); + writel(0, base + NvRegAdapterControl); + + /* 2) initialize descriptor rings */ + oom = nv_init_ring(dev); + writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegUnknownTransmitterReg); nv_txrx_reset(dev); writel(0, base + NvRegUnknownSetupReg6); - /* 2) initialize descriptor rings */ np->in_shutdown = 0; - oom = nv_init_ring(dev); /* 3) set mac address */ { u32 mac[2]; - mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); @@ -1233,53 +1540,31 @@ static int nv_open(struct net_device *de writel(mac[1], base + NvRegMacAddrB); } - /* 4) continue setup */ + /* 4) give hw rings */ + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + + /* 5) continue setup */ np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; np->duplex = 0; + + writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); - writel(0, base + NvRegTxRxControl); + writel(np->desc_ver, base + NvRegTxRxControl); pci_push(base); - writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); - writel(0, base + NvRegUnknownSetupReg4); - - /* 5) Find a suitable PHY */ - writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); - for (i = 1; i < 32; i++) { - int id1, id2; - - spin_lock_irq(&np->lock); - id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); - spin_unlock_irq(&np->lock); - if (id1 < 0 || id1 == 0xffff) - continue; - spin_lock_irq(&np->lock); - id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); - spin_unlock_irq(&np->lock); - if (id2 < 0 || id2 == 0xffff) - continue; - dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", - dev->name, id1, id2, i); - np->phyaddr = i; - spin_lock_irq(&np->lock); - nv_update_linkspeed(dev); - spin_unlock_irq(&np->lock); - - break; - } - if (i == 32) { - printk(KERN_INFO "%s: open: failing due to lack of suitable PHY.\n", - dev->name); - ret = -EINVAL; - goto out_drain; - } + writel(0, base + NvRegUnknownSetupReg4); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); /* 6) continue setup */ - writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), - base + NvRegMisc1); + writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); @@ -1291,17 +1576,12 @@ static int nv_open(struct net_device *de writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); - writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID, + writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); - /* 7) start packet processing */ - writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); - writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), - base + NvRegRingSizes); - i = readl(base + NvRegPowerState); if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState); @@ -1309,13 +1589,9 @@ static int nv_open(struct net_device *de pci_push(base); udelay(10); writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); - writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); - writel(0, base + NvRegIrqMask); pci_push(base); - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); - pci_push(base); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); @@ -1324,6 +1600,7 @@ static int nv_open(struct net_device *de if (ret) goto out_drain; + /* ask for interrupts */ writel(np->irqmask, base + NvRegIrqMask); spin_lock_irq(&np->lock); @@ -1332,18 +1609,27 @@ static int nv_open(struct net_device *de writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); + /* One manual link speed update: Interrupts are enabled, future link + * speed changes cause interrupts and are handled by nv_link_irq(). + */ + { + u32 miistat; + miistat = readl(base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); + } + ret = nv_update_linkspeed(dev); nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); - if (oom) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - if (mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE) { + if (ret) { netif_carrier_on(dev); } else { printk("%s: no link during initialization.\n", dev->name); netif_carrier_off(dev); } - + if (oom) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock_irq(&np->lock); return 0; @@ -1448,6 +1734,14 @@ static int __devinit nv_probe(struct pci goto out_relreg; } + /* handle different descriptor versions */ + if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 || + pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 || + pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3) + np->desc_ver = DESC_VER_1; + else + np->desc_ver = DESC_VER_2; + err = -ENOMEM; dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); if (!dev->base_addr) @@ -1507,9 +1801,15 @@ static int __devinit nv_probe(struct pci writel(0, base + NvRegWakeUpFlags); np->wolenabled = 0; - np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); + if (np->desc_ver == DESC_VER_1) { + np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; + if (id->driver_data & DEV_NEED_LASTPACKET1) + np->tx_flags |= NV_TX_LASTPACKET1; + } else { + np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; + if (id->driver_data & DEV_NEED_LASTPACKET1) + np->tx_flags |= NV_TX2_LASTPACKET1; + } if (id->driver_data & DEV_IRQMASK_1) np->irqmask = NVREG_IRQMASK_WANTED_1; if (id->driver_data & DEV_IRQMASK_2) @@ -1517,6 +1817,42 @@ static int __devinit nv_probe(struct pci if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; + /* find a suitable phy */ + for (i = 1; i < 32; i++) { + int id1, id2; + + spin_lock_irq(&np->lock); + id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); + spin_unlock_irq(&np->lock); + if (id1 < 0 || id1 == 0xffff) + continue; + spin_lock_irq(&np->lock); + id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); + spin_unlock_irq(&np->lock); + if (id2 < 0 || id2 == 0xffff) + continue; + + id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; + id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; + dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", + pci_name(pci_dev), id1, id2, i); + np->phyaddr = i; + np->phy_oui = id1 | id2; + break; + } + if (i == 32) { + /* PHY in isolate mode? No phy attached and user wants to + * test loopback? Very odd, but can be correct. + */ + printk(KERN_INFO "%s: open: Could not find a valid PHY.\n", + pci_name(pci_dev)); + } + + if (i != 32) { + /* reset it */ + phy_init(dev); + } + err = register_netdev(dev); if (err) { printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err); @@ -1570,21 +1906,77 @@ static void __devexit nv_remove(struct p static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, - .device = 0x1C3, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ, }, { /* nForce2 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, - .device = 0x0066, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_5, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, }, { /* nForce3 Ethernet Controller */ .vendor = PCI_VENDOR_ID_NVIDIA, - .device = 0x00D6, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_6, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_7, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* CK804 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_8, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* CK804 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_9, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* MCP04 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_10, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* MCP04 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NVENET_11, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, @@ -1611,9 +2003,9 @@ static void __exit exit_nic(void) pci_unregister_driver(&driver); } -MODULE_PARM(max_interrupt_work, "i"); +module_param(max_interrupt_work, int, 0); MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); - + MODULE_AUTHOR("Manfred Spraul "); MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); MODULE_LICENSE("GPL"); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/gianfar.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,1921 @@ +/* + * drivers/net/gianfar.c + * + * Gianfar Ethernet Driver + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Gianfar: AKA Lambda Draconis, "Dragon" + * RA 11 31 24.2 + * Dec +69 19 52 + * V 3.84 + * B-V +1.62 + * + * Theory of operation + * This driver is designed for the Triple-speed Ethernet + * controllers on the Freescale 8540/8560 integrated processors, + * as well as the Fast Ethernet Controller on the 8540. + * + * The driver is initialized through OCP. Structures which + * define the configuration needed by the board are defined in a + * board structure in arch/ppc/platforms (though I do not + * discount the possibility that other architectures could one + * day be supported. One assumption the driver currently makes + * is that the PHY is configured in such a way to advertise all + * capabilities. This is a sensible default, and on certain + * PHYs, changing this default encounters substantial errata + * issues. Future versions may remove this requirement, but for + * now, it is best for the firmware to ensure this is the case. + * + * The Gianfar Ethernet Controller uses a ring of buffer + * descriptors. The beginning is indicated by a register + * pointing to the physical address of the start of the ring. + * The end is determined by a "wrap" bit being set in the + * last descriptor of the ring. + * + * When a packet is received, the RXF bit in the + * IEVENT register is set, triggering an interrupt when the + * corresponding bit in the IMASK register is also set (if + * interrupt coalescing is active, then the interrupt may not + * happen immediately, but will wait until either a set number + * of frames or amount of time have passed.). In NAPI, the + * interrupt handler will signal there is work to be done, and + * exit. Without NAPI, the packet(s) will be handled + * immediately. Both methods will start at the last known empty + * descriptor, and process every subsequent descriptor until there + * are none left with data (NAPI will stop after a set number of + * packets to give time to other tasks, but will eventually + * process all the packets). The data arrives inside a + * pre-allocated skb, and so after the skb is passed up to the + * stack, a new skb must be allocated, and the address field in + * the buffer descriptor must be updated to indicate this new + * skb. + * + * When the kernel requests that a packet be transmitted, the + * driver starts where it left off last time, and points the + * descriptor at the buffer which was passed in. The driver + * then informs the DMA engine that there are packets ready to + * be transmitted. Once the controller is finished transmitting + * the packet, an interrupt may be triggered (under the same + * conditions as for reception, but depending on the TXF bit). + * The driver then cleans up the buffer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" +#include "gianfar_phy.h" +#ifdef CONFIG_NET_FASTROUTE +#include +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) +#define irqreturn_t void +#define IRQ_HANDLED +#endif + +#define TX_TIMEOUT (1*HZ) +#define SKB_ALLOC_TIMEOUT 1000000 +#undef BRIEF_GFAR_ERRORS +#undef VERBOSE_GFAR_ERRORS + +#ifdef CONFIG_GFAR_NAPI +#define RECEIVE(x) netif_receive_skb(x) +#else +#define RECEIVE(x) netif_rx(x) +#endif + +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.0, " +char gfar_driver_name[] = "Gianfar Ethernet"; +char gfar_driver_version[] = "1.0"; + +int startup_gfar(struct net_device *dev); +static int gfar_enet_open(struct net_device *dev); +static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void gfar_timeout(struct net_device *dev); +static int gfar_close(struct net_device *dev); +struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp); +static struct net_device_stats *gfar_get_stats(struct net_device *dev); +static int gfar_set_mac_address(struct net_device *dev); +static int gfar_change_mtu(struct net_device *dev, int new_mtu); +static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void gfar_phy_change(void *data); +static void gfar_phy_timer(unsigned long data); +static void adjust_link(struct net_device *dev); +static void init_registers(struct net_device *dev); +static int init_phy(struct net_device *dev); +static int gfar_probe(struct ocp_device *ocpdev); +static void gfar_remove(struct ocp_device *ocpdev); +void free_skb_resources(struct gfar_private *priv); +static void gfar_set_multi(struct net_device *dev); +static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); +#ifdef CONFIG_GFAR_NAPI +static int gfar_poll(struct net_device *dev, int *budget); +#endif +#ifdef CONFIG_NET_FASTROUTE +static int gfar_accept_fastpath(struct net_device *dev, struct dst_entry *dst); +#endif +static inline int try_fastroute(struct sk_buff *skb, struct net_device *dev, int length); +#ifdef CONFIG_GFAR_NAPI +static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); +#else +static int gfar_clean_rx_ring(struct net_device *dev); +#endif +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); + +extern struct ethtool_ops gfar_ethtool_ops; +extern void gfar_gstrings_normon(struct net_device *dev, u32 stringset, + u8 * buf); +extern void gfar_fill_stats_normon(struct net_device *dev, + struct ethtool_stats *dummy, u64 * buf); +extern int gfar_stats_count_normon(struct net_device *dev); + + +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION("Gianfar Ethernet Driver"); +MODULE_LICENSE("GPL"); + +/* Called by the ocp code to initialize device data structures + * required for bringing up the device + * returns 0 on success */ +static int gfar_probe(struct ocp_device *ocpdev) +{ + u32 tempval; + struct ocp_device *mdiodev; + struct net_device *dev = NULL; + struct gfar_private *priv = NULL; + struct ocp_gfar_data *einfo; + int idx; + int err = 0; + struct ethtool_ops *dev_ethtool_ops; + + einfo = (struct ocp_gfar_data *) ocpdev->def->additions; + + if (einfo == NULL) { + printk(KERN_ERR "gfar %d: Missing additional data!\n", + ocpdev->def->index); + + return -ENODEV; + } + + /* get a pointer to the register memory which can + * configure the PHYs. If it's different from this set, + * get the device which has those regs */ + if ((einfo->phyregidx >= 0) && (einfo->phyregidx != ocpdev->def->index)) { + mdiodev = ocp_find_device(OCP_ANY_ID, + OCP_FUNC_GFAR, einfo->phyregidx); + + /* If the device which holds the MDIO regs isn't + * up, wait for it to come up */ + if (mdiodev == NULL) + return -EAGAIN; + } else { + mdiodev = ocpdev; + } + + /* Create an ethernet device instance */ + dev = alloc_etherdev(sizeof (*priv)); + + if (dev == NULL) + return -ENOMEM; + + priv = netdev_priv(dev); + + /* Set the info in the priv to the current info */ + priv->einfo = einfo; + + /* get a pointer to the register memory */ + priv->regs = (struct gfar *) + ioremap(ocpdev->def->paddr, sizeof (struct gfar)); + + if (priv->regs == NULL) { + err = -ENOMEM; + goto regs_fail; + } + + /* Set the PHY base address */ + priv->phyregs = (struct gfar *) + ioremap(mdiodev->def->paddr, sizeof (struct gfar)); + + if (priv->phyregs == NULL) { + err = -ENOMEM; + goto phy_regs_fail; + } + + ocp_set_drvdata(ocpdev, dev); + + /* Stop the DMA engine now, in case it was running before */ + /* (The firmware could have used it, and left it running). */ + /* To do this, we write Graceful Receive Stop and Graceful */ + /* Transmit Stop, and then wait until the corresponding bits */ + /* in IEVENT indicate the stops have completed. */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + + /* Reset MAC layer */ + gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); + + tempval = (MACCFG1_TX_FLOW | MACCFG1_RX_FLOW); + gfar_write(&priv->regs->maccfg1, tempval); + + /* Initialize MACCFG2. */ + gfar_write(&priv->regs->maccfg2, MACCFG2_INIT_SETTINGS); + + /* Initialize ECNTRL */ + gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); + + /* Copy the station address into the dev structure, */ + /* and into the address registers MAC_STNADDR1,2. */ + /* Backwards, because little endian MACs are dumb. */ + /* Don't set the regs if the firmware already did */ + memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long) (priv->regs); + + SET_MODULE_OWNER(dev); + + /* Fill in the dev structure */ + dev->open = gfar_enet_open; + dev->hard_start_xmit = gfar_start_xmit; + dev->tx_timeout = gfar_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_GFAR_NAPI + dev->poll = gfar_poll; + dev->weight = GFAR_DEV_WEIGHT; +#endif + dev->stop = gfar_close; + dev->get_stats = gfar_get_stats; + dev->change_mtu = gfar_change_mtu; + dev->mtu = 1500; + dev->set_multicast_list = gfar_set_multi; + dev->flags |= IFF_MULTICAST; + + dev_ethtool_ops = + (struct ethtool_ops *)kmalloc(sizeof(struct ethtool_ops), + GFP_KERNEL); + + if(dev_ethtool_ops == NULL) { + err = -ENOMEM; + goto ethtool_fail; + } + + memcpy(dev_ethtool_ops, &gfar_ethtool_ops, sizeof(gfar_ethtool_ops)); + + /* If there is no RMON support in this device, we don't + * want to expose non-existant statistics */ + if((priv->einfo->flags & GFAR_HAS_RMON) == 0) { + dev_ethtool_ops->get_strings = gfar_gstrings_normon; + dev_ethtool_ops->get_stats_count = gfar_stats_count_normon; + dev_ethtool_ops->get_ethtool_stats = gfar_fill_stats_normon; + } + + if((priv->einfo->flags & GFAR_HAS_COALESCE) == 0) { + dev_ethtool_ops->set_coalesce = NULL; + dev_ethtool_ops->get_coalesce = NULL; + } + + dev->ethtool_ops = dev_ethtool_ops; + +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = gfar_accept_fastpath; +#endif + + priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; +#ifdef CONFIG_GFAR_BUFSTASH + priv->rx_stash_size = STASH_LENGTH; +#endif + priv->tx_ring_size = DEFAULT_TX_RING_SIZE; + priv->rx_ring_size = DEFAULT_RX_RING_SIZE; + + /* Initially, coalescing is disabled */ + priv->txcoalescing = 0; + priv->txcount = 0; + priv->txtime = 0; + priv->rxcoalescing = 0; + priv->rxcount = 0; + priv->rxtime = 0; + + err = register_netdev(dev); + + if (err) { + printk(KERN_ERR "%s: Cannot register net device, aborting.\n", + dev->name); + goto register_fail; + } + + /* Print out the device info */ + printk(DEVICE_NAME, dev->name); + for (idx = 0; idx < 6; idx++) + printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':'); + printk("\n"); + + /* Even more device info helps when determining which kernel */ + /* provided which set of benchmarks. Since this is global for all */ + /* devices, we only print it once */ +#ifdef CONFIG_GFAR_NAPI + printk(KERN_INFO "%s: Running with NAPI enabled\n", dev->name); +#else + printk(KERN_INFO "%s: Running with NAPI disabled\n", dev->name); +#endif + printk(KERN_INFO "%s: %d/%d RX/TX BD ring size\n", + dev->name, priv->rx_ring_size, priv->tx_ring_size); + + return 0; + + +register_fail: + kfree(dev_ethtool_ops); +ethtool_fail: + iounmap((void *) priv->phyregs); +phy_regs_fail: + iounmap((void *) priv->regs); +regs_fail: + free_netdev(dev); + return -ENOMEM; +} + +static void gfar_remove(struct ocp_device *ocpdev) +{ + struct net_device *dev = ocp_get_drvdata(ocpdev); + struct gfar_private *priv = netdev_priv(dev); + + ocp_set_drvdata(ocpdev, NULL); + + kfree(dev->ethtool_ops); + iounmap((void *) priv->regs); + iounmap((void *) priv->phyregs); + free_netdev(dev); +} + +/* Configure the PHY for dev. + * returns 0 if success. -1 if failure + */ +static int init_phy(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct phy_info *curphy; + + priv->link = 1; + priv->oldlink = 0; + priv->oldspeed = 0; + priv->olddplx = -1; + + /* get info for this PHY */ + curphy = get_phy_info(dev); + + if (curphy == NULL) { + printk(KERN_ERR "%s: No PHY found\n", dev->name); + return -1; + } + + priv->phyinfo = curphy; + + /* Run the commands which configure the PHY */ + phy_run_commands(dev, curphy->config); + + return 0; +} + +static void init_registers(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_INIT_CLEAR); + + /* Initialize IMASK */ + gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR); + + /* Init hash registers to zero */ + gfar_write(&priv->regs->iaddr0, 0); + gfar_write(&priv->regs->iaddr1, 0); + gfar_write(&priv->regs->iaddr2, 0); + gfar_write(&priv->regs->iaddr3, 0); + gfar_write(&priv->regs->iaddr4, 0); + gfar_write(&priv->regs->iaddr5, 0); + gfar_write(&priv->regs->iaddr6, 0); + gfar_write(&priv->regs->iaddr7, 0); + + gfar_write(&priv->regs->gaddr0, 0); + gfar_write(&priv->regs->gaddr1, 0); + gfar_write(&priv->regs->gaddr2, 0); + gfar_write(&priv->regs->gaddr3, 0); + gfar_write(&priv->regs->gaddr4, 0); + gfar_write(&priv->regs->gaddr5, 0); + gfar_write(&priv->regs->gaddr6, 0); + gfar_write(&priv->regs->gaddr7, 0); + + /* Zero out rctrl */ + gfar_write(&priv->regs->rctrl, 0x00000000); + + /* Zero out the rmon mib registers if it has them */ + if (priv->einfo->flags & GFAR_HAS_RMON) { + memset((void *) &(priv->regs->rmon), 0, + sizeof (struct rmon_mib)); + + /* Mask off the CAM interrupts */ + gfar_write(&priv->regs->rmon.cam1, 0xffffffff); + gfar_write(&priv->regs->rmon.cam2, 0xffffffff); + } + + /* Initialize the max receive buffer length */ + gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); + +#ifdef CONFIG_GFAR_BUFSTASH + /* If we are stashing buffers, we need to set the + * extraction length to the size of the buffer */ + gfar_write(&priv->regs->attreli, priv->rx_stash_size << 16); +#endif + + /* Initialize the Minimum Frame Length Register */ + gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS); + + /* Setup Attributes so that snooping is on for rx */ + gfar_write(&priv->regs->attr, ATTR_INIT_SETTINGS); + gfar_write(&priv->regs->attreli, ATTRELI_INIT_SETTINGS); + + /* Assign the TBI an address which won't conflict with the PHYs */ + gfar_write(&priv->regs->tbipa, TBIPA_VALUE); +} + +void stop_gfar(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + unsigned long flags; + u32 tempval; + + /* Lock it down */ + spin_lock_irqsave(&priv->lock, flags); + + /* Tell the kernel the link is down */ + priv->link = 0; + adjust_link(dev); + + /* Mask all interrupts */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); + + /* Clear all interrupts */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); + + /* Stop the DMA, and wait for it to stop */ + tempval = gfar_read(&priv->regs->dmactrl); + if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) + != (DMACTRL_GRS | DMACTRL_GTS)) { + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & + (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + } + + /* Disable Rx and Tx */ + tempval = gfar_read(®s->maccfg1); + tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); + + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + phy_run_commands(dev, priv->phyinfo->shutdown); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + /* Free the IRQs */ + if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) { + free_irq(priv->einfo->interruptError, dev); + free_irq(priv->einfo->interruptTransmit, dev); + free_irq(priv->einfo->interruptReceive, dev); + } else { + free_irq(priv->einfo->interruptTransmit, dev); + } + + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + free_irq(priv->einfo->interruptPHY, dev); + } else { + del_timer_sync(&priv->phy_info_timer); + } + + free_skb_resources(priv); + + dma_unmap_single(NULL, gfar_read(®s->tbase), + sizeof(struct txbd)*priv->tx_ring_size, + DMA_BIDIRECTIONAL); + dma_unmap_single(NULL, gfar_read(®s->rbase), + sizeof(struct rxbd)*priv->rx_ring_size, + DMA_BIDIRECTIONAL); + + /* Free the buffer descriptors */ + kfree(priv->tx_bd_base); +} + +/* If there are any tx skbs or rx skbs still around, free them. + * Then free tx_skbuff and rx_skbuff */ +void free_skb_resources(struct gfar_private *priv) +{ + struct rxbd8 *rxbdp; + struct txbd8 *txbdp; + int i; + + /* Go through all the buffer descriptors and free their data buffers */ + txbdp = priv->tx_bd_base; + + for (i = 0; i < priv->tx_ring_size; i++) { + + if (priv->tx_skbuff[i]) { + dma_unmap_single(NULL, txbdp->bufPtr, + txbdp->length, + DMA_TO_DEVICE); + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; + } + } + + kfree(priv->tx_skbuff); + + rxbdp = priv->rx_bd_base; + + /* rx_skbuff is not guaranteed to be allocated, so only + * free it and its contents if it is allocated */ + if(priv->rx_skbuff != NULL) { + for (i = 0; i < priv->rx_ring_size; i++) { + if (priv->rx_skbuff[i]) { + dma_unmap_single(NULL, rxbdp->bufPtr, + priv->rx_buffer_size + + RXBUF_ALIGNMENT, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(priv->rx_skbuff[i]); + priv->rx_skbuff[i] = NULL; + } + + rxbdp->status = 0; + rxbdp->length = 0; + rxbdp->bufPtr = 0; + + rxbdp++; + } + + kfree(priv->rx_skbuff); + } +} + +/* Bring the controller up and running */ +int startup_gfar(struct net_device *dev) +{ + struct txbd8 *txbdp; + struct rxbd8 *rxbdp; + unsigned long addr; + int i; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + int err = 0; + + gfar_write(®s->imask, IMASK_INIT_CLEAR); + + /* Allocate memory for the buffer descriptors */ + addr = + (unsigned int) kmalloc(sizeof (struct txbd8) * priv->tx_ring_size + + sizeof (struct rxbd8) * priv->rx_ring_size, + GFP_KERNEL); + + if (addr == 0) { + printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n", + dev->name); + return -ENOMEM; + } + + priv->tx_bd_base = (struct txbd8 *) addr; + + /* enet DMA only understands physical addresses */ + gfar_write(®s->tbase, + dma_map_single(NULL, (void *)addr, + sizeof(struct txbd8) * priv->tx_ring_size, + DMA_BIDIRECTIONAL)); + + /* Start the rx descriptor ring where the tx ring leaves off */ + addr = addr + sizeof (struct txbd8) * priv->tx_ring_size; + priv->rx_bd_base = (struct rxbd8 *) addr; + gfar_write(®s->rbase, + dma_map_single(NULL, (void *)addr, + sizeof(struct rxbd8) * priv->rx_ring_size, + DMA_BIDIRECTIONAL)); + + /* Setup the skbuff rings */ + priv->tx_skbuff = + (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * + priv->tx_ring_size, GFP_KERNEL); + + if (priv->tx_skbuff == NULL) { + printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", + dev->name); + err = -ENOMEM; + goto tx_skb_fail; + } + + for (i = 0; i < priv->tx_ring_size; i++) + priv->tx_skbuff[i] = NULL; + + priv->rx_skbuff = + (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * + priv->rx_ring_size, GFP_KERNEL); + + if (priv->rx_skbuff == NULL) { + printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", + dev->name); + err = -ENOMEM; + goto rx_skb_fail; + } + + for (i = 0; i < priv->rx_ring_size; i++) + priv->rx_skbuff[i] = NULL; + + /* Initialize some variables in our dev structure */ + priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; + priv->cur_rx = priv->rx_bd_base; + priv->skb_curtx = priv->skb_dirtytx = 0; + priv->skb_currx = 0; + + /* Initialize Transmit Descriptor Ring */ + txbdp = priv->tx_bd_base; + for (i = 0; i < priv->tx_ring_size; i++) { + txbdp->status = 0; + txbdp->length = 0; + txbdp->bufPtr = 0; + txbdp++; + } + + /* Set the last descriptor in the ring to indicate wrap */ + txbdp--; + txbdp->status |= TXBD_WRAP; + + rxbdp = priv->rx_bd_base; + for (i = 0; i < priv->rx_ring_size; i++) { + struct sk_buff *skb = NULL; + + rxbdp->status = 0; + + skb = gfar_new_skb(dev, rxbdp); + + priv->rx_skbuff[i] = skb; + + rxbdp++; + } + + /* Set the last descriptor in the ring to wrap */ + rxbdp--; + rxbdp->status |= RXBD_WRAP; + + /* If the device has multiple interrupts, register for + * them. Otherwise, only register for the one */ + if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) { + /* Install our interrupt handlers for Error, + * Transmit, and Receive */ + if (request_irq(priv->einfo->interruptError, gfar_error, + 0, "enet_error", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptError); + + err = -1; + goto err_irq_fail; + } + + if (request_irq(priv->einfo->interruptTransmit, gfar_transmit, + 0, "enet_tx", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptTransmit); + + err = -1; + + goto tx_irq_fail; + } + + if (request_irq(priv->einfo->interruptReceive, gfar_receive, + 0, "enet_rx", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", + dev->name, priv->einfo->interruptReceive); + + err = -1; + goto rx_irq_fail; + } + } else { + if (request_irq(priv->einfo->interruptTransmit, gfar_interrupt, + 0, "gfar_interrupt", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d\n", + dev->name, priv->einfo->interruptError); + + err = -1; + goto err_irq_fail; + } + } + + /* Grab the PHY interrupt */ + if (priv->einfo->flags & GFAR_HAS_PHY_INTR) { + if (request_irq(priv->einfo->interruptPHY, phy_interrupt, + SA_SHIRQ, "phy_interrupt", dev) < 0) { + printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", + dev->name, priv->einfo->interruptPHY); + + err = -1; + + if (priv->einfo->flags & GFAR_HAS_MULTI_INTR) + goto phy_irq_fail; + else + goto tx_irq_fail; + } + } else { + init_timer(&priv->phy_info_timer); + priv->phy_info_timer.function = &gfar_phy_timer; + priv->phy_info_timer.data = (unsigned long) dev; + mod_timer(&priv->phy_info_timer, jiffies + 2 * HZ); + } + + /* Set up the bottom half queue */ + INIT_WORK(&priv->tq, (void (*)(void *))gfar_phy_change, dev); + + /* Configure the PHY interrupt */ + phy_run_commands(dev, priv->phyinfo->startup); + + /* Tell the kernel the link is up, and determine the + * negotiated features (speed, duplex) */ + adjust_link(dev); + + if (priv->link == 0) + printk(KERN_INFO "%s: No link detected\n", dev->name); + + /* Configure the coalescing support */ + if (priv->txcoalescing) + gfar_write(®s->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(®s->txic, 0); + + if (priv->rxcoalescing) + gfar_write(®s->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(®s->rxic, 0); + + init_waitqueue_head(&priv->rxcleanupq); + + /* Enable Rx and Tx in MACCFG1 */ + tempval = gfar_read(®s->maccfg1); + tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); + + /* Initialize DMACTRL to have WWR and WOP */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= DMACTRL_INIT_SETTINGS; + gfar_write(&priv->regs->dmactrl, tempval); + + /* Clear THLT, so that the DMA starts polling now */ + gfar_write(®s->tstat, TSTAT_CLEAR_THALT); + + /* Make sure we aren't stopped */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + /* Unmask the interrupts we look for */ + gfar_write(®s->imask, IMASK_DEFAULT); + + return 0; + +phy_irq_fail: + free_irq(priv->einfo->interruptReceive, dev); +rx_irq_fail: + free_irq(priv->einfo->interruptTransmit, dev); +tx_irq_fail: + free_irq(priv->einfo->interruptError, dev); +err_irq_fail: +rx_skb_fail: + free_skb_resources(priv); +tx_skb_fail: + kfree(priv->tx_bd_base); + return err; +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int gfar_enet_open(struct net_device *dev) +{ + int err; + + /* Initialize a bunch of registers */ + init_registers(dev); + + gfar_set_mac_address(dev); + + err = init_phy(dev); + + if (err) + return err; + + err = startup_gfar(dev); + + netif_start_queue(dev); + + return err; +} + +/* This is called by the kernel when a frame is ready for transmission. */ +/* It is pointed to by the dev->hard_start_xmit function pointer */ +static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *txbdp; + + /* Update transmit stats */ + priv->stats.tx_bytes += skb->len; + + /* Lock priv now */ + spin_lock_irq(&priv->lock); + + /* Point at the first free tx descriptor */ + txbdp = priv->cur_tx; + + /* Clear all but the WRAP status flags */ + txbdp->status &= TXBD_WRAP; + + /* Set buffer length and pointer */ + txbdp->length = skb->len; + txbdp->bufPtr = dma_map_single(NULL, skb->data, + skb->len, DMA_TO_DEVICE); + + /* Save the skb pointer so we can free it later */ + priv->tx_skbuff[priv->skb_curtx] = skb; + + /* Update the current skb pointer (wrapping if this was the last) */ + priv->skb_curtx = + (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + + /* Flag the BD as interrupt-causing */ + txbdp->status |= TXBD_INTERRUPT; + + /* Flag the BD as ready to go, last in frame, and */ + /* in need of CRC */ + txbdp->status |= (TXBD_READY | TXBD_LAST | TXBD_CRC); + + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, the next one */ + /* is at the beginning of the ring */ + if (txbdp->status & TXBD_WRAP) + txbdp = priv->tx_bd_base; + else + txbdp++; + + /* If the next BD still needs to be cleaned up, then the bds + are full. We need to tell the kernel to stop sending us stuff. */ + if (txbdp == priv->dirty_tx) { + netif_stop_queue(dev); + + priv->stats.tx_fifo_errors++; + } + + /* Update the current txbd to the next one */ + priv->cur_tx = txbdp; + + /* Tell the DMA to go go go */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + + /* Unlock priv */ + spin_unlock_irq(&priv->lock); + + return 0; +} + +/* Stops the kernel queue, and halts the controller */ +static int gfar_close(struct net_device *dev) +{ + stop_gfar(dev); + + netif_stop_queue(dev); + + return 0; +} + +/* returns a net_device_stats structure pointer */ +static struct net_device_stats * gfar_get_stats(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + return &(priv->stats); +} + +/* Changes the mac address if the controller is not running. */ +int gfar_set_mac_address(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + int i; + char tmpbuf[MAC_ADDR_LEN]; + u32 tempval; + + /* Now copy it into the mac registers backwards, cuz */ + /* little endian is silly */ + for (i = 0; i < MAC_ADDR_LEN; i++) + tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->dev_addr[i]; + + gfar_write(&priv->regs->macstnaddr1, *((u32 *) (tmpbuf))); + + tempval = *((u32 *) (tmpbuf + 4)); + + gfar_write(&priv->regs->macstnaddr2, tempval); + + return 0; +} + +/********************************************************************** + * gfar_accept_fastpath + * + * Used to authenticate to the kernel that a fast path entry can be + * added to device's routing table cache + * + * Input : pointer to ethernet interface network device structure and + * a pointer to the designated entry to be added to the cache. + * Output : zero upon success, negative upon failure + **********************************************************************/ +#ifdef CONFIG_NET_FASTROUTE +static int gfar_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +{ + struct net_device *odev = dst->dev; + + if ((dst->ops->protocol != __constant_htons(ETH_P_IP)) + || (odev->type != ARPHRD_ETHER) + || (odev->accept_fastpath == NULL)) { + return -1; + } + + return 0; +} +#endif + +/* try_fastroute() -- Checks the fastroute cache to see if a given packet + * can be routed immediately to another device. If it can, we send it. + * If we used a fastroute, we return 1. Otherwise, we return 0. + * Returns 0 if CONFIG_NET_FASTROUTE is not on + */ +static inline int try_fastroute(struct sk_buff *skb, struct net_device *dev, int length) +{ +#ifdef CONFIG_NET_FASTROUTE + struct ethhdr *eth; + struct iphdr *iph; + unsigned int hash; + struct rtable *rt; + struct net_device *odev; + struct gfar_private *priv = netdev_priv(dev); + unsigned int CPU_ID = smp_processor_id(); + + eth = (struct ethhdr *) (skb->data); + + /* Only route ethernet IP packets */ + if (eth->h_proto == __constant_htons(ETH_P_IP)) { + iph = (struct iphdr *) (skb->data + ETH_HLEN); + + /* Generate the hash value */ + hash = ((*(u8 *) &iph->daddr) ^ (*(u8 *) & iph->saddr)) & NETDEV_FASTROUTE_HMASK; + + rt = (struct rtable *) (dev->fastpath[hash]); + if (rt != NULL + && ((*(u32 *) &iph->daddr) == (*(u32 *) &rt->key.dst)) + && ((*(u32 *) &iph->saddr) == (*(u32 *) &rt->key.src)) + && !(rt->u.dst.obsolete)) { + odev = rt->u.dst.dev; + netdev_rx_stat[CPU_ID].fastroute_hit++; + + /* Make sure the packet is: + * 1) IPv4 + * 2) without any options (header length of 5) + * 3) Not a multicast packet + * 4) going to a valid destination + * 5) Not out of time-to-live + */ + if (iph->version == 4 + && iph->ihl == 5 + && (!(eth->h_dest[0] & 0x01)) + && neigh_is_valid(rt->u.dst.neighbour) + && iph->ttl > 1) { + + /* Fast Route Path: Taken if the outgoing device is ready to transmit the packet now */ + if ((!netif_queue_stopped(odev)) + && (!spin_is_locked(odev->xmit_lock)) + && (skb->len <= (odev->mtu + ETH_HLEN + 2 + 4))) { + + skb->pkt_type = PACKET_FASTROUTE; + skb->protocol = __constant_htons(ETH_P_IP); + ip_decrease_ttl(iph); + memcpy(eth->h_source, odev->dev_addr, MAC_ADDR_LEN); + memcpy(eth->h_dest, rt->u.dst.neighbour->ha, MAC_ADDR_LEN); + skb->dev = odev; + + /* Prep the skb for the packet */ + skb_put(skb, length); + + if (odev->hard_start_xmit(skb, odev) != 0) { + panic("%s: FastRoute path corrupted", dev->name); + } + netdev_rx_stat[CPU_ID].fastroute_success++; + } + + /* Semi Fast Route Path: Mark the packet as needing fast routing, but let the + * stack handle getting it to the device */ + else { + skb->pkt_type = PACKET_FASTROUTE; + skb->nh.raw = skb->data + ETH_HLEN; + skb->protocol = __constant_htons(ETH_P_IP); + netdev_rx_stat[CPU_ID].fastroute_defer++; + + /* Prep the skb for the packet */ + skb_put(skb, length); + + if(RECEIVE(skb) == NET_RX_DROP) { + priv->extra_stats.kernel_dropped++; + } + } + + return 1; + } + } + } +#endif /* CONFIG_NET_FASTROUTE */ + return 0; +} + +static int gfar_change_mtu(struct net_device *dev, int new_mtu) +{ + int tempsize, tempval; + struct gfar_private *priv = netdev_priv(dev); + int oldsize = priv->rx_buffer_size; + int frame_size = new_mtu + 18; + + if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { + printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name); + return -EINVAL; + } + + tempsize = + (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + + INCREMENTAL_BUFFER_SIZE; + + /* Only stop and start the controller if it isn't already + * stopped */ + if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + stop_gfar(dev); + + priv->rx_buffer_size = tempsize; + + dev->mtu = new_mtu; + + gfar_write(&priv->regs->mrblr, priv->rx_buffer_size); + gfar_write(&priv->regs->maxfrm, priv->rx_buffer_size); + + /* If the mtu is larger than the max size for standard + * ethernet frames (ie, a jumbo frame), then set maccfg2 + * to allow huge frames, and to check the length */ + tempval = gfar_read(&priv->regs->maccfg2); + + if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE) + tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + else + tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + + gfar_write(&priv->regs->maccfg2, tempval); + + if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + startup_gfar(dev); + + return 0; +} + +/* gfar_timeout gets called when a packet has not been + * transmitted after a set amount of time. + * For now, assume that clearing out all the structures, and + * starting over will fix the problem. */ +static void gfar_timeout(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + + priv->stats.tx_errors++; + + if (dev->flags & IFF_UP) { + stop_gfar(dev); + startup_gfar(dev); + } + + if (!netif_queue_stopped(dev)) + netif_schedule(dev); +} + +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *bdp; + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); + + /* Lock priv */ + spin_lock(&priv->lock); + bdp = priv->dirty_tx; + while ((bdp->status & TXBD_READY) == 0) { + /* If dirty_tx and cur_tx are the same, then either the */ + /* ring is empty or full now (it could only be full in the beginning, */ + /* obviously). If it is empty, we are done. */ + if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) + break; + + priv->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, */ + /* but we eventually sent the packet. */ + if (bdp->status & TXBD_DEF) + priv->stats.collisions++; + + /* Free the sk buffer associated with this TxBD */ + dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); + priv->tx_skbuff[priv->skb_dirtytx] = NULL; + priv->skb_dirtytx = + (priv->skb_dirtytx + + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + + /* update bdp to point at next bd in the ring (wrapping if necessary) */ + if (bdp->status & TXBD_WRAP) + bdp = priv->tx_bd_base; + else + bdp++; + + /* Move dirty_tx to be the next bd */ + priv->dirty_tx = bdp; + + /* We freed a buffer, so now we can restart transmission */ + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } /* while ((bdp->status & TXBD_READY) == 0) */ + + /* If we are coalescing the interrupts, reset the timer */ + /* Otherwise, clear it */ + if (priv->txcoalescing) + gfar_write(&priv->regs->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(&priv->regs->txic, 0); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp) +{ + struct gfar_private *priv = netdev_priv(dev); + struct sk_buff *skb = NULL; + unsigned int timeout = SKB_ALLOC_TIMEOUT; + + /* We have to allocate the skb, so keep trying till we succeed */ + while ((!skb) && timeout--) + skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); + + if (skb == NULL) + return NULL; + + /* We need the data buffer to be aligned properly. We will reserve + * as many bytes as needed to align the data properly + */ + skb_reserve(skb, + RXBUF_ALIGNMENT - + (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1))); + + skb->dev = dev; + + bdp->bufPtr = dma_map_single(NULL, skb->data, + priv->rx_buffer_size + RXBUF_ALIGNMENT, + DMA_FROM_DEVICE); + + bdp->length = 0; + + /* Mark the buffer empty */ + bdp->status |= (RXBD_EMPTY | RXBD_INTERRUPT); + + return skb; +} + +static inline void count_errors(unsigned short status, struct gfar_private *priv) +{ + struct net_device_stats *stats = &priv->stats; + struct gfar_extra_stats *estats = &priv->extra_stats; + + /* If the packet was truncated, none of the other errors + * matter */ + if (status & RXBD_TRUNCATED) { + stats->rx_length_errors++; + + estats->rx_trunc++; + + return; + } + /* Count the errors, if there were any */ + if (status & (RXBD_LARGE | RXBD_SHORT)) { + stats->rx_length_errors++; + + if (status & RXBD_LARGE) + estats->rx_large++; + else + estats->rx_short++; + } + if (status & RXBD_NONOCTET) { + stats->rx_frame_errors++; + estats->rx_nonoctet++; + } + if (status & RXBD_CRCERR) { + estats->rx_crcerr++; + stats->rx_crc_errors++; + } + if (status & RXBD_OVERRUN) { + estats->rx_overrun++; + stats->rx_crc_errors++; + } +} + +irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + +#ifdef CONFIG_GFAR_NAPI + u32 tempval; +#endif + + /* Clear IEVENT, so rx interrupt isn't called again + * because of this interrupt */ + gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); + + /* support NAPI */ +#ifdef CONFIG_GFAR_NAPI + if (netif_rx_schedule_prep(dev)) { + tempval = gfar_read(&priv->regs->imask); + tempval &= IMASK_RX_DISABLED; + gfar_write(&priv->regs->imask, tempval); + + __netif_rx_schedule(dev); + } else { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", + dev->name, gfar_read(priv->regs->ievent), + gfar_read(priv->regs->imask)); +#endif + } +#else + + spin_lock(&priv->lock); + gfar_clean_rx_ring(dev); + + /* If we are coalescing interrupts, update the timer */ + /* Otherwise, clear it */ + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + /* Just in case we need to wake the ring param changer */ + priv->rxclean = 1; + + spin_unlock(&priv->lock); +#endif + + return IRQ_HANDLED; +} + + +/* gfar_process_frame() -- handle one incoming packet if skb + * isn't NULL. Try the fastroute before using the stack */ +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, + int length) +{ + struct gfar_private *priv = netdev_priv(dev); + + if (skb == NULL) { +#ifdef BRIEF_GFAR_ERRORS + printk(KERN_WARNING "%s: Missing skb!!.\n", + dev->name); +#endif + priv->stats.rx_dropped++; + priv->extra_stats.rx_skbmissing++; + } else { + if(try_fastroute(skb, dev, length) == 0) { + /* Prep the skb for the packet */ + skb_put(skb, length); + + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, dev); + + /* Send the packet up the stack */ + if (RECEIVE(skb) == NET_RX_DROP) { + priv->extra_stats.kernel_dropped++; + } + } + } + + return 0; +} + +/* gfar_clean_rx_ring() -- Processes each frame in the rx ring + * until all are gone (or, in the case of NAPI, the budget/quota + * has been reached). Returns the number of frames handled + */ +#ifdef CONFIG_GFAR_NAPI +static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) +#else +static int gfar_clean_rx_ring(struct net_device *dev) +#endif +{ + struct rxbd8 *bdp; + struct sk_buff *skb; + u16 pkt_len; + int howmany = 0; + struct gfar_private *priv = netdev_priv(dev); + + /* Get the first full descriptor */ + bdp = priv->cur_rx; + +#ifdef CONFIG_GFAR_NAPI +#define GFAR_RXDONE() ((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0)) +#else +#define GFAR_RXDONE() (bdp->status & RXBD_EMPTY) +#endif + while (!GFAR_RXDONE()) { + skb = priv->rx_skbuff[priv->skb_currx]; + + if (!(bdp->status & + (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET + | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) { + /* Increment the number of packets */ + priv->stats.rx_packets++; + howmany++; + + /* Remove the FCS from the packet length */ + pkt_len = bdp->length - 4; + + gfar_process_frame(dev, skb, pkt_len); + + priv->stats.rx_bytes += pkt_len; + + } else { + count_errors(bdp->status, priv); + + if (skb) + dev_kfree_skb_any(skb); + + priv->rx_skbuff[priv->skb_currx] = NULL; + } + + dev->last_rx = jiffies; + + /* Clear the status flags for this buffer */ + bdp->status &= ~RXBD_STATS; + + /* Add another skb for the future */ + skb = gfar_new_skb(dev, bdp); + priv->rx_skbuff[priv->skb_currx] = skb; + + /* Update to the next pointer */ + if (bdp->status & RXBD_WRAP) + bdp = priv->rx_bd_base; + else + bdp++; + + /* update to point at the next skb */ + priv->skb_currx = + (priv->skb_currx + + 1) & RX_RING_MOD_MASK(priv->rx_ring_size); + + } + + /* Update the current rxbd pointer to be the next one */ + priv->cur_rx = bdp; + + /* If no packets have arrived since the + * last one we processed, clear the IEVENT RX and + * BSY bits so that another interrupt won't be + * generated when we set IMASK */ + if (bdp->status & RXBD_EMPTY) + gfar_write(&priv->regs->ievent, IEVENT_RX_MASK); + + return howmany; +} + +#ifdef CONFIG_GFAR_NAPI +static int gfar_poll(struct net_device *dev, int *budget) +{ + int howmany; + struct gfar_private *priv = netdev_priv(dev); + int rx_work_limit = *budget; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + + spin_lock(&priv->lock); + howmany = gfar_clean_rx_ring(dev, rx_work_limit); + + dev->quota -= howmany; + rx_work_limit -= howmany; + *budget -= howmany; + + if (rx_work_limit >= 0) { + netif_rx_complete(dev); + + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); + + gfar_write(&priv->regs->imask, IMASK_DEFAULT); + + /* If we are coalescing interrupts, update the timer */ + /* Otherwise, clear it */ + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + /* Signal to the ring size changer that it's safe to go */ + priv->rxclean = 1; + } + + spin_unlock(priv->lock); + + return (rx_work_limit < 0) ? 1 : 0; +} +#endif + +/* The interrupt handler for devices with one interrupt */ +static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Save ievent for future reference */ + u32 events = gfar_read(&priv->regs->ievent); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, events); + + /* Check for reception */ + if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0)) + gfar_receive(irq, dev_id, regs); + + /* Check for transmit completion */ + if ((events & IEVENT_TXF) || (events & IEVENT_TXB)) + gfar_transmit(irq, dev_id, regs); + + /* Update error statistics */ + if (events & IEVENT_TXE) { + priv->stats.tx_errors++; + + if (events & IEVENT_LC) + priv->stats.tx_window_errors++; + if (events & IEVENT_CRL) + priv->stats.tx_aborted_errors++; + if (events & IEVENT_XFUN) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_WARNING "%s: tx underrun. dropped packet\n", + dev->name); +#endif + priv->stats.tx_dropped++; + priv->extra_stats.tx_underrun++; + + /* Reactivate the Tx Queues */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + } + } + if (events & IEVENT_BSY) { + priv->stats.rx_errors++; + priv->extra_stats.rx_bsy++; + + gfar_receive(irq, dev_id, regs); + +#ifndef CONFIG_GFAR_NAPI + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); +#endif + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name, + gfar_read(priv->regs->rstat)); +#endif + } + if (events & IEVENT_BABR) { + priv->stats.rx_errors++; + priv->extra_stats.rx_babr++; + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babbling error\n", dev->name); +#endif + } + if (events & IEVENT_EBERR) { + priv->extra_stats.eberr++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: EBERR\n", dev->name); +#endif + } + if (events & IEVENT_RXC) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: control frame\n", dev->name); +#endif + } + + if (events & IEVENT_BABT) { + priv->extra_stats.tx_babt++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babt error\n", dev->name); +#endif + } + + return IRQ_HANDLED; +} + +static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Run the commands which acknowledge the interrupt */ + phy_run_commands(dev, priv->phyinfo->ack_int); + + /* Schedule the bottom half */ + schedule_work(&priv->tq); + + return IRQ_HANDLED; +} + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void gfar_phy_change(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct gfar_private *priv = netdev_priv(dev); + int timeout = HZ / 1000 + 1; + + /* Delay to give the PHY a chance to change the + * register state */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(timeout); + + /* Run the commands which check the link state */ + phy_run_commands(dev, priv->phyinfo->handle_int); + + /* React to the change in state */ + adjust_link(dev); +} + +/* Called every so often on systems that don't interrupt + * the core for PHY changes */ +static void gfar_phy_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct gfar_private *priv = netdev_priv(dev); + + schedule_work(&priv->tq); + + mod_timer(&priv->phy_info_timer, jiffies + 2 * HZ); +} + +/* Called every time the controller might need to be made + * aware of new link state. The PHY code conveys this + * information through variables in the priv structure, and this + * function converts those variables into the appropriate + * register values, and can bring down the device if needed. + */ +static void adjust_link(struct net_device *dev) +{ + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + + if (priv->link) { + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (priv->duplexity != priv->olddplx) { + if (!(priv->duplexity)) { + tempval = gfar_read(®s->maccfg2); + tempval &= ~(MACCFG2_FULL_DUPLEX); + gfar_write(®s->maccfg2, tempval); + + printk(KERN_INFO "%s: Half Duplex\n", + dev->name); + } else { + tempval = gfar_read(®s->maccfg2); + tempval |= MACCFG2_FULL_DUPLEX; + gfar_write(®s->maccfg2, tempval); + + printk(KERN_INFO "%s: Full Duplex\n", + dev->name); + } + + priv->olddplx = priv->duplexity; + } + + if (priv->speed != priv->oldspeed) { + switch (priv->speed) { + case 1000: + tempval = gfar_read(®s->maccfg2); + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); + gfar_write(®s->maccfg2, tempval); + break; + case 100: + case 10: + tempval = gfar_read(®s->maccfg2); + tempval = + ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); + gfar_write(®s->maccfg2, tempval); + break; + default: + printk(KERN_WARNING + "%s: Ack! Speed (%d) is not 10/100/1000!\n", + dev->name, priv->speed); + break; + } + + printk(KERN_INFO "%s: Speed %dBT\n", dev->name, + priv->speed); + + priv->oldspeed = priv->speed; + } + + if (!priv->oldlink) { + printk(KERN_INFO "%s: Link is up\n", dev->name); + priv->oldlink = 1; + netif_carrier_on(dev); + netif_schedule(dev); + } + } else { + if (priv->oldlink) { + printk(KERN_INFO "%s: Link is down\n", dev->name); + priv->oldlink = 0; + priv->oldspeed = 0; + priv->olddplx = -1; + netif_carrier_off(dev); + } + } +} + + +/* Update the hash table based on the current list of multicast + * addresses we subscribe to. Also, change the promiscuity of + * the device based on the flags (this function is called + * whenever dev->flags is changed */ +static void gfar_set_multi(struct net_device *dev) +{ + struct dev_mc_list *mc_ptr; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 tempval; + + if(dev->flags & IFF_PROMISC) { + printk(KERN_INFO "%s: Entering promiscuous mode.\n", + dev->name); + /* Set RCTRL to PROM */ + tempval = gfar_read(®s->rctrl); + tempval |= RCTRL_PROM; + gfar_write(®s->rctrl, tempval); + } else { + /* Set RCTRL to not PROM */ + tempval = gfar_read(®s->rctrl); + tempval &= ~(RCTRL_PROM); + gfar_write(®s->rctrl, tempval); + } + + if(dev->flags & IFF_ALLMULTI) { + /* Set the hash to rx all multicast frames */ + gfar_write(®s->gaddr0, 0xffffffff); + gfar_write(®s->gaddr1, 0xffffffff); + gfar_write(®s->gaddr2, 0xffffffff); + gfar_write(®s->gaddr3, 0xffffffff); + gfar_write(®s->gaddr4, 0xffffffff); + gfar_write(®s->gaddr5, 0xffffffff); + gfar_write(®s->gaddr6, 0xffffffff); + gfar_write(®s->gaddr7, 0xffffffff); + } else { + /* zero out the hash */ + gfar_write(®s->gaddr0, 0x0); + gfar_write(®s->gaddr1, 0x0); + gfar_write(®s->gaddr2, 0x0); + gfar_write(®s->gaddr3, 0x0); + gfar_write(®s->gaddr4, 0x0); + gfar_write(®s->gaddr5, 0x0); + gfar_write(®s->gaddr6, 0x0); + gfar_write(®s->gaddr7, 0x0); + + if(dev->mc_count == 0) + return; + + /* Parse the list, and set the appropriate bits */ + for(mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr); + } + } + + return; +} + +/* Set the appropriate hash bit for the given addr */ +/* The algorithm works like so: + * 1) Take the Destination Address (ie the multicast address), and + * do a CRC on it (little endian), and reverse the bits of the + * result. + * 2) Use the 8 most significant bits as a hash into a 256-entry + * table. The table is controlled through 8 32-bit registers: + * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is + * gaddr7. This means that the 3 most significant bits in the + * hash index which gaddr register to use, and the 5 other bits + * indicate which bit (assuming an IBM numbering scheme, which + * for PowerPC (tm) is usually the case) in the register holds + * the entry. */ +static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr) +{ + u32 tempval; + struct gfar_private *priv = netdev_priv(dev); + struct gfar *regs = priv->regs; + u32 *hash = ®s->gaddr0; + u32 result = ether_crc(MAC_ADDR_LEN, addr); + u8 whichreg = ((result >> 29) & 0x7); + u8 whichbit = ((result >> 24) & 0x1f); + u32 value = (1 << (31-whichbit)); + + tempval = gfar_read(&hash[whichreg]); + tempval |= value; + gfar_write(&hash[whichreg], tempval); + + return; +} + +/* GFAR error interrupt handler */ +static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct gfar_private *priv = netdev_priv(dev); + + /* Save ievent for future reference */ + u32 events = gfar_read(&priv->regs->ievent); + + /* Clear IEVENT */ + gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK); + + /* Hmm... */ +#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS) + printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n", + dev->name, events, gfar_read(priv->regs->imask)); +#endif + + /* Update the error counters */ + if (events & IEVENT_TXE) { + priv->stats.tx_errors++; + + if (events & IEVENT_LC) + priv->stats.tx_window_errors++; + if (events & IEVENT_CRL) + priv->stats.tx_aborted_errors++; + if (events & IEVENT_XFUN) { +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: underrun. packet dropped.\n", + dev->name); +#endif + priv->stats.tx_dropped++; + priv->extra_stats.tx_underrun++; + + /* Reactivate the Tx Queues */ + gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); + } +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: Transmit Error\n", dev->name); +#endif + } + if (events & IEVENT_BSY) { + priv->stats.rx_errors++; + priv->extra_stats.rx_bsy++; + + gfar_receive(irq, dev_id, regs); + +#ifndef CONFIG_GFAR_NAPI + /* Clear the halt bit in RSTAT */ + gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); +#endif + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name, + gfar_read(priv->regs->rstat)); +#endif + } + if (events & IEVENT_BABR) { + priv->stats.rx_errors++; + priv->extra_stats.rx_babr++; + +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babbling error\n", dev->name); +#endif + } + if (events & IEVENT_EBERR) { + priv->extra_stats.eberr++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: EBERR\n", dev->name); +#endif + } + if (events & IEVENT_RXC) +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: control frame\n", dev->name); +#endif + + if (events & IEVENT_BABT) { + priv->extra_stats.tx_babt++; +#ifdef VERBOSE_GFAR_ERRORS + printk(KERN_DEBUG "%s: babt error\n", dev->name); +#endif + } + return IRQ_HANDLED; +} + +/* Structure for a device driver */ +static struct ocp_device_id gfar_ids[] = { + {.vendor = OCP_ANY_ID,.function = OCP_FUNC_GFAR}, + {.vendor = OCP_VENDOR_INVALID} +}; + +static struct ocp_driver gfar_driver = { + .name = "gianfar", + .id_table = gfar_ids, + + .probe = gfar_probe, + .remove = gfar_remove, +}; + +static int __init gfar_init(void) +{ + int rc; + + rc = ocp_register_driver(&gfar_driver); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) + if (rc != 0) { +#else + if (rc == 0) { +#endif + ocp_unregister_driver(&gfar_driver); + return -ENODEV; + } + + return 0; +} + +static void __exit gfar_exit(void) +{ + ocp_unregister_driver(&gfar_driver); +} + +module_init(gfar_init); +module_exit(gfar_exit); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/gianfar_ethtool.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,484 @@ +/* + * drivers/net/gianfar_ethtool.c + * + * Gianfar Ethernet Driver + * Ethtool support for Gianfar Enet + * Based on e1000 ethtool support + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This software may be used and distributed according to + * the terms of the GNU Public License, Version 2, incorporated herein + * by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" + +#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) + +extern int startup_gfar(struct net_device *dev); +extern void stop_gfar(struct net_device *dev); +extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs); + +void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, + u64 * buf); +void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); +int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); +int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals); +void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals); +int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals); +void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); + +static char stat_gstrings[][ETH_GSTRING_LEN] = { + "RX Dropped by Kernel", + "RX Large Frame Errors", + "RX Short Frame Errors", + "RX Non-Octet Errors", + "RX CRC Errors", + "RX Overrun Errors", + "RX Busy Errors", + "RX Babbling Errors", + "RX Truncated Frames", + "Ethernet Bus Error", + "TX Babbling Errors", + "TX Underrun Errors", + "RX SKB Missing Errors", + "TX Timeout Errors", + "tx&rx 64B frames", + "tx&rx 65-127B frames", + "tx&rx 128-255B frames", + "tx&rx 256-511B frames", + "tx&rx 512-1023B frames", + "tx&rx 1024-1518B frames", + "tx&rx 1519-1522B Good VLAN", + "RX bytes", + "RX Packets", + "RX FCS Errors", + "Receive Multicast Packet", + "Receive Broadcast Packet", + "RX Control Frame Packets", + "RX Pause Frame Packets", + "RX Unknown OP Code", + "RX Alignment Error", + "RX Frame Length Error", + "RX Code Error", + "RX Carrier Sense Error", + "RX Undersize Packets", + "RX Oversize Packets", + "RX Fragmented Frames", + "RX Jabber Frames", + "RX Dropped Frames", + "TX Byte Counter", + "TX Packets", + "TX Multicast Packets", + "TX Broadcast Packets", + "TX Pause Control Frames", + "TX Deferral Packets", + "TX Excessive Deferral Packets", + "TX Single Collision Packets", + "TX Multiple Collision Packets", + "TX Late Collision Packets", + "TX Excessive Collision Packets", + "TX Total Collision", + "RESERVED", + "TX Dropped Frames", + "TX Jabber Frames", + "TX FCS Errors", + "TX Control Frames", + "TX Oversize Frames", + "TX Undersize Frames", + "TX Fragmented Frames", +}; + +/* Fill in an array of 64-bit statistics from various sources. + * This array will be appended to the end of the ethtool_stats + * structure, and returned to user space + */ +void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf) +{ + int i; + struct gfar_private *priv = (struct gfar_private *) dev->priv; + u32 *rmon = (u32 *) & priv->regs->rmon; + u64 *extra = (u64 *) & priv->extra_stats; + struct gfar_stats *stats = (struct gfar_stats *) buf; + + for (i = 0; i < GFAR_RMON_LEN; i++) { + stats->rmon[i] = (u64) (rmon[i]); + } + + for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { + stats->extra[i] = extra[i]; + } +} + +/* Returns the number of stats (and their corresponding strings) */ +int gfar_stats_count(struct net_device *dev) +{ + return GFAR_STATS_LEN; +} + +void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf) +{ + memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN); +} + +void gfar_fill_stats_normon(struct net_device *dev, + struct ethtool_stats *dummy, u64 * buf) +{ + int i; + struct gfar_private *priv = (struct gfar_private *) dev->priv; + u64 *extra = (u64 *) & priv->extra_stats; + + for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) { + buf[i] = extra[i]; + } +} + + +int gfar_stats_count_normon(struct net_device *dev) +{ + return GFAR_EXTRA_STATS_LEN; +} +/* Fills in the drvinfo structure with some basic info */ +void gfar_gdrvinfo(struct net_device *dev, struct + ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, gfar_driver_name, GFAR_INFOSTR_LEN); + strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN); + strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN); + strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN); + drvinfo->n_stats = GFAR_STATS_LEN; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +/* Return the current settings in the ethtool_cmd structure */ +int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + uint gigabit_support = + priv->einfo->flags & GFAR_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; + uint gigabit_advert = + priv->einfo->flags & GFAR_HAS_GIGABIT ? ADVERTISED_1000baseT_Full: 0; + + cmd->supported = (SUPPORTED_10baseT_Half + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | gigabit_support | SUPPORTED_Autoneg); + + /* For now, we always advertise everything */ + cmd->advertising = (ADVERTISED_10baseT_Half + | ADVERTISED_100baseT_Half + | ADVERTISED_100baseT_Full + | gigabit_advert | ADVERTISED_Autoneg); + + cmd->speed = priv->speed; + cmd->duplex = priv->duplexity; + cmd->port = PORT_MII; + cmd->phy_address = priv->einfo->phyid; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = AUTONEG_ENABLE; + cmd->maxtxpkt = priv->txcount; + cmd->maxrxpkt = priv->rxcount; + + return 0; +} + +/* Return the length of the register structure */ +int gfar_reglen(struct net_device *dev) +{ + return sizeof (struct gfar); +} + +/* Return a dump of the GFAR register space */ +void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf) +{ + int i; + struct gfar_private *priv = (struct gfar_private *) dev->priv; + u32 *theregs = (u32 *) priv->regs; + u32 *buf = (u32 *) regbuf; + + for (i = 0; i < sizeof (struct gfar) / sizeof (u32); i++) + buf[i] = theregs[i]; +} + +/* Return the link state 1 is up, 0 is down */ +u32 gfar_get_link(struct net_device *dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + return (u32) priv->link; +} + +/* Fill in a buffer with the strings which correspond to the + * stats */ +void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) +{ + memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN); +} + +/* Convert microseconds to ethernet clock ticks, which changes + * depending on what speed the controller is running at */ +static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs) +{ + unsigned int count; + + /* The timer is different, depending on the interface speed */ + switch (priv->speed) { + case 1000: + count = GFAR_GBIT_TIME; + break; + case 100: + count = GFAR_100_TIME; + break; + case 10: + default: + count = GFAR_10_TIME; + break; + } + + /* Make sure we return a number greater than 0 + * if usecs > 0 */ + return ((usecs * 1000 + count - 1) / count); +} + +/* Convert ethernet clock ticks to microseconds */ +static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int ticks) +{ + unsigned int count; + + /* The timer is different, depending on the interface speed */ + switch (priv->speed) { + case 1000: + count = GFAR_GBIT_TIME; + break; + case 100: + count = GFAR_100_TIME; + break; + case 10: + default: + count = GFAR_10_TIME; + break; + } + + /* Make sure we return a number greater than 0 */ + /* if ticks is > 0 */ + return ((ticks * count) / 1000); +} + +/* Get the coalescing parameters, and put them in the cvals + * structure. */ +int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); + cvals->rx_max_coalesced_frames = priv->rxcount; + + cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, priv->txtime); + cvals->tx_max_coalesced_frames = priv->txcount; + + cvals->use_adaptive_rx_coalesce = 0; + cvals->use_adaptive_tx_coalesce = 0; + + cvals->pkt_rate_low = 0; + cvals->rx_coalesce_usecs_low = 0; + cvals->rx_max_coalesced_frames_low = 0; + cvals->tx_coalesce_usecs_low = 0; + cvals->tx_max_coalesced_frames_low = 0; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the + * normal {rx,tx}_* coalescing parameters are used. + */ + + /* When the packet rate is (measured in packets per second) + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ + cvals->pkt_rate_high = 0; + cvals->rx_coalesce_usecs_high = 0; + cvals->rx_max_coalesced_frames_high = 0; + cvals->tx_coalesce_usecs_high = 0; + cvals->tx_max_coalesced_frames_high = 0; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ + cvals->rate_sample_interval = 0; + + return 0; +} + +/* Change the coalescing values. + * Both cvals->*_usecs and cvals->*_frames have to be > 0 + * in order for coalescing to be active + */ +int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + + /* Set up rx coalescing */ + if ((cvals->rx_coalesce_usecs == 0) || + (cvals->rx_max_coalesced_frames == 0)) + priv->rxcoalescing = 0; + else + priv->rxcoalescing = 1; + + priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); + priv->rxcount = cvals->rx_max_coalesced_frames; + + /* Set up tx coalescing */ + if ((cvals->tx_coalesce_usecs == 0) || + (cvals->tx_max_coalesced_frames == 0)) + priv->txcoalescing = 0; + else + priv->txcoalescing = 1; + + priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); + priv->txcount = cvals->tx_max_coalesced_frames; + + if (priv->rxcoalescing) + gfar_write(&priv->regs->rxic, + mk_ic_value(priv->rxcount, priv->rxtime)); + else + gfar_write(&priv->regs->rxic, 0); + + if (priv->txcoalescing) + gfar_write(&priv->regs->txic, + mk_ic_value(priv->txcount, priv->txtime)); + else + gfar_write(&priv->regs->txic, 0); + + return 0; +} + +/* Fills in rvals with the current ring parameters. Currently, + * rx, rx_mini, and rx_jumbo rings are the same size, as mini and + * jumbo are ignored by the driver */ +void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + + rvals->rx_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->rx_mini_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->rx_jumbo_max_pending = GFAR_RX_MAX_RING_SIZE; + rvals->tx_max_pending = GFAR_TX_MAX_RING_SIZE; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ + rvals->rx_pending = priv->rx_ring_size; + rvals->rx_mini_pending = priv->rx_ring_size; + rvals->rx_jumbo_pending = priv->rx_ring_size; + rvals->tx_pending = priv->tx_ring_size; +} + +/* Change the current ring parameters, stopping the controller if + * necessary so that we don't mess things up while we're in + * motion. We wait for the ring to be clean before reallocating + * the rings. */ +int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) +{ + u32 tempval; + struct gfar_private *priv = (struct gfar_private *) dev->priv; + int err = 0; + + if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) + return -EINVAL; + + if (!is_power_of_2(rvals->rx_pending)) { + printk("%s: Ring sizes must be a power of 2\n", + dev->name); + return -EINVAL; + } + + if (rvals->tx_pending > GFAR_TX_MAX_RING_SIZE) + return -EINVAL; + + if (!is_power_of_2(rvals->tx_pending)) { + printk("%s: Ring sizes must be a power of 2\n", + dev->name); + return -EINVAL; + } + + /* Stop the controller so we don't rx any more frames */ + /* But first, make sure we clear the bits */ + tempval = gfar_read(&priv->regs->dmactrl); + tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + tempval = gfar_read(&priv->regs->dmactrl); + tempval |= (DMACTRL_GRS | DMACTRL_GTS); + gfar_write(&priv->regs->dmactrl, tempval); + + while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) + cpu_relax(); + + /* Note that rx is not clean right now */ + priv->rxclean = 0; + + if (dev->flags & IFF_UP) { + /* Tell the driver to process the rest of the frames */ + gfar_receive(0, (void *) dev, NULL); + + /* Now wait for it to be done */ + wait_event_interruptible(priv->rxcleanupq, priv->rxclean); + + /* Ok, all packets have been handled. Now we bring it down, + * change the ring size, and bring it up */ + + stop_gfar(dev); + } + + priv->rx_ring_size = rvals->rx_pending; + priv->tx_ring_size = rvals->tx_pending; + + if (dev->flags & IFF_UP) + err = startup_gfar(dev); + + return err; +} + +struct ethtool_ops gfar_ethtool_ops = { + .get_settings = gfar_gsettings, + .get_drvinfo = gfar_gdrvinfo, + .get_regs_len = gfar_reglen, + .get_regs = gfar_get_regs, + .get_link = gfar_get_link, + .get_coalesce = gfar_gcoalesce, + .set_coalesce = gfar_scoalesce, + .get_ringparam = gfar_gringparam, + .set_ringparam = gfar_sringparam, + .get_strings = gfar_gstrings, + .get_stats_count = gfar_stats_count, + .get_ethtool_stats = gfar_fill_stats, +}; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/gianfar.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,537 @@ +/* + * drivers/net/gianfar.h + * + * Gianfar Ethernet Driver + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Still left to do: + * -Add support for module parameters + */ +#ifndef __GIANFAR_H +#define __GIANFAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +#include +#else +#include +#define work_struct tq_struct +#define schedule_work schedule_task +#endif + +#include +#include +#include +#include "gianfar_phy.h" + +/* The maximum number of packets to be handled in one call of gfar_poll */ +#define GFAR_DEV_WEIGHT 64 + +/* Number of bytes to align the rx bufs to */ +#define RXBUF_ALIGNMENT 64 + +/* The number of bytes which composes a unit for the purpose of + * allocating data buffers. ie-for any given MTU, the data buffer + * will be the next highest multiple of 512 bytes. */ +#define INCREMENTAL_BUFFER_SIZE 512 + + +#define MAC_ADDR_LEN 6 + +extern char gfar_driver_name[]; +extern char gfar_driver_version[]; + +/* These need to be powers of 2 for this driver */ +#ifdef CONFIG_GFAR_NAPI +#define DEFAULT_TX_RING_SIZE 256 +#define DEFAULT_RX_RING_SIZE 256 +#else +#define DEFAULT_TX_RING_SIZE 64 +#define DEFAULT_RX_RING_SIZE 64 +#endif + +#define GFAR_RX_MAX_RING_SIZE 256 +#define GFAR_TX_MAX_RING_SIZE 256 + +#define DEFAULT_RX_BUFFER_SIZE 1536 +#define TX_RING_MOD_MASK(size) (size-1) +#define RX_RING_MOD_MASK(size) (size-1) +#define JUMBO_BUFFER_SIZE 9728 +#define JUMBO_FRAME_SIZE 9600 + +/* Latency of interface clock in nanoseconds */ +/* Interface clock latency , in this case, means the + * time described by a value of 1 in the interrupt + * coalescing registers' time fields. Since those fields + * refer to the time it takes for 64 clocks to pass, the + * latencies are as such: + * GBIT = 125MHz => 8ns/clock => 8*64 ns / tick + * 100 = 25 MHz => 40ns/clock => 40*64 ns / tick + * 10 = 2.5 MHz => 400ns/clock => 400*64 ns / tick + */ +#define GFAR_GBIT_TIME 512 +#define GFAR_100_TIME 2560 +#define GFAR_10_TIME 25600 + +#define DEFAULT_TXCOUNT 16 +#define DEFAULT_TXTIME 32768 + +#define DEFAULT_RXCOUNT 16 +#define DEFAULT_RXTIME 32768 + +#define TBIPA_VALUE 0x1f +#define MIIMCFG_INIT_VALUE 0x00000007 +#define MIIMCFG_RESET 0x80000000 +#define MIIMIND_BUSY 0x00000001 + +/* MAC register bits */ +#define MACCFG1_SOFT_RESET 0x80000000 +#define MACCFG1_RESET_RX_MC 0x00080000 +#define MACCFG1_RESET_TX_MC 0x00040000 +#define MACCFG1_RESET_RX_FUN 0x00020000 +#define MACCFG1_RESET_TX_FUN 0x00010000 +#define MACCFG1_LOOPBACK 0x00000100 +#define MACCFG1_RX_FLOW 0x00000020 +#define MACCFG1_TX_FLOW 0x00000010 +#define MACCFG1_SYNCD_RX_EN 0x00000008 +#define MACCFG1_RX_EN 0x00000004 +#define MACCFG1_SYNCD_TX_EN 0x00000002 +#define MACCFG1_TX_EN 0x00000001 + +#define MACCFG2_INIT_SETTINGS 0x00007205 +#define MACCFG2_FULL_DUPLEX 0x00000001 +#define MACCFG2_IF 0x00000300 +#define MACCFG2_MII 0x00000100 +#define MACCFG2_GMII 0x00000200 +#define MACCFG2_HUGEFRAME 0x00000020 +#define MACCFG2_LENGTHCHECK 0x00000010 + +#define ECNTRL_INIT_SETTINGS 0x00001000 +#define ECNTRL_TBI_MODE 0x00000020 + +#define MRBLR_INIT_SETTINGS DEFAULT_RX_BUFFER_SIZE + +#define MINFLR_INIT_SETTINGS 0x00000040 + +/* Init to do tx snooping for buffers and descriptors */ +#define DMACTRL_INIT_SETTINGS 0x000000c3 +#define DMACTRL_GRS 0x00000010 +#define DMACTRL_GTS 0x00000008 + +#define TSTAT_CLEAR_THALT 0x80000000 + +/* Interrupt coalescing macros */ +#define IC_ICEN 0x80000000 +#define IC_ICFT_MASK 0x1fe00000 +#define IC_ICFT_SHIFT 21 +#define mk_ic_icft(x) \ + (((unsigned int)x << IC_ICFT_SHIFT)&IC_ICFT_MASK) +#define IC_ICTT_MASK 0x0000ffff +#define mk_ic_ictt(x) (x&IC_ICTT_MASK) + +#define mk_ic_value(count, time) (IC_ICEN | \ + mk_ic_icft(count) | \ + mk_ic_ictt(time)) + +#define RCTRL_PROM 0x00000008 +#define RSTAT_CLEAR_RHALT 0x00800000 + +#define IEVENT_INIT_CLEAR 0xffffffff +#define IEVENT_BABR 0x80000000 +#define IEVENT_RXC 0x40000000 +#define IEVENT_BSY 0x20000000 +#define IEVENT_EBERR 0x10000000 +#define IEVENT_MSRO 0x04000000 +#define IEVENT_GTSC 0x02000000 +#define IEVENT_BABT 0x01000000 +#define IEVENT_TXC 0x00800000 +#define IEVENT_TXE 0x00400000 +#define IEVENT_TXB 0x00200000 +#define IEVENT_TXF 0x00100000 +#define IEVENT_LC 0x00040000 +#define IEVENT_CRL 0x00020000 +#define IEVENT_XFUN 0x00010000 +#define IEVENT_RXB0 0x00008000 +#define IEVENT_GRSC 0x00000100 +#define IEVENT_RXF0 0x00000080 +#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0) +#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF) +#define IEVENT_ERR_MASK \ +(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \ + IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \ + | IEVENT_CRL | IEVENT_XFUN) + +#define IMASK_INIT_CLEAR 0x00000000 +#define IMASK_BABR 0x80000000 +#define IMASK_RXC 0x40000000 +#define IMASK_BSY 0x20000000 +#define IMASK_EBERR 0x10000000 +#define IMASK_MSRO 0x04000000 +#define IMASK_GRSC 0x02000000 +#define IMASK_BABT 0x01000000 +#define IMASK_TXC 0x00800000 +#define IMASK_TXEEN 0x00400000 +#define IMASK_TXBEN 0x00200000 +#define IMASK_TXFEN 0x00100000 +#define IMASK_LC 0x00040000 +#define IMASK_CRL 0x00020000 +#define IMASK_XFUN 0x00010000 +#define IMASK_RXB0 0x00008000 +#define IMASK_GTSC 0x00000100 +#define IMASK_RXFEN0 0x00000080 +#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY) +#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \ + IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ + IMASK_XFUN | IMASK_RXC | IMASK_BABT) + + +/* Attribute fields */ + +/* This enables rx snooping for buffers and descriptors */ +#ifdef CONFIG_GFAR_BDSTASH +#define ATTR_BDSTASH 0x00000800 +#else +#define ATTR_BDSTASH 0x00000000 +#endif + +#ifdef CONFIG_GFAR_BUFSTASH +#define ATTR_BUFSTASH 0x00004000 +#define STASH_LENGTH 64 +#else +#define ATTR_BUFSTASH 0x00000000 +#endif + +#define ATTR_SNOOPING 0x000000c0 +#define ATTR_INIT_SETTINGS (ATTR_SNOOPING \ + | ATTR_BDSTASH | ATTR_BUFSTASH) + +#define ATTRELI_INIT_SETTINGS 0x0 + + +/* TxBD status field bits */ +#define TXBD_READY 0x8000 +#define TXBD_PADCRC 0x4000 +#define TXBD_WRAP 0x2000 +#define TXBD_INTERRUPT 0x1000 +#define TXBD_LAST 0x0800 +#define TXBD_CRC 0x0400 +#define TXBD_DEF 0x0200 +#define TXBD_HUGEFRAME 0x0080 +#define TXBD_LATECOLLISION 0x0080 +#define TXBD_RETRYLIMIT 0x0040 +#define TXBD_RETRYCOUNTMASK 0x003c +#define TXBD_UNDERRUN 0x0002 + +/* RxBD status field bits */ +#define RXBD_EMPTY 0x8000 +#define RXBD_RO1 0x4000 +#define RXBD_WRAP 0x2000 +#define RXBD_INTERRUPT 0x1000 +#define RXBD_LAST 0x0800 +#define RXBD_FIRST 0x0400 +#define RXBD_MISS 0x0100 +#define RXBD_BROADCAST 0x0080 +#define RXBD_MULTICAST 0x0040 +#define RXBD_LARGE 0x0020 +#define RXBD_NONOCTET 0x0010 +#define RXBD_SHORT 0x0008 +#define RXBD_CRCERR 0x0004 +#define RXBD_OVERRUN 0x0002 +#define RXBD_TRUNCATED 0x0001 +#define RXBD_STATS 0x01ff + +struct txbd8 +{ + u16 status; /* Status Fields */ + u16 length; /* Buffer length */ + u32 bufPtr; /* Buffer Pointer */ +}; + +struct rxbd8 +{ + u16 status; /* Status Fields */ + u16 length; /* Buffer Length */ + u32 bufPtr; /* Buffer Pointer */ +}; + +struct rmon_mib +{ + u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */ + u32 tr127; /* 0x.684 - Transmit and Receive 65-127 byte Frame Counter */ + u32 tr255; /* 0x.688 - Transmit and Receive 128-255 byte Frame Counter */ + u32 tr511; /* 0x.68c - Transmit and Receive 256-511 byte Frame Counter */ + u32 tr1k; /* 0x.690 - Transmit and Receive 512-1023 byte Frame Counter */ + u32 trmax; /* 0x.694 - Transmit and Receive 1024-1518 byte Frame Counter */ + u32 trmgv; /* 0x.698 - Transmit and Receive 1519-1522 byte Good VLAN Frame */ + u32 rbyt; /* 0x.69c - Receive Byte Counter */ + u32 rpkt; /* 0x.6a0 - Receive Packet Counter */ + u32 rfcs; /* 0x.6a4 - Receive FCS Error Counter */ + u32 rmca; /* 0x.6a8 - Receive Multicast Packet Counter */ + u32 rbca; /* 0x.6ac - Receive Broadcast Packet Counter */ + u32 rxcf; /* 0x.6b0 - Receive Control Frame Packet Counter */ + u32 rxpf; /* 0x.6b4 - Receive Pause Frame Packet Counter */ + u32 rxuo; /* 0x.6b8 - Receive Unknown OP Code Counter */ + u32 raln; /* 0x.6bc - Receive Alignment Error Counter */ + u32 rflr; /* 0x.6c0 - Receive Frame Length Error Counter */ + u32 rcde; /* 0x.6c4 - Receive Code Error Counter */ + u32 rcse; /* 0x.6c8 - Receive Carrier Sense Error Counter */ + u32 rund; /* 0x.6cc - Receive Undersize Packet Counter */ + u32 rovr; /* 0x.6d0 - Receive Oversize Packet Counter */ + u32 rfrg; /* 0x.6d4 - Receive Fragments Counter */ + u32 rjbr; /* 0x.6d8 - Receive Jabber Counter */ + u32 rdrp; /* 0x.6dc - Receive Drop Counter */ + u32 tbyt; /* 0x.6e0 - Transmit Byte Counter Counter */ + u32 tpkt; /* 0x.6e4 - Transmit Packet Counter */ + u32 tmca; /* 0x.6e8 - Transmit Multicast Packet Counter */ + u32 tbca; /* 0x.6ec - Transmit Broadcast Packet Counter */ + u32 txpf; /* 0x.6f0 - Transmit Pause Control Frame Counter */ + u32 tdfr; /* 0x.6f4 - Transmit Deferral Packet Counter */ + u32 tedf; /* 0x.6f8 - Transmit Excessive Deferral Packet Counter */ + u32 tscl; /* 0x.6fc - Transmit Single Collision Packet Counter */ + u32 tmcl; /* 0x.700 - Transmit Multiple Collision Packet Counter */ + u32 tlcl; /* 0x.704 - Transmit Late Collision Packet Counter */ + u32 txcl; /* 0x.708 - Transmit Excessive Collision Packet Counter */ + u32 tncl; /* 0x.70c - Transmit Total Collision Counter */ + u8 res1[4]; + u32 tdrp; /* 0x.714 - Transmit Drop Frame Counter */ + u32 tjbr; /* 0x.718 - Transmit Jabber Frame Counter */ + u32 tfcs; /* 0x.71c - Transmit FCS Error Counter */ + u32 txcf; /* 0x.720 - Transmit Control Frame Counter */ + u32 tovr; /* 0x.724 - Transmit Oversize Frame Counter */ + u32 tund; /* 0x.728 - Transmit Undersize Frame Counter */ + u32 tfrg; /* 0x.72c - Transmit Fragments Frame Counter */ + u32 car1; /* 0x.730 - Carry Register One */ + u32 car2; /* 0x.734 - Carry Register Two */ + u32 cam1; /* 0x.738 - Carry Mask Register One */ + u32 cam2; /* 0x.73c - Carry Mask Register Two */ +}; + +struct gfar_extra_stats { + u64 kernel_dropped; + u64 rx_large; + u64 rx_short; + u64 rx_nonoctet; + u64 rx_crcerr; + u64 rx_overrun; + u64 rx_bsy; + u64 rx_babr; + u64 rx_trunc; + u64 eberr; + u64 tx_babt; + u64 tx_underrun; + u64 rx_skbmissing; + u64 tx_timeout; +}; + +#define GFAR_RMON_LEN ((sizeof(struct rmon_mib) - 16)/sizeof(u32)) +#define GFAR_EXTRA_STATS_LEN (sizeof(struct gfar_extra_stats)/sizeof(u64)) + +/* Number of stats in the stats structure (ignore car and cam regs)*/ +#define GFAR_STATS_LEN (GFAR_RMON_LEN + GFAR_EXTRA_STATS_LEN) + +#define GFAR_INFOSTR_LEN 32 + +struct gfar_stats { + u64 extra[GFAR_EXTRA_STATS_LEN]; + u64 rmon[GFAR_RMON_LEN]; +}; + + +struct gfar { + u8 res1[16]; + u32 ievent; /* 0x.010 - Interrupt Event Register */ + u32 imask; /* 0x.014 - Interrupt Mask Register */ + u32 edis; /* 0x.018 - Error Disabled Register */ + u8 res2[4]; + u32 ecntrl; /* 0x.020 - Ethernet Control Register */ + u32 minflr; /* 0x.024 - Minimum Frame Length Register */ + u32 ptv; /* 0x.028 - Pause Time Value Register */ + u32 dmactrl; /* 0x.02c - DMA Control Register */ + u32 tbipa; /* 0x.030 - TBI PHY Address Register */ + u8 res3[88]; + u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */ + u8 res4[8]; + u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */ + u32 fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */ + u8 res5[96]; + u32 tctrl; /* 0x.100 - Transmit Control Register */ + u32 tstat; /* 0x.104 - Transmit Status Register */ + u8 res6[4]; + u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */ + u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */ + u8 res7[16]; + u32 ctbptr; /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */ + u8 res8[92]; + u32 tbptr; /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */ + u8 res9[124]; + u32 tbase; /* 0x.204 - Transmit Descriptor Base Address Register */ + u8 res10[168]; + u32 ostbd; /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */ + u32 ostbdp; /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */ + u8 res11[72]; + u32 rctrl; /* 0x.300 - Receive Control Register */ + u32 rstat; /* 0x.304 - Receive Status Register */ + u8 res12[4]; + u32 rbdlen; /* 0x.30c - RxBD Data Length Register */ + u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */ + u8 res13[16]; + u32 crbptr; /* 0x.324 - Current Receive Buffer Descriptor Pointer */ + u8 res14[24]; + u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */ + u8 res15[64]; + u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */ + u8 res16[124]; + u32 rbase; /* 0x.404 - Receive Descriptor Base Address */ + u8 res17[248]; + u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */ + u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */ + u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */ + u32 hafdup; /* 0x.50c - Half Duplex Register */ + u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ + u8 res18[12]; + u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ + u32 miimcom; /* 0x.524 - MII Management Command Register */ + u32 miimadd; /* 0x.528 - MII Management Address Register */ + u32 miimcon; /* 0x.52c - MII Management Control Register */ + u32 miimstat; /* 0x.530 - MII Management Status Register */ + u32 miimind; /* 0x.534 - MII Management Indicator Register */ + u8 res19[4]; + u32 ifstat; /* 0x.53c - Interface Status Register */ + u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ + u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */ + u8 res20[312]; + struct rmon_mib rmon; + u8 res21[192]; + u32 iaddr0; /* 0x.800 - Indivdual address register 0 */ + u32 iaddr1; /* 0x.804 - Indivdual address register 1 */ + u32 iaddr2; /* 0x.808 - Indivdual address register 2 */ + u32 iaddr3; /* 0x.80c - Indivdual address register 3 */ + u32 iaddr4; /* 0x.810 - Indivdual address register 4 */ + u32 iaddr5; /* 0x.814 - Indivdual address register 5 */ + u32 iaddr6; /* 0x.818 - Indivdual address register 6 */ + u32 iaddr7; /* 0x.81c - Indivdual address register 7 */ + u8 res22[96]; + u32 gaddr0; /* 0x.880 - Global address register 0 */ + u32 gaddr1; /* 0x.884 - Global address register 1 */ + u32 gaddr2; /* 0x.888 - Global address register 2 */ + u32 gaddr3; /* 0x.88c - Global address register 3 */ + u32 gaddr4; /* 0x.890 - Global address register 4 */ + u32 gaddr5; /* 0x.894 - Global address register 5 */ + u32 gaddr6; /* 0x.898 - Global address register 6 */ + u32 gaddr7; /* 0x.89c - Global address register 7 */ + u8 res23[856]; + u32 attr; /* 0x.bf8 - Attributes Register */ + u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */ + u8 res24[1024]; + +}; + +/* Struct stolen almost completely (and shamelessly) from the FCC enet source + * (Ok, that's not so true anymore, but there is a family resemblence) + * The GFAR buffer descriptors track the ring buffers. The rx_bd_base + * and tx_bd_base always point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct gfar_private +{ + /* pointers to arrays of skbuffs for tx and rx */ + struct sk_buff ** tx_skbuff; + struct sk_buff ** rx_skbuff; + + /* indices pointing to the next free sbk in skb arrays */ + u16 skb_curtx; + u16 skb_currx; + + /* index of the first skb which hasn't been transmitted + * yet. */ + u16 skb_dirtytx; + + /* Configuration info for the coalescing features */ + unsigned char txcoalescing; + unsigned short txcount; + unsigned short txtime; + unsigned char rxcoalescing; + unsigned short rxcount; + unsigned short rxtime; + + /* GFAR addresses */ + struct rxbd8 *rx_bd_base; /* Base addresses of Rx and Tx Buffers */ + struct txbd8 *tx_bd_base; + struct rxbd8 *cur_rx; /* Next free rx ring entry */ + struct txbd8 *cur_tx; /* Next free ring entry */ + struct txbd8 *dirty_tx; /* The Ring entry to be freed. */ + struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ + struct phy_info *phyinfo; + struct gfar *phyregs; + struct work_struct tq; + struct timer_list phy_info_timer; + struct net_device_stats stats; /* linux network statistics */ + struct gfar_extra_stats extra_stats; + spinlock_t lock; + unsigned int rx_buffer_size; + unsigned int rx_stash_size; + unsigned int tx_ring_size; + unsigned int rx_ring_size; + wait_queue_head_t rxcleanupq; + unsigned int rxclean; + int link; /* current link state */ + int oldlink; + int duplexity; /* Indicates negotiated duplex state */ + int olddplx; + int speed; /* Indicates negotiated speed */ + int oldspeed; + + /* Info structure initialized by board setup code */ + struct ocp_gfar_data *einfo; +}; + +extern inline u32 gfar_read(volatile unsigned *addr) +{ + u32 val; + val = in_be32(addr); + return val; +} + +extern inline void gfar_write(volatile unsigned *addr, u32 val) +{ + out_be32(addr, val); +} + + + +#endif /* __GIANFAR_H */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/gianfar_phy.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,504 @@ +/* + * drivers/net/gianfar_phy.c + * + * Gianfar Ethernet Driver -- PHY handling + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "gianfar.h" +#include "gianfar_phy.h" + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +void write_phy_reg(struct net_device *dev, u16 regnum, u16 value) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar *regbase = priv->phyregs; + struct ocp_gfar_data *einfo = priv->einfo; + + /* Set the PHY address and the register address we want to write */ + gfar_write(®base->miimadd, ((einfo->phyid) << 8) | regnum); + + /* Write out the value we want */ + gfar_write(®base->miimcon, value); + + /* Wait for the transaction to finish */ + while (gfar_read(®base->miimind) & MIIMIND_BUSY) + cpu_relax(); +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value. Clears miimcom first. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +u16 read_phy_reg(struct net_device *dev, u16 regnum) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar *regbase = priv->phyregs; + struct ocp_gfar_data *einfo = priv->einfo; + u16 value; + + /* Set the PHY address and the register address we want to read */ + gfar_write(®base->miimadd, ((einfo->phyid) << 8) | regnum); + + /* Clear miimcom, and then initiate a read */ + gfar_write(®base->miimcom, 0); + gfar_write(®base->miimcom, MIIM_READ_COMMAND); + + /* Wait for the transaction to finish */ + while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + cpu_relax(); + + /* Grab the value of the register from miimstat */ + value = gfar_read(®base->miimstat); + + return value; +} + +/* returns which value to write to the control register. */ +/* For 10/100 the value is slightly different. */ +u16 mii_cr_init(u16 mii_reg, struct net_device * dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct ocp_gfar_data *einfo = priv->einfo; + + if (einfo->flags & GFAR_HAS_GIGABIT) + return MIIM_CONTROL_INIT; + else + return MIIM_CR_INIT; +} + +#define BRIEF_GFAR_ERRORS +/* Wait for auto-negotiation to complete */ +u16 mii_parse_sr(u16 mii_reg, struct net_device * dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + + unsigned int timeout = GFAR_AN_TIMEOUT; + + if (mii_reg & MIIM_STATUS_LINK) + priv->link = 1; + else + priv->link = 0; + + /* Only auto-negotiate if the link has just gone up */ + if (priv->link && !priv->oldlink) { + while ((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--) + mii_reg = read_phy_reg(dev, MIIM_STATUS); + +#if defined(BRIEF_GFAR_ERRORS) + if (mii_reg & MIIM_STATUS_AN_DONE) + printk(KERN_INFO "%s: Auto-negotiation done\n", + dev->name); + else + printk(KERN_INFO "%s: Auto-negotiation timed out\n", + dev->name); +#endif + } + + return 0; +} + +/* Determine the speed and duplex which was negotiated */ +u16 mii_parse_88E1011_psr(u16 mii_reg, struct net_device * dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + unsigned int speed; + + if (priv->link) { + if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) + priv->duplexity = 1; + else + priv->duplexity = 0; + + speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); + + switch (speed) { + case MIIM_88E1011_PHYSTAT_GBIT: + priv->speed = 1000; + break; + case MIIM_88E1011_PHYSTAT_100: + priv->speed = 100; + break; + default: + priv->speed = 10; + break; + } + } else { + priv->speed = 0; + priv->duplexity = 0; + } + + return 0; +} + +u16 mii_parse_cis8201(u16 mii_reg, struct net_device * dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + unsigned int speed; + + if (priv->link) { + if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) + priv->duplexity = 1; + else + priv->duplexity = 0; + + speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; + + switch (speed) { + case MIIM_CIS8201_AUXCONSTAT_GBIT: + priv->speed = 1000; + break; + case MIIM_CIS8201_AUXCONSTAT_100: + priv->speed = 100; + break; + default: + priv->speed = 10; + break; + } + } else { + priv->speed = 0; + priv->duplexity = 0; + } + + return 0; +} + +u16 mii_parse_dm9161_scsr(u16 mii_reg, struct net_device * dev) +{ + struct gfar_private *priv = (struct gfar_private *) dev->priv; + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) + priv->speed = 100; + else + priv->speed = 10; + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) + priv->duplexity = 1; + else + priv->duplexity = 0; + + return 0; +} + +u16 dm9161_wait(u16 mii_reg, struct net_device *dev) +{ + int timeout = HZ; + int secondary = 10; + u16 temp; + + do { + + /* Davicom takes a bit to come up after a reset, + * so wait here for a bit */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(timeout); + + temp = read_phy_reg(dev, MIIM_STATUS); + + secondary--; + } while ((!(temp & MIIM_STATUS_AN_DONE)) && secondary); + + return 0; +} + +static struct phy_info phy_info_M88E1011S = { + 0x01410c6, + "Marvell 88E1011S", + 4, + (const struct phy_cmd[]) { /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + /* Read the status */ + {MIIM_88E1011_PHY_STATUS, miim_read, mii_parse_88E1011_psr}, + /* Clear the IEVENT register */ + {MIIM_88E1011_IEVENT, miim_read, NULL}, + /* Set up the mask */ + {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_INIT, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* ack_int */ + /* Clear the interrupt */ + {MIIM_88E1011_IEVENT, miim_read, NULL}, + /* Disable interrupts */ + {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_CLEAR, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* handle_int */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Check the status */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + {MIIM_88E1011_PHY_STATUS, miim_read, mii_parse_88E1011_psr}, + /* Enable Interrupts */ + {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_INIT, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* shutdown */ + {MIIM_88E1011_IEVENT, miim_read, NULL}, + {MIIM_88E1011_IMASK, MIIM_88E1011_IMASK_CLEAR, NULL}, + {miim_end,} + }, +}; + +/* Cicada 8204 */ +static struct phy_info phy_info_cis8204 = { + 0x3f11, + "Cicada Cis8204", + 6, + (const struct phy_cmd[]) { /* config */ + /* Override PHY config settings */ + {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, + /* Set up the interface mode */ + {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* startup */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + /* Read the status */ + {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, + /* Clear the status register */ + {MIIM_CIS8204_ISTAT, miim_read, NULL}, + /* Enable interrupts */ + {MIIM_CIS8204_IMASK, MIIM_CIS8204_IMASK_MASK, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* ack_int */ + /* Clear the status register */ + {MIIM_CIS8204_ISTAT, miim_read, NULL}, + /* Disable interrupts */ + {MIIM_CIS8204_IMASK, 0x0, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* handle_int */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + /* Read the status */ + {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, + /* Enable interrupts */ + {MIIM_CIS8204_IMASK, MIIM_CIS8204_IMASK_MASK, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* shutdown */ + /* Clear the status register */ + {MIIM_CIS8204_ISTAT, miim_read, NULL}, + /* Disable interrupts */ + {MIIM_CIS8204_IMASK, 0x0, NULL}, + {miim_end,} + }, +}; + +/* Cicada 8201 */ +static struct phy_info phy_info_cis8201 = { + 0xfc41, + "CIS8201", + 4, + (const struct phy_cmd[]) { /* config */ + /* Override PHY config settings */ + {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, + /* Set up the interface mode */ + {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, mii_cr_init}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* startup */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + /* Read the status */ + {MIIM_CIS8201_AUX_CONSTAT, miim_read, mii_parse_cis8201}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* ack_int */ + {miim_end,} + }, + (const struct phy_cmd[]) { /* handle_int */ + {miim_end,} + }, + (const struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; + +static struct phy_info phy_info_dm9161 = { + 0x0181b88, + "Davicom DM9161E", + 4, + (const struct phy_cmd[]) { /* config */ + {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, + /* Do not bypass the scrambler/descrambler */ + {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, + /* Clear 10BTCSR to default */ + {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CR_INIT, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* startup */ + /* Restart Auto Negotiation */ + {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, dm9161_wait}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, mii_parse_sr}, + /* Read the status */ + {MIIM_DM9161_SCSR, miim_read, mii_parse_dm9161_scsr}, + /* Clear any pending interrupts */ + {MIIM_DM9161_INTR, miim_read, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* ack_int */ + {MIIM_DM9161_INTR, miim_read, NULL}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* handle_int */ + {MIIM_STATUS, miim_read, NULL}, + {MIIM_STATUS, miim_read, mii_parse_sr}, + {MIIM_DM9161_SCSR, miim_read, mii_parse_dm9161_scsr}, + {miim_end,} + }, + (const struct phy_cmd[]) { /* shutdown */ + {MIIM_DM9161_INTR, miim_read, NULL}, + {miim_end,} + }, +}; + +static struct phy_info *phy_info[] = { + &phy_info_cis8201, + &phy_info_cis8204, + &phy_info_M88E1011S, + &phy_info_dm9161, + NULL +}; + +/* Use the PHY ID registers to determine what type of PHY is attached + * to device dev. return a struct phy_info structure describing that PHY + */ +struct phy_info * get_phy_info(struct net_device *dev) +{ + u16 phy_reg; + u32 phy_ID; + int i; + struct phy_info *theInfo = NULL; + + /* Grab the bits from PHYIR1, and put them in the upper half */ + phy_reg = read_phy_reg(dev, MIIM_PHYIR1); + phy_ID = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = read_phy_reg(dev, MIIM_PHYIR2); + phy_ID |= (phy_reg & 0xffff); + + /* loop through all the known PHY types, and find one that */ + /* matches the ID we read from the PHY. */ + for (i = 0; phy_info[i]; i++) + if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) + theInfo = phy_info[i]; + + if (theInfo == NULL) { + printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); + return NULL; + } else { + printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, + phy_ID); + } + + return theInfo; +} + +/* Take a list of struct phy_cmd, and, depending on the values, either */ +/* read or write, using a helper function if provided */ +/* It is assumed that all lists of struct phy_cmd will be terminated by */ +/* mii_end. */ +void phy_run_commands(struct net_device *dev, const struct phy_cmd *cmd) +{ + int i; + u16 result; + struct gfar_private *priv = (struct gfar_private *) dev->priv; + struct gfar *phyregs = priv->phyregs; + + /* Reset the management interface */ + gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); + + /* Setup the MII Mgmt clock speed */ + gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); + + /* Wait until the bus is free */ + while (gfar_read(&phyregs->miimind) & MIIMIND_BUSY) + cpu_relax(); + + for (i = 0; cmd->mii_reg != miim_end; i++) { + /* The command is a read if mii_data is miim_read */ + if (cmd->mii_data == miim_read) { + /* Read the value of the PHY reg */ + result = read_phy_reg(dev, cmd->mii_reg); + + /* If a function was supplied, we need to let it process */ + /* the result. */ + if (cmd->funct != NULL) + (*(cmd->funct)) (result, dev); + } else { /* Otherwise, it's a write */ + /* If a function was supplied, it will provide + * the value to write */ + /* Otherwise, the value was supplied in cmd->mii_data */ + if (cmd->funct != NULL) + result = (*(cmd->funct)) (0, dev); + else + result = cmd->mii_data; + + /* Write the appropriate value to the PHY reg */ + write_phy_reg(dev, cmd->mii_reg, result); + } + cmd++; + } +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/gianfar_phy.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,192 @@ +/* + * drivers/net/gianfar_phy.h + * + * Gianfar Ethernet Driver -- PHY handling + * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 + * Based on 8260_io/fcc_enet.c + * + * Author: Andy Fleming + * Maintainer: Kumar Gala (kumar.gala@freescale.com) + * + * Copyright 2004 Freescale Semiconductor, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __GIANFAR_PHY_H +#define __GIANFAR_PHY_H + +#define miim_end ((u32)-2) +#define miim_read ((u32)-1) + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define MIIM_CONTROL 0x00 +#define MIIM_CONTROL_RESET 0x00008000 +#define MIIM_CONTROL_INIT 0x00001140 +#define MIIM_ANEN 0x00001000 + +#define MIIM_CR 0x00 +#define MIIM_CR_RST 0x00008000 +#define MIIM_CR_INIT 0x00001000 + +#define MIIM_STATUS 0x1 +#define MIIM_STATUS_AN_DONE 0x00000020 +#define MIIM_STATUS_LINK 0x0004 + +#define MIIM_PHYIR1 0x2 +#define MIIM_PHYIR2 0x3 + +#define GFAR_AN_TIMEOUT 0x000fffff + +#define MIIM_ANLPBPA 0x5 +#define MIIM_ANLPBPA_HALF 0x00000040 +#define MIIM_ANLPBPA_FULL 0x00000020 + +#define MIIM_ANEX 0x6 +#define MIIM_ANEX_NP 0x00000004 +#define MIIM_ANEX_PRX 0x00000002 + + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS8201_EXT_CON1 0x17 +#define MIIM_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MIIM_CIS8204_IMASK 0x19 +#define MIIM_CIS8204_IMASK_IEN 0x8000 +#define MIIM_CIS8204_IMASK_SPEED 0x4000 +#define MIIM_CIS8204_IMASK_LINK 0x2000 +#define MIIM_CIS8204_IMASK_DUPLEX 0x1000 +#define MIIM_CIS8204_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MIIM_CIS8204_ISTAT 0x1a +#define MIIM_CIS8204_ISTAT_STATUS 0x8000 +#define MIIM_CIS8204_ISTAT_SPEED 0x4000 +#define MIIM_CIS8204_ISTAT_LINK 0x2000 +#define MIIM_CIS8204_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS8201_AUX_CONSTAT 0x1c +#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MIIM_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MIIM_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MIIM_CIS8201_AUXCONSTAT_100 0x0008 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1011_PHY_STATUS 0x11 +#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 +#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 +#define MIIM_88E1011_PHYSTAT_100 0x4000 +#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 +#define MIIM_88E1011_PHYSTAT_LINK 0x0400 + +#define MIIM_88E1011_IEVENT 0x13 +#define MIIM_88E1011_IEVENT_CLEAR 0x0000 + +#define MIIM_88E1011_IMASK 0x12 +#define MIIM_88E1011_IMASK_INIT 0x6400 +#define MIIM_88E1011_IMASK_CLEAR 0x0000 + +/* DM9161 Control register values */ +#define MIIM_DM9161_CR_STOP 0x0400 +#define MIIM_DM9161_CR_RSTAN 0x1200 + +#define MIIM_DM9161_SCR 0x10 +#define MIIM_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR 0x11 +#define MIIM_DM9161_SCSR_100F 0x8000 +#define MIIM_DM9161_SCSR_100H 0x4000 +#define MIIM_DM9161_SCSR_10F 0x2000 +#define MIIM_DM9161_SCSR_10H 0x1000 + +/* DM9161 Interrupt Register */ +#define MIIM_DM9161_INTR 0x15 +#define MIIM_DM9161_INTR_PEND 0x8000 +#define MIIM_DM9161_INTR_DPLX_MASK 0x0800 +#define MIIM_DM9161_INTR_SPD_MASK 0x0400 +#define MIIM_DM9161_INTR_LINK_MASK 0x0200 +#define MIIM_DM9161_INTR_MASK 0x0100 +#define MIIM_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MIIM_DM9161_INTR_SPD_CHANGE 0x0008 +#define MIIM_DM9161_INTR_LINK_CHANGE 0x0004 +#define MIIM_DM9161_INTR_INIT 0x0000 +#define MIIM_DM9161_INTR_STOP \ +(MIIM_DM9161_INTR_DPLX_MASK | MIIM_DM9161_INTR_SPD_MASK \ + | MIIM_DM9161_INTR_LINK_MASK | MIIM_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR 0x12 +#define MIIM_DM9161_10BTCSR_INIT 0x7800 + + +#define MIIM_READ_COMMAND 0x00000001 + +/* + * struct phy_cmd: A command for reading or writing a PHY register + * + * mii_reg: The register to read or write + * + * mii_data: For writes, the value to put in the register. + * A value of -1 indicates this is a read. + * + * funct: A function pointer which is invoked for each command. + * For reads, this function will be passed the value read + * from the PHY, and process it. + * For writes, the result of this function will be written + * to the PHY register + */ +struct phy_cmd { + u32 mii_reg; + u32 mii_data; + u16 (*funct) (u16 mii_reg, struct net_device * dev); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY. During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is. The 32-bit result + * gotten from the PHY will be shifted right by "shift" bits to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * The struct phy_cmd entries represent pointers to an arrays of + * commands which tell the driver what to do to the PHY. + */ +struct phy_info { + u32 id; + char *name; + unsigned int shift; + /* Called to configure the PHY, and modify the controller + * based on the results */ + const struct phy_cmd *config; + + /* Called when starting up the controller. Usually sets + * up the interrupt for state changes */ + const struct phy_cmd *startup; + + /* Called inside the interrupt handler to acknowledge + * the interrupt */ + const struct phy_cmd *ack_int; + + /* Called in the bottom half to handle the interrupt */ + const struct phy_cmd *handle_int; + + /* Called when bringing down the controller. Usually stops + * the interrupts from being generated */ + const struct phy_cmd *shutdown; +}; + +struct phy_info *get_phy_info(struct net_device *dev); +void phy_run_commands(struct net_device *dev, const struct phy_cmd *cmd); + +#endif /* GIANFAR_PHY_H */ --- linux-2.6.8-rc1/drivers/net/irda/irtty-sir.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/irda/irtty-sir.c 2004-07-13 17:09:13.000000000 -0700 @@ -584,7 +584,7 @@ static void irtty_close(struct tty_struc */ /* we are dead now */ - tty->disc_data = 0; + tty->disc_data = NULL; sirdev_put_instance(priv->dev); --- linux-2.6.8-rc1/drivers/net/irda/stir4200.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/irda/stir4200.c 2004-07-13 17:09:24.000000000 -0700 @@ -168,6 +168,7 @@ enum StirTestMask { struct stir_cb { struct usb_device *usbdev; /* init: probe_irda */ + struct usb_interface *usbintf; struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ struct net_device_stats stats; /* network statistics */ @@ -508,6 +509,7 @@ static int change_speed(struct stir_cb * { int i, err; __u8 mode; + int rc; for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { if (speed == stir_modes[i].speed) @@ -521,7 +523,14 @@ static int change_speed(struct stir_cb * pr_debug("speed change from %d to %d\n", stir->speed, speed); /* sometimes needed to get chip out of stuck state */ + rc = usb_lock_device_for_reset(stir->usbdev, stir->usbintf); + if (rc < 0) { + err = rc; + goto out; + } err = usb_reset_device(stir->usbdev); + if (rc) + usb_unlock_device(stir->usbdev); if (err) goto out; @@ -1066,6 +1075,7 @@ static int stir_probe(struct usb_interfa stir = net->priv; stir->netdev = net; stir->usbdev = dev; + stir->usbintf = intf; ret = usb_reset_configuration(dev); if (ret != 0) { --- linux-2.6.8-rc1/drivers/net/irda/vlsi_ir.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/net/irda/vlsi_ir.c 2004-07-13 17:09:13.000000000 -0700 @@ -1876,7 +1876,7 @@ static int __init vlsi_mod_init(void) * Failure to create the procfs entry is handled like running * without procfs - it's not required for the driver to work. */ - vlsi_proc_root = create_proc_entry(PROC_DIR, S_IFDIR, 0); + vlsi_proc_root = create_proc_entry(PROC_DIR, S_IFDIR, NULL); if (vlsi_proc_root) { /* protect registered procdir against module removal. * Because we are in the module init path there's no race @@ -1888,7 +1888,7 @@ static int __init vlsi_mod_init(void) ret = pci_module_init(&vlsi_irda_driver); if (ret && vlsi_proc_root) - remove_proc_entry(PROC_DIR, 0); + remove_proc_entry(PROC_DIR, NULL); return ret; } @@ -1897,7 +1897,7 @@ static void __exit vlsi_mod_exit(void) { pci_unregister_driver(&vlsi_irda_driver); if (vlsi_proc_root) - remove_proc_entry(PROC_DIR, 0); + remove_proc_entry(PROC_DIR, NULL); } module_init(vlsi_mod_init); --- linux-2.6.8-rc1/drivers/net/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/Kconfig 2004-07-13 17:35:08.000000000 -0700 @@ -1746,6 +1746,7 @@ config VIA_VELOCITY tristate "VIA Velocity support" depends on NET_PCI && PCI select CRC32 + select CRC_CCITT select MII help If you have a VIA "Velocity" based network card say Y here. @@ -2043,6 +2044,23 @@ config R8169 To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. +config R8169_NAPI + bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)" + depends on R8169 && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + + If in doubt, say N. + config SK98LIN tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support" depends on PCI @@ -2131,6 +2149,45 @@ config TIGON3 To compile this driver as a module, choose M here: the module will be called tg3. This is recommended. +config MV64340_ETH + tristate "MV-64340 Ethernet support" + depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX + help + This driver supports the gigabit Ethernet on the Marvell MV64340 + chipset which is used in the Momenco Ocelot C and Jaguar ATX. + +config MV64340_ETH_0 + bool "MV-64340 Port 0" + depends on MV64340_ETH + help + This enables support for Port 0 of the Marvell MV64340 Gigabit + Ethernet. + +config MV64340_ETH_1 + bool "MV-64340 Port 1" + depends on MV64340_ETH + help + This enables support for Port 1 of the Marvell MV64340 Gigabit + Ethernet. + +config MV64340_ETH_2 + bool "MV-64340 Port 2" + depends on MV64340_ETH + help + This enables support for Port 2 of the Marvell MV64340 Gigabit + Ethernet. + +config GIANFAR + tristate "Gianfar Ethernet" + depends on 85xx + help + This driver supports the Gigabit TSEC on the MPC85xx + family of chips, and the FEC on the 8540 + +config GFAR_NAPI + bool "NAPI Support" + depends on GIANFAR + endmenu # --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/kgdb_eth.c 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,132 @@ +/* + * Network interface GDB stub + * + * Written by San Mehat (nettwerk@biodome.org) + * Based upon 'gdbserial' by David Grothe (dave@gcom.com) + * and Scott Foehner (sfoehner@engr.sgi.com) + * + * Twiddled for 2.6 by Robert Walsh + * and wangdi . + * + * Refactored for netpoll API by Matt Mackall + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define IN_BUF_SIZE 512 /* power of 2, please */ +#define OUT_BUF_SIZE 256 + +static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE]; +static int in_head, in_tail, out_count; +static atomic_t in_count; +int kgdboe = 0; /* Default to tty mode */ + +extern void set_debug_traps(void); +extern void breakpoint(void); +static void rx_hook(struct netpoll *np, int port, char *msg, int len); + +static struct netpoll np = { + .name = "kgdboe", + .dev_name = "eth0", + .rx_hook = rx_hook, + .local_port = 6443, + .remote_port = 6442, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; +static int configured; + +int eth_getDebugChar(void) +{ + int chr; + + while (atomic_read(&in_count) == 0) + netpoll_poll(&np); + + chr = in_buf[in_tail++]; + in_tail &= (IN_BUF_SIZE - 1); + atomic_dec(&in_count); + return chr; +} + +void eth_flushDebugChar(void) +{ + if(out_count && np.dev) { + netpoll_send_udp(&np, out_buf, out_count); + out_count = 0; + } +} + +void eth_putDebugChar(int chr) +{ + out_buf[out_count++] = chr; + if(out_count == OUT_BUF_SIZE) + eth_flushDebugChar(); +} + +static void rx_hook(struct netpoll *np, int port, char *msg, int len) +{ + int i; + + np->remote_port = port; + + /* Is this gdb trying to attach? */ + if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8)) + kgdb_schedule_breakpoint(); + + for (i = 0; i < len; i++) { + if (msg[i] == 3) + kgdb_schedule_breakpoint(); + + if (atomic_read(&in_count) >= IN_BUF_SIZE) { + /* buffer overflow, clear it */ + in_head = in_tail = 0; + atomic_set(&in_count, 0); + break; + } + in_buf[in_head++] = msg[i]; + in_head &= (IN_BUF_SIZE - 1); + atomic_inc(&in_count); + } +} + +static int option_setup(char *opt) +{ + configured = !netpoll_parse_options(&np, opt); + return 0; +} +__setup("kgdboe=", option_setup); + +static int init_kgdboe(void) +{ +#ifdef CONFIG_SMP + if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) { + printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS); + return -1; + } +#endif + + set_debug_traps(); + + if(!configured || netpoll_setup(&np)) + return 1; + + kgdboe = 1; + printk(KERN_INFO "kgdb: debugging over ethernet enabled\n"); + + return 0; +} + +module_init(init_kgdboe); --- linux-2.6.8-rc1/drivers/net/Makefile 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/Makefile 2004-07-13 17:09:26.097305480 -0700 @@ -10,6 +10,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_GIANFAR) += gianfar.o gianfar_ethtool.o gianfar_phy.o # # link order important here @@ -95,6 +96,8 @@ obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o +obj-$(CONFIG_MV64340_ETH) += mv64340_eth.o + obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o @@ -190,4 +193,6 @@ obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +# Must come after all NICs that might use them obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_KGDB) += kgdb_eth.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/mv64340_eth.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,2724 @@ +/* + * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports + * Copyright (C) 2002 Matthew Dharm + * + * Based on the 64360 driver from: + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * Copyright (C) 2003 PMC-Sierra, Inc., + * written by Manish Lachwani (lachwani@pmc-sierra.com) + * + * Copyright (C) 2003 Ralf Baechle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "mv64340_eth.h" + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +/* Definition for configuring driver */ +#undef MV64340_RX_QUEUE_FILL_ON_TASK + +/* Constants */ +#define EXTRA_BYTES 32 +#define WRAP ETH_HLEN + 2 + 4 + 16 +#define BUFFER_MTU dev->mtu + WRAP +#define INT_CAUSE_UNMASK_ALL 0x0007ffff +#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff +#ifdef MV64340_RX_FILL_ON_TASK +#define INT_CAUSE_MASK_ALL 0x00000000 +#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL +#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT +#endif + +/* Static function declarations */ +static int mv64340_eth_real_open(struct net_device *); +static int mv64340_eth_real_stop(struct net_device *); +static int mv64340_eth_change_mtu(struct net_device *, int); +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *); +static void eth_port_init_mac_tables(unsigned int eth_port_num); +#ifdef MV64340_NAPI +static int mv64340_poll(struct net_device *dev, int *budget); +#endif + +unsigned char prom_mac_addr_base[6]; +unsigned long mv64340_sram_base; + +/* + * Changes MTU (maximum transfer unit) of the gigabit ethenret port + * + * Input : pointer to ethernet interface network device structure + * new mtu size + * Output : 0 upon success, -EINVAL upon failure + */ +static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&mp->lock, flags); + + if ((new_mtu > 9500) || (new_mtu < 64)) { + spin_unlock_irqrestore(&mp->lock, flags); + return -EINVAL; + } + + dev->mtu = new_mtu; + /* + * Stop then re-open the interface. This will allocate RX skb's with + * the new MTU. + * There is a possible danger that the open will not successed, due + * to memory is full, which might fail the open function. + */ + if (netif_running(dev)) { + if (mv64340_eth_real_stop(dev)) + printk(KERN_ERR + "%s: Fatal error on stopping device\n", + dev->name); + if (mv64340_eth_real_open(dev)) + printk(KERN_ERR + "%s: Fatal error on opening device\n", + dev->name); + } + + spin_unlock_irqrestore(&mp->lock, flags); + return 0; +} + +/* + * mv64340_eth_rx_task + * + * Fills / refills RX queue on a certain gigabit ethernet port + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task(void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + struct sk_buff *skb; + + if (test_and_set_bit(0, &mp->rx_task_busy)) + panic("%s: Error in test_set_bit / clear_bit", dev->name); + + while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { + /* The +8 for buffer allignment and another 32 byte extra */ + + skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES); + if (!skb) + /* Better luck next time */ + break; + mp->rx_ring_skbs++; + pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; + pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES; + /* Allign buffer to 8 bytes */ + if (pkt_info.byte_cnt & ~0x7) { + pkt_info.byte_cnt &= ~0x7; + pkt_info.byte_cnt += 8; + } + pkt_info.buf_ptr = + pci_map_single(0, skb->data, + dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES, + PCI_DMA_FROMDEVICE); + pkt_info.return_info = skb; + if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { + printk(KERN_ERR + "%s: Error allocating RX Ring\n", dev->name); + break; + } + skb_reserve(skb, 2); + } + clear_bit(0, &mp->rx_task_busy); + /* + * If RX ring is empty of SKB, set a timer to try allocating + * again in a later time . + */ + if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) { + printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); + /* After 100mSec */ + mp->timeout.expires = jiffies + (HZ / 10); + add_timer(&mp->timeout); + mp->rx_timer_flag = 1; + } +#if MV64340_RX_QUEUE_FILL_ON_TASK + else { + /* Return interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num), + INT_CAUSE_UNMASK_ALL); + } +#endif +} + +/* + * mv64340_eth_rx_task_timer_wrapper + * + * Timer routine to wake up RX queue filling task. This function is + * used only in case the RX queue is empty, and all alloc_skb has + * failed (due to out of memory event). + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_rx_task_timer_wrapper(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct mv64340_private *mp = netdev_priv(dev); + + mp->rx_timer_flag = 0; + mv64340_eth_rx_task((void *) data); +} + + +/* + * mv64340_eth_update_mac_address + * + * Update the MAC address of the port in the address table + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_update_mac_address(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + eth_port_init_mac_tables(port_num); + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + eth_port_uc_addr_set(port_num, mp->port_mac_addr); +} + +/* + * mv64340_eth_set_rx_mode + * + * Change from promiscuos to regular rx mode + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void mv64340_eth_set_rx_mode(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + if (dev->flags & IFF_PROMISC) { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) | + ETH_UNICAST_PROMISCUOUS_MODE); + } else { + ethernet_set_config_reg + (mp->port_num, + ethernet_get_config_reg(mp->port_num) & + ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE); + } +} + + +/* + * mv64340_eth_set_mac_address + * + * Change the interface's mac address. + * No special hardware thing should be done because interface is always + * put in promiscuous mode. + * + * Input : pointer to ethernet interface network device structure and + * a pointer to the designated entry to be added to the cache. + * Output : zero upon success, negative upon failure + */ +static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr) +{ + int i; + + for (i = 0; i < 6; i++) + /* +2 is for the offset of the HW addr type */ + dev->dev_addr[i] = ((unsigned char *) addr)[i + 2]; + mv64340_eth_update_mac_address(dev); + return 0; +} + +/* + * mv64340_eth_tx_timeout + * + * Called upon a timeout on transmitting a packet + * + * Input : pointer to ethernet interface network device structure. + * Output : N/A + */ +static void mv64340_eth_tx_timeout(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + printk(KERN_INFO "%s: TX timeout ", dev->name); + + /* Do the reset outside of interrupt context */ + schedule_work(&mp->tx_timeout_task); +} + +/* + * mv64340_eth_tx_timeout_task + * + * Actual routine to reset the adapter when a timeout on Tx has occurred + */ +static void mv64340_eth_tx_timeout_task(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + netif_device_detach(dev); + eth_port_reset(mp->port_num); + eth_port_start(mp); + netif_device_attach(dev); +} + +/* + * mv64340_eth_free_tx_queue + * + * Input : dev - a pointer to the required interface + * + * Output : 0 if was able to release skb , nonzero otherwise + */ +static int mv64340_eth_free_tx_queue(struct net_device *dev, + unsigned int eth_int_cause_ext) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + struct pkt_info pkt_info; + int released = 1; + + if (!(eth_int_cause_ext & (BIT0 | BIT8))) + return released; + + spin_lock(&mp->lock); + + /* Check only queue 0 */ + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.cmd_sts & BIT0) { + printk("%s: Error in TX\n", dev->name); + stats->tx_errors++; + } + + /* + * If return_info is different than 0, release the skb. + * The case where return_info is not 0 is only in case + * when transmitted a scatter/gather packet, where only + * last skb releases the whole chain. + */ + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + released = 0; + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, PCI_DMA_TODEVICE); + + /* + * Decrement the number of outstanding skbs counter on + * the TX queue. + */ + if (mp->tx_ring_skbs == 0) + panic("ERROR - TX outstanding SKBs counter is corrupted"); + + } + + spin_unlock(&mp->lock); + + return released; +} + +/* + * mv64340_eth_receive + * + * This function is forward packets that are received from the port's + * queues toward kernel core or FastRoute them to another interface. + * + * Input : dev - a pointer to the required interface + * max - maximum number to receive (0 means unlimted) + * + * Output : number of served packets + */ +#ifdef MV64340_NAPI +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max, + int budget) +#else +static int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max) +#endif +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + unsigned int received_packets = 0; + struct sk_buff *skb; + struct pkt_info pkt_info; + +#ifdef MV64340_NAPI + while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) { +#else + while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) { +#endif + mp->rx_ring_skbs--; + received_packets++; +#ifdef MV64340_NAPI + budget--; +#endif + /* Update statistics. Note byte count includes 4 byte CRC count */ + stats->rx_packets++; + stats->rx_bytes += pkt_info.byte_cnt; + skb = (struct sk_buff *) pkt_info.return_info; + /* + * In case received a packet without first / last bits on OR + * the error summary bit is on, the packets needs to be dropeed. + */ + if (((pkt_info.cmd_sts + & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) + || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) { + stats->rx_dropped++; + if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC | + ETH_RX_LAST_DESC)) != + (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) { + if (net_ratelimit()) + printk(KERN_ERR + "%s: Received packet spread on multiple" + " descriptors\n", + dev->name); + } + if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb_irq(skb); + } else { + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, pkt_info.byte_cnt - 4); + skb->dev = dev; + + if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum = htons((pkt_info.cmd_sts + & 0x0007fff8) >> 3); + } + skb->protocol = eth_type_trans(skb, dev); +#ifdef MV64340_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + return received_packets; +} + +/* + * mv64340_eth_int_handler + * + * Main interrupt handler for the gigbit ethernet ports + * + * Input : irq - irq number (not used) + * dev_id - a pointer to the required interface's data structure + * regs - not used + * Output : N/A + */ + +static irqreturn_t mv64340_eth_int_handler(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct mv64340_private *mp = netdev_priv(dev); + u32 eth_int_cause, eth_int_cause_ext = 0; + unsigned int port_num = mp->port_num; + + /* Read interrupt cause registers */ + eth_int_cause = MV_READ(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num)) & + INT_CAUSE_UNMASK_ALL; + + if (eth_int_cause & BIT1) + eth_int_cause_ext = + MV_READ(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & + INT_CAUSE_UNMASK_ALL_EXT; + +#ifdef MV64340_NAPI + if (!(eth_int_cause & 0x0007fffd)) { + /* Dont ack the Rx interrupt */ +#endif + /* + * Clear specific ethernet port intrerrupt registers by + * acknowleding relevant bits. + */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), + ~eth_int_cause); + if (eth_int_cause_ext != 0x0) + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), + ~eth_int_cause_ext); + + /* UDP change : We may need this */ + if ((eth_int_cause_ext & 0x0000ffff) && + (mv64340_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && + (MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1)) + netif_wake_queue(dev); +#ifdef MV64340_NAPI + } else { + if (netif_rx_schedule_prep(dev)) { + /* Mask all the interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + __netif_rx_schedule(dev); + } +#else + { + if (eth_int_cause & (BIT2 | BIT11)) + mv64340_eth_receive_queue(dev, 0); + + /* + * After forwarded received packets to upper layer, add a task + * in an interrupts enabled context that refills the RX ring + * with skb's. + */ +#if MV64340_RX_QUEUE_FILL_ON_TASK + /* Unmask all interrupts on ethernet port */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_MASK_ALL); + queue_task(&mp->rx_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + mp->rx_task.func(dev); +#endif +#endif + } + /* PHY status changed */ + if (eth_int_cause_ext & (BIT16 | BIT20)) { + unsigned int phy_reg_data; + + /* Check Link status on ethernet port */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) { + netif_stop_queue(dev); + } else { + netif_wake_queue(dev); + + /* + * Start all TX queues on ethernet port. This is good in + * case of previous packets where not transmitted, due + * to link down and this command re-enables all TX + * queues. + * Note that it is possible to get a TX resource error + * interrupt after issuing this, since not all TX queues + * are enabled, or has anything to send. + */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 1); + } + } + + /* + * If no real interrupt occured, exit. + * This can happen when using gigE interrupt coalescing mechanism. + */ + if ((eth_int_cause == 0x0) && (eth_int_cause_ext == 0x0)) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +#ifdef MV64340_COAL + +/* + * eth_port_set_rx_coal - Sets coalescing interrupt mechanism on RX path + * + * DESCRIPTION: + * This routine sets the RX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the tClk of the MV-643xx chip + * , and the required delay of the interrupt in usec. + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in usec + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal = ((t_clk / 1000000) * delay) / 64; + + /* Set RX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + ((coal & 0x3fff) << 8) | + (MV_READ(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num)) + & 0xffc000ff)); + + return coal; +} +#endif + +/* + * eth_port_set_tx_coal - Sets coalescing interrupt mechanism on TX path + * + * DESCRIPTION: + * This routine sets the TX coalescing interrupt mechanism parameter. + * This parameter is a timeout counter, that counts in 64 t_clk + * chunks ; that when timeout event occurs a maskable interrupt + * occurs. + * The parameter is calculated using the t_cLK frequency of the + * MV-643xx chip and the required delay in the interrupt in uSec + * + * INPUT: + * unsigned int eth_port_num Ethernet port number + * unsigned int t_clk t_clk of the MV-643xx chip in HZ units + * unsigned int delay Delay in uSeconds + * + * OUTPUT: + * Interrupt coalescing mechanism value is set in MV-643xx chip. + * + * RETURN: + * The interrupt coalescing value set in the gigE port. + * + */ +static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num, + unsigned int t_clk, unsigned int delay) +{ + unsigned int coal; + coal = ((t_clk / 1000000) * delay) / 64; + /* Set TX Coalescing mechanism */ + MV_WRITE(MV64340_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), + coal << 4); + return coal; +} + +/* + * mv64340_eth_open + * + * This function is called when openning the network device. The function + * should initialize all the hardware, initialize cyclic Rx/Tx + * descriptors chain and buffers and allocate an IRQ to the network + * device. + * + * Input : a pointer to the network device structure + * + * Output : zero of success , nonzero if fails. + */ + +static int mv64340_eth_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int err = err; + + spin_lock_irq(&mp->lock); + + err = request_irq(dev->irq, mv64340_eth_int_handler, + SA_INTERRUPT | SA_SAMPLE_RANDOM, dev->name, dev); + + if (err) { + printk(KERN_ERR "Can not assign IRQ number to MV64340_eth%d\n", + port_num); + err = -EAGAIN; + goto out; + } + + if (mv64340_eth_real_open(dev)) { + printk("%s: Error opening interface\n", dev->name); + err = -EBUSY; + goto out_free; + } + + spin_unlock_irq(&mp->lock); + + return 0; + +out_free: + free_irq(dev->irq, dev); + +out: + spin_unlock_irq(&mp->lock); + + return err; +} + +/* + * ether_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Rx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int rx_desc_num Number of Rx descriptors + * int rx_buff_size Size of Rx buffer + * unsigned int rx_desc_base_addr Rx descriptors memory area base addr. + * unsigned int rx_buff_base_addr Rx buffer memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Rx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_rx_desc_ring(struct mv64340_private * mp, + unsigned long rx_buff_base_addr) +{ + unsigned long buffer_addr = rx_buff_base_addr; + volatile struct eth_rx_desc *p_rx_desc; + int rx_desc_num = mp->rx_ring_size; + unsigned long rx_desc_base_addr = (unsigned long) mp->p_rx_desc_area; + int rx_buff_size = 1536; /* Dummy, will be replaced later */ + int i; + + p_rx_desc = (struct eth_rx_desc *) rx_desc_base_addr; + + /* Rx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (rx_buff_base_addr & 0xf) + return 0; + + /* Rx buffers are limited to 64K bytes and Minimum size is 8 bytes */ + if ((rx_buff_size < 8) || (rx_buff_size > RX_BUFFER_MAX_SIZE)) + return 0; + + /* Rx buffers must be 64-bit aligned. */ + if ((rx_buff_base_addr + rx_buff_size) & 0x7) + return 0; + + /* initialize the Rx descriptors ring */ + for (i = 0; i < rx_desc_num; i++) { + p_rx_desc[i].buf_size = rx_buff_size; + p_rx_desc[i].byte_cnt = 0x0000; + p_rx_desc[i].cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + p_rx_desc[i].next_desc_ptr = + (struct eth_rx_desc *) mp->rx_desc_dma + + (i + 1) % rx_desc_num; + p_rx_desc[i].buf_ptr = buffer_addr; + + mp->rx_skb[i] = NULL; + buffer_addr += rx_buff_size; + } + + /* Save Rx desc pointer to driver struct. */ + mp->rx_curr_desc_q = 0; + mp->rx_used_desc_q = 0; + + mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); + + mp->port_rx_queue_command |= 1; + + return 1; +} + +/* + * ether_init_tx_desc_ring - Curve a Tx chain desc list and buffer in memory. + * + * DESCRIPTION: + * This function prepares a Tx chained list of descriptors and packet + * buffers in a form of a ring. The routine must be called after port + * initialization routine and before port start routine. + * The Ethernet SDMA engine uses CPU bus addresses to access the various + * devices in the system (i.e. DRAM). This function uses the ethernet + * struct 'virtual to physical' routine (set by the user) to set the ring + * with physical addresses. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * int tx_desc_num Number of Tx descriptors + * int tx_buff_size Size of Tx buffer + * unsigned int tx_desc_base_addr Tx descriptors memory area base addr. + * + * OUTPUT: + * The routine updates the Ethernet port control struct with information + * regarding the Tx descriptors and buffers. + * + * RETURN: + * false if the given descriptors memory area is not aligned according to + * Ethernet SDMA specifications. + * true otherwise. + */ +static int ether_init_tx_desc_ring(struct mv64340_private *mp) +{ + unsigned long tx_desc_base_addr = (unsigned long) mp->p_tx_desc_area; + int tx_desc_num = mp->tx_ring_size; + struct eth_tx_desc *p_tx_desc; + int i; + + /* Tx desc Must be 4LW aligned (i.e. Descriptor_Address[3:0]=0000). */ + if (tx_desc_base_addr & 0xf) + return 0; + + /* save the first desc pointer to link with the last descriptor */ + p_tx_desc = (struct eth_tx_desc *) tx_desc_base_addr; + + /* Initialize the Tx descriptors ring */ + for (i = 0; i < tx_desc_num; i++) { + p_tx_desc[i].byte_cnt = 0x0000; + p_tx_desc[i].l4i_chk = 0x0000; + p_tx_desc[i].cmd_sts = 0x00000000; + p_tx_desc[i].next_desc_ptr = + (struct eth_tx_desc *) mp->tx_desc_dma + + (i + 1) % tx_desc_num; + p_tx_desc[i].buf_ptr = 0x00000000; + mp->tx_skb[i] = NULL; + } + + /* Set Tx desc pointer in driver struct. */ + mp->tx_curr_desc_q = 0; + mp->tx_used_desc_q = 0; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + mp->tx_first_desc_q = 0; +#endif + /* Init Tx ring base and size parameters */ + mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); + + /* Add the queue to the list of Tx queues of this port */ + mp->port_tx_queue_command |= 1; + + return 1; +} + +/* Helper function for mv64340_eth_open */ +static int mv64340_eth_real_open(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + u32 phy_reg_data; + unsigned int size; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Clear the ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Unmask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + + /* Unmask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + + /* Set the MAC Address */ + memcpy(mp->port_mac_addr, dev->dev_addr, 6); + + eth_port_init(mp); + + INIT_WORK(&mp->rx_task, (void (*)(void *)) mv64340_eth_rx_task, dev); + + memset(&mp->timeout, 0, sizeof(struct timer_list)); + mp->timeout.function = mv64340_eth_rx_task_timer_wrapper; + mp->timeout.data = (unsigned long) dev; + + mp->rx_task_busy = 0; + mp->rx_timer_flag = 0; + + /* Allocate TX ring */ + mp->tx_ring_skbs = 0; + mp->tx_ring_size = MV64340_TX_QUEUE_SIZE; + size = mp->tx_ring_size * sizeof(struct eth_tx_desc); + mp->tx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes alligned */ + mp->p_tx_desc_area = pci_alloc_consistent(NULL, size, &mp->tx_desc_dma); + if (!mp->p_tx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + dev->name, size); + return -ENOMEM; + } + memset((void *) mp->p_tx_desc_area, 0, mp->tx_desc_area_size); + + /* Dummy will be replaced upon real tx */ + ether_init_tx_desc_ring(mp); + + /* Allocate RX ring */ + /* Meantime RX Ring are fixed - but must be configurable by user */ + mp->rx_ring_size = MV64340_RX_QUEUE_SIZE; + mp->rx_ring_skbs = 0; + size = mp->rx_ring_size * sizeof(struct eth_rx_desc); + mp->rx_desc_area_size = size; + + /* Assumes allocated ring is 16 bytes aligned */ + + mp->p_rx_desc_area = pci_alloc_consistent(NULL, size, &mp->rx_desc_dma); + + if (!mp->p_rx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Rx ring (size %d bytes)\n", + dev->name, size); + printk(KERN_ERR "%s: Freeing previously allocated TX queues...", + dev->name); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, + mp->tx_desc_dma); + return -ENOMEM; + } + memset(mp->p_rx_desc_area, 0, size); + + if (!(ether_init_rx_desc_ring(mp, 0))) + panic("%s: Error initializing RX Ring", dev->name); + + mv64340_eth_rx_task(dev); /* Fill RX ring with skb's */ + + eth_port_start(mp); + + /* Interrupt Coalescing */ + +#ifdef MV64340_COAL + mp->rx_int_coal = + eth_port_set_rx_coal(port_num, 133000000, MV64340_RX_COAL); +#endif + + mp->tx_int_coal = + eth_port_set_tx_coal (port_num, 133000000, MV64340_TX_COAL); + + /* Increase the Rx side buffer size */ + + MV_WRITE (MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num), (0x5 << 17) | + (MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG(port_num)) + & 0xfff1ffff)); + + /* Check Link status on phy */ + eth_port_read_smi_reg(port_num, 1, &phy_reg_data); + if (!(phy_reg_data & 0x20)) + netif_stop_queue(dev); + else + netif_start_queue(dev); + + return 0; +} + +static void mv64340_eth_free_tx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + unsigned int curr; + + /* Stop Tx Queues */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free TX rings */ + /* Free outstanding skb's on TX rings */ + for (curr = 0; + (mp->tx_ring_skbs) && (curr < MV64340_TX_QUEUE_SIZE); + curr++) { + if (mp->tx_skb[curr]) { + dev_kfree_skb(mp->tx_skb[curr]); + mp->tx_ring_skbs--; + } + } + if (mp->tx_ring_skbs != 0) + printk("%s: Error on Tx descriptor free - could not free %d" + " descriptors\n", dev->name, + mp->tx_ring_skbs); + pci_free_consistent(0, mp->tx_desc_area_size, + (void *) mp->p_tx_desc_area, mp->tx_desc_dma); +} + +static void mv64340_eth_free_rx_rings(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + int curr; + + /* Stop RX Queues */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + 0x0000ff00); + + /* Free RX rings */ + /* Free preallocated skb's on RX rings */ + for (curr = 0; + mp->rx_ring_skbs && (curr < MV64340_RX_QUEUE_SIZE); + curr++) { + if (mp->rx_skb[curr]) { + dev_kfree_skb(mp->rx_skb[curr]); + mp->rx_ring_skbs--; + } + } + + if (mp->rx_ring_skbs != 0) + printk(KERN_ERR + "%s: Error in freeing Rx Ring. %d skb's still" + " stuck in RX Ring - ignoring them\n", dev->name, + mp->rx_ring_skbs); + pci_free_consistent(0, mp->rx_desc_area_size, + (void *) mp->p_rx_desc_area, + mp->rx_desc_dma); +} + +/* + * mv64340_eth_stop + * + * This function is used when closing the network device. + * It updates the hardware, + * release all memory that holds buffers and descriptors and release the IRQ. + * Input : a pointer to the device structure + * Output : zero if success , nonzero if fails + */ + +/* Helper function for mv64340_eth_stop */ + +static int mv64340_eth_real_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + unsigned int port_num = mp->port_num; + + netif_stop_queue(dev); + + mv64340_eth_free_tx_rings(dev); + mv64340_eth_free_rx_rings(dev); + + eth_port_reset(mp->port_num); + + /* Disable ethernet port interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + + /* Mask RX buffer and TX end interrupt */ + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), 0); + + /* Mask phy and link status changes interrupts */ + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), 0); + + return 0; +} + +static int mv64340_eth_stop(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + spin_lock_irq(&mp->lock); + + mv64340_eth_real_stop(dev); + + free_irq(dev->irq, dev); + spin_unlock_irq(&mp->lock); + + return 0; +} + +#ifdef MV64340_NAPI +static void mv64340_tx(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct pkt_info pkt_info; + + while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { + if (pkt_info.return_info) { + dev_kfree_skb_irq((struct sk_buff *) + pkt_info.return_info); + if (skb_shinfo(pkt_info.return_info)->nr_frags) + pci_unmap_page(NULL, pkt_info.buf_ptr, + pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + + if (mp->tx_ring_skbs != 1) + mp->tx_ring_skbs--; + } else + pci_unmap_page(NULL, pkt_info.buf_ptr, pkt_info.byte_cnt, + PCI_DMA_TODEVICE); + } + + if (netif_queue_stopped(dev) && + MV64340_TX_QUEUE_SIZE > mp->tx_ring_skbs + 1) + netif_wake_queue(dev); +} + +/* + * mv64340_poll + * + * This function is used in case of NAPI + */ +static int mv64340_poll(struct net_device *dev, int *budget) +{ + struct mv64340_private *mp = netdev_priv(dev); + int done = 1, orig_budget, work_done; + unsigned int port_num = mp->port_num; + unsigned long flags; + +#ifdef MV64340_TX_FAST_REFILL + if (++mp->tx_clean_threshold > 5) { + spin_lock_irqsave(&mp->lock, flags); + mv64340_tx(dev); + mp->tx_clean_threshold = 0; + spin_unlock_irqrestore(&mp->lock, flags); + } +#endif + + if ((u32)(MV_READ(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num))) != (u32)mp->rx_used_desc_q) { + orig_budget = *budget; + if (orig_budget > dev->quota) + orig_budget = dev->quota; + work_done = mv64340_eth_receive_queue(dev, 0, orig_budget); + mp->rx_task.func(dev); + *budget -= work_done; + dev->quota -= work_done; + if (work_done >= orig_budget) + done = 0; + } + + if (done) { + spin_lock_irqsave(&mp->lock, flags); + __netif_rx_complete(dev); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),0); + MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL); + MV_WRITE(MV64340_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), + INT_CAUSE_UNMASK_ALL_EXT); + spin_unlock_irqrestore(&mp->lock, flags); + } + + return done ? 0 : 1; +} +#endif + +/* + * mv64340_eth_start_xmit + * + * This function is queues a packet in the Tx descriptor for + * required port. + * + * Input : skb - a pointer to socket buffer + * dev - a pointer to the required port + * + * Output : zero upon success + */ +static int mv64340_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + ETH_FUNC_RET_STATUS status; + unsigned long flags; + struct pkt_info pkt_info; + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR + "%s: Tried sending packet when interface is stopped\n", + dev->name); + return 1; + } + + /* This is a hard error, log it. */ + if ((MV64340_TX_QUEUE_SIZE - mp->tx_ring_skbs) <= + (skb_shinfo(skb)->nr_frags + 1)) { + netif_stop_queue(dev); + printk(KERN_ERR + "%s: Bug in mv64340_eth - Trying to transmit when" + " queue full !\n", dev->name); + return 1; + } + + /* Paranoid check - this shouldn't happen */ + if (skb == NULL) { + stats->tx_dropped++; + return 1; + } + + spin_lock_irqsave(&mp->lock, flags); + + /* Update packet info data structure -- DMA owned, first last */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (!skb_shinfo(skb)->nr_frags || (skb_shinfo(skb)->nr_frags > 3)) { +#endif + pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | + ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + + pkt_info.byte_cnt = skb->len; + pkt_info.buf_ptr = pci_map_single(0, skb->data, skb->len, + PCI_DMA_TODEVICE); + + + pkt_info.return_info = skb; + status = eth_port_send(mp, &pkt_info); + if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) + printk(KERN_ERR "%s: Error on transmitting packet\n", + dev->name); + mp->tx_ring_skbs++; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + } else { + unsigned int frag; + u32 ipheader; + + /* first frag which is skb header */ + pkt_info.byte_cnt = skb_headlen(skb); + pkt_info.buf_ptr = pci_map_single(0, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + pkt_info.return_info = 0; + ipheader = skb->nh.iph->ihl << 11; + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + ipheader; + /* CPU already calculated pseudo header checksum. So, use it */ + pkt_info.l4i_chk = skb->h.th->check; + status = eth_port_send(mp, &pkt_info); + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + if (status == ETH_QUEUE_FULL) + printk("Error on Queue Full \n"); + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + } + + /* Check for the remaining frags */ + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + pkt_info.l4i_chk = 0x0000; + pkt_info.cmd_sts = 0x00000000; + + /* Last Frag enables interrupt and frees the skb */ + if (frag == (skb_shinfo(skb)->nr_frags - 1)) { + pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | + ETH_TX_LAST_DESC; + pkt_info.return_info = skb; + mp->tx_ring_skbs++; + } + else { + pkt_info.return_info = 0; + } + pkt_info.byte_cnt = this_frag->size; + if (this_frag->size < 8) + printk("%d : \n", skb_shinfo(skb)->nr_frags); + + pkt_info.buf_ptr = pci_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, PCI_DMA_TODEVICE); + + status = eth_port_send(mp, &pkt_info); + + if (status != ETH_OK) { + if ((status == ETH_ERROR)) + printk(KERN_ERR "%s: Error on transmitting packet\n", dev->name); + + if (status == ETH_QUEUE_LAST_RESOURCE) + printk("Tx resource error \n"); + + if (status == ETH_QUEUE_FULL) + printk("Queue is full \n"); + } + } + } +#endif + + /* Check if TX queue can handle another skb. If not, then + * signal higher layers to stop requesting TX + */ + if (MV64340_TX_QUEUE_SIZE <= (mp->tx_ring_skbs + 1)) + /* + * Stop getting skb's from upper layers. + * Getting skb's from upper layers will be enabled again after + * packets are released. + */ + netif_stop_queue(dev); + + /* Update statistics and start of transmittion time */ + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; + + spin_unlock_irqrestore(&mp->lock, flags); + + return 0; /* success */ +} + +/* + * mv64340_eth_get_stats + * + * Returns a pointer to the interface statistics. + * + * Input : dev - a pointer to the required interface + * + * Output : a pointer to the interface's statistics + */ + +static struct net_device_stats *mv64340_eth_get_stats(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + return &mp->stats; +} + +/*/ + * mv64340_eth_init + * + * First function called after registering the network device. + * It's purpose is to initialize the device as an ethernet device, + * fill the structure that was given in registration with pointers + * to functions, and setting the MAC address of the interface + * + * Input : number of port to initialize + * Output : -ENONMEM if failed , 0 if success + */ +static struct net_device *mv64340_eth_init(int port_num) +{ + struct mv64340_private *mp; + struct net_device *dev; + int err; + + dev = alloc_etherdev(sizeof(struct mv64340_private)); + if (!dev) + return NULL; + + mp = netdev_priv(dev); + + dev->irq = ETH_PORT0_IRQ_NUM + port_num; + + dev->open = mv64340_eth_open; + dev->stop = mv64340_eth_stop; + dev->hard_start_xmit = mv64340_eth_start_xmit; + dev->get_stats = mv64340_eth_get_stats; + dev->set_mac_address = mv64340_eth_set_mac_address; + dev->set_multicast_list = mv64340_eth_set_rx_mode; + + /* No need to Tx Timeout */ + dev->tx_timeout = mv64340_eth_tx_timeout; +#ifdef MV64340_NAPI + dev->poll = mv64340_poll; + dev->weight = 64; +#endif + + dev->watchdog_timeo = 2 * HZ; + dev->tx_queue_len = MV64340_TX_QUEUE_SIZE; + dev->base_addr = 0; + dev->change_mtu = mv64340_eth_change_mtu; + +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +#ifdef MAX_SKB_FRAGS +#ifndef CONFIG_JAGUAR_DMALOW + /* + * Zero copy can only work if we use Discovery II memory. Else, we will + * have to map the buffers to ISA memory which is only 16 MB + */ + dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HW_CSUM; +#endif +#endif +#endif + + mp->port_num = port_num; + + /* Configure the timeout task */ + INIT_WORK(&mp->tx_timeout_task, + (void (*)(void *))mv64340_eth_tx_timeout_task, dev); + + spin_lock_init(&mp->lock); + + /* set MAC addresses */ + memcpy(dev->dev_addr, prom_mac_addr_base, 6); + dev->dev_addr[5] += port_num; + + err = register_netdev(dev); + if (err) + goto out_free_dev; + + printk(KERN_NOTICE "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, port_num, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + if (dev->features & NETIF_F_SG) + printk("Scatter Gather Enabled "); + + if (dev->features & NETIF_F_IP_CSUM) + printk("TX TCP/IP Checksumming Supported \n"); + + printk("RX TCP/UDP Checksum Offload ON, \n"); + printk("TX and RX Interrupt Coalescing ON \n"); + +#ifdef MV64340_NAPI + printk("RX NAPI Enabled \n"); +#endif + + return dev; + +out_free_dev: + free_netdev(dev); + + return NULL; +} + +static void mv64340_eth_remove(struct net_device *dev) +{ + struct mv64340_private *mp = netdev_priv(dev); + + unregister_netdev(dev); + flush_scheduled_work(); + free_netdev(dev); +} + +static struct net_device *mv64340_dev0; +static struct net_device *mv64340_dev1; +static struct net_device *mv64340_dev2; + +/* + * mv64340_init_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static int __init mv64340_init_module(void) +{ + printk(KERN_NOTICE "MV-64340 10/100/1000 Ethernet Driver\n"); + +#ifdef CONFIG_MV64340_ETH_0 + mv64340_dev0 = mv64340_eth_init(0); + if (!mv64340_dev0) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 0\n"); + } +#endif +#ifdef CONFIG_MV64340_ETH_1 + mv64340_dev1 = mv64340_eth_init(1); + if (!mv64340_dev1) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 1\n"); + } +#endif +#ifdef CONFIG_MV64340_ETH_2 + mv64340_dev2 = mv64340_eth_init(2); + if (!mv64340_dev2) { + printk(KERN_ERR + "Error registering MV-64360 ethernet port 2\n"); + } +#endif + return 0; +} + +/* + * mv64340_cleanup_module + * + * Registers the network drivers into the Linux kernel + * + * Input : N/A + * + * Output : N/A + */ +static void __exit mv64340_cleanup_module(void) +{ + if (mv64340_dev2) + mv64340_eth_remove(mv64340_dev2); + if (mv64340_dev1) + mv64340_eth_remove(mv64340_dev1); + if (mv64340_dev0) + mv64340_eth_remove(mv64340_dev0); +} + +module_init(mv64340_init_module); +module_exit(mv64340_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rabeeh Khoury, Assaf Hoffman, Matthew Dharm and Manish Lachwani"); +MODULE_DESCRIPTION("Ethernet driver for Marvell MV64340"); + +/* + * The second part is the low level driver of the gigE ethernet ports. + */ + +/* + * Marvell's Gigabit Ethernet controller low level driver + * + * DESCRIPTION: + * This file introduce low level API to Marvell's Gigabit Ethernet + * controller. This Gigabit Ethernet Controller driver API controls + * 1) Operations (i.e. port init, start, reset etc'). + * 2) Data flow (i.e. port send, receive etc'). + * Each Gigabit Ethernet port is controlled via + * struct mv64340_private. + * This struct includes user configuration information as well as + * driver internal data needed for its operations. + * + * Supported Features: + * - This low level driver is OS independent. Allocating memory for + * the descriptor rings and buffers are not within the scope of + * this driver. + * - The user is free from Rx/Tx queue managing. + * - This low level driver introduce functionality API that enable + * the to operate Marvell's Gigabit Ethernet Controller in a + * convenient way. + * - Simple Gigabit Ethernet port operation API. + * - Simple Gigabit Ethernet port data flow API. + * - Data flow and operation API support per queue functionality. + * - Support cached descriptors for better performance. + * - Enable access to all four DRAM banks and internal SRAM memory + * spaces. + * - PHY access and control API. + * - Port control register configuration API. + * - Full control over Unicast and Multicast MAC configurations. + * + * Operation flow: + * + * Initialization phase + * This phase complete the initialization of the the mv64340_private + * struct. + * User information regarding port configuration has to be set + * prior to calling the port initialization routine. + * + * In this phase any port Tx/Rx activity is halted, MIB counters + * are cleared, PHY address is set according to user parameter and + * access to DRAM and internal SRAM memory spaces. + * + * Driver ring initialization + * Allocating memory for the descriptor rings and buffers is not + * within the scope of this driver. Thus, the user is required to + * allocate memory for the descriptors ring and buffers. Those + * memory parameters are used by the Rx and Tx ring initialization + * routines in order to curve the descriptor linked list in a form + * of a ring. + * Note: Pay special attention to alignment issues when using + * cached descriptors/buffers. In this phase the driver store + * information in the mv64340_private struct regarding each queue + * ring. + * + * Driver start + * This phase prepares the Ethernet port for Rx and Tx activity. + * It uses the information stored in the mv64340_private struct to + * initialize the various port registers. + * + * Data flow: + * All packet references to/from the driver are done using + * struct pkt_info. + * This struct is a unified struct used with Rx and Tx operations. + * This way the user is not required to be familiar with neither + * Tx nor Rx descriptors structures. + * The driver's descriptors rings are management by indexes. + * Those indexes controls the ring resources and used to indicate + * a SW resource error: + * 'current' + * This index points to the current available resource for use. For + * example in Rx process this index will point to the descriptor + * that will be passed to the user upon calling the receive routine. + * In Tx process, this index will point to the descriptor + * that will be assigned with the user packet info and transmitted. + * 'used' + * This index points to the descriptor that need to restore its + * resources. For example in Rx process, using the Rx buffer return + * API will attach the buffer returned in packet info to the + * descriptor pointed by 'used'. In Tx process, using the Tx + * descriptor return will merely return the user packet info with + * the command status of the transmitted buffer pointed by the + * 'used' index. Nevertheless, it is essential to use this routine + * to update the 'used' index. + * 'first' + * This index supports Tx Scatter-Gather. It points to the first + * descriptor of a packet assembled of multiple buffers. For example + * when in middle of Such packet we have a Tx resource error the + * 'curr' index get the value of 'first' to indicate that the ring + * returned to its state before trying to transmit this packet. + * + * Receive operation: + * The eth_port_receive API set the packet information struct, + * passed by the caller, with received information from the + * 'current' SDMA descriptor. + * It is the user responsibility to return this resource back + * to the Rx descriptor ring to enable the reuse of this source. + * Return Rx resource is done using the eth_rx_return_buff API. + * + * Transmit operation: + * The eth_port_send API supports Scatter-Gather which enables to + * send a packet spanned over multiple buffers. This means that + * for each packet info structure given by the user and put into + * the Tx descriptors ring, will be transmitted only if the 'LAST' + * bit will be set in the packet info command status field. This + * API also consider restriction regarding buffer alignments and + * sizes. + * The user must return a Tx resource after ensuring the buffer + * has been transmitted to enable the Tx ring indexes to update. + * + * BOARD LAYOUT + * This device is on-board. No jumper diagram is necessary. + * + * EXTERNAL INTERFACE + * + * Prior to calling the initialization routine eth_port_init() the user + * must set the following fields under mv64340_private struct: + * port_num User Ethernet port number. + * port_mac_addr[6] User defined port MAC address. + * port_config User port configuration value. + * port_config_extend User port config extend value. + * port_sdma_config User port SDMA config value. + * port_serial_control User port serial control value. + * + * This driver introduce a set of default values: + * PORT_CONFIG_VALUE Default port configuration value + * PORT_CONFIG_EXTEND_VALUE Default port extend configuration value + * PORT_SDMA_CONFIG_VALUE Default sdma control value + * PORT_SERIAL_CONTROL_VALUE Default port serial control value + * + * This driver data flow is done using the struct pkt_info which + * is a unified struct for Rx and Tx operations: + * + * byte_cnt Tx/Rx descriptor buffer byte count. + * l4i_chk CPU provided TCP Checksum. For Tx operation + * only. + * cmd_sts Tx/Rx descriptor command status. + * buf_ptr Tx/Rx descriptor buffer pointer. + * return_info Tx/Rx user resource return information. + */ + +/* defines */ +/* SDMA command macros */ +#define ETH_ENABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) + +#define ETH_DISABLE_TX_QUEUE(eth_port) \ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), \ + (1 << 8)) + +#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << rx_queue)) + +#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), \ + (1 << (8 + rx_queue))) + +#define LINK_UP_TIMEOUT 100000 +#define PHY_BUSY_TIMEOUT 10000000 + +/* locals */ + +/* PHY routines */ +#ifdef MDD_CUT +static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); +#endif +static int ethernet_phy_get(unsigned int eth_port_num); + +/* Ethernet Port routines */ +static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, + int option); + +#ifdef MDD_CUT +static void eth_b_copy(unsigned int src_addr, unsigned int dst_addr, + int byte_count); +#endif + +/* + * eth_port_init - Initialize the Ethernet port driver + * + * DESCRIPTION: + * This function prepares the ethernet port to start its activity: + * 1) Completes the ethernet port driver struct initialization toward port + * start routine. + * 2) Resets the device to a quiescent state in case of warm reboot. + * 3) Enable SDMA access to all four DRAM banks as well as internal SRAM. + * 4) Clean MAC tables. The reset status of those tables is unknown. + * 5) Set PHY address. + * Note: Call this routine prior to eth_port_start routine and after + * setting user values in the user fields of Ethernet port control + * struct. + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * See description. + * + * RETURN: + * None. + */ +static void eth_port_init(struct mv64340_private * mp) +{ + mp->port_config = PORT_CONFIG_VALUE; + mp->port_config_extend = PORT_CONFIG_EXTEND_VALUE; +#if defined(__BIG_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE; +#elif defined(__LITTLE_ENDIAN) + mp->port_sdma_config = PORT_SDMA_CONFIG_VALUE | + ETH_BLM_RX_NO_SWAP | ETH_BLM_TX_NO_SWAP; +#else +#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be defined! +#endif + mp->port_serial_control = PORT_SERIAL_CONTROL_VALUE; + + mp->port_rx_queue_command = 0; + mp->port_tx_queue_command = 0; + + mp->rx_resource_err = 0; + mp->tx_resource_err = 0; + + eth_port_reset(mp->port_num); + + eth_port_init_mac_tables(mp->port_num); + + ethernet_phy_reset(mp->port_num); +} + +/* + * eth_port_start - Start the Ethernet port activity. + * + * DESCRIPTION: + * This routine prepares the Ethernet port for Rx and Tx activity: + * 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that + * has been initialized a descriptor's ring (using + * ether_init_tx_desc_ring for Tx and ether_init_rx_desc_ring for Rx) + * 2. Initialize and enable the Ethernet configuration port by writing to + * the port's configuration and command registers. + * 3. Initialize and enable the SDMA by writing to the SDMA's + * configuration and command registers. After completing these steps, + * the ethernet port SDMA can starts to perform Rx and Tx activities. + * + * Note: Each Rx and Tx queue descriptor's list must be initialized prior + * to calling this function (use ether_init_tx_desc_ring for Tx queues + * and ether_init_rx_desc_ring for Rx queues). + * + * INPUT: + * struct mv64340_private *mp Ethernet port control struct + * + * OUTPUT: + * Ethernet port is ready to receive and transmit. + * + * RETURN: + * false if the port PHY is not up. + * true otherwise. + */ +static int eth_port_start(struct mv64340_private *mp) +{ + unsigned int eth_port_num = mp->port_num; + int tx_curr_desc, rx_curr_desc; + unsigned int phy_reg_data; + + /* Assignment of Tx CTRP of given queue */ + tx_curr_desc = mp->tx_curr_desc_q; + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_tx_desc *) mp->tx_desc_dma + tx_curr_desc); + + /* Assignment of Rx CRDP of given queue */ + rx_curr_desc = mp->rx_curr_desc_q; + MV_WRITE(MV64340_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(eth_port_num), + (struct eth_rx_desc *) mp->rx_desc_dma + rx_curr_desc); + + /* Add the assigned Ethernet address to the port's address table */ + eth_port_uc_addr_set(mp->port_num, mp->port_mac_addr); + + /* Assign port configuration and command. */ + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + mp->port_config); + + MV_WRITE(MV64340_ETH_PORT_CONFIG_EXTEND_REG(eth_port_num), + mp->port_config_extend); + + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + mp->port_serial_control); + + MV_SET_REG_BITS(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), + ETH_SERIAL_PORT_ENABLE); + + /* Assign port SDMA configuration */ + MV_WRITE(MV64340_ETH_SDMA_CONFIG_REG(eth_port_num), + mp->port_sdma_config); + + /* Enable port Rx. */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port_num), + mp->port_rx_queue_command); + + /* Check if link is up */ + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (!(phy_reg_data & 0x20)) + return 0; + + return 1; +} + +/* + * eth_port_uc_addr_set - This function Set the port Unicast address. + * + * DESCRIPTION: + * This function Set the port Ethernet MAC address. + * + * INPUT: + * unsigned int eth_port_num Port number. + * char * p_addr Address to be set + * + * OUTPUT: + * Set MAC address low and high registers. also calls eth_port_uc_addr() + * To set the unicast table with the proper information. + * + * RETURN: + * N/A. + * + */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr) +{ + unsigned int mac_h; + unsigned int mac_l; + + mac_l = (p_addr[4] << 8) | (p_addr[5]); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | + (p_addr[2] << 8) | (p_addr[3] << 0); + + MV_WRITE(MV64340_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); + MV_WRITE(MV64340_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); + + /* Accept frames of this address */ + eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR); + + return; +} + +/* + * eth_port_uc_addr - This function Set the port unicast address table + * + * DESCRIPTION: + * This function locates the proper entry in the Unicast table for the + * specified MAC nibble and sets its properties according to function + * parameters. + * + * INPUT: + * unsigned int eth_port_num Port number. + * unsigned char uc_nibble Unicast MAC Address last nibble. + * int option 0 = Add, 1 = remove address. + * + * OUTPUT: + * This function add/removes MAC addresses from the port unicast address + * table. + * + * RETURN: + * true is output succeeded. + * false if option parameter is invalid. + * + */ +static int eth_port_uc_addr(unsigned int eth_port_num, + unsigned char uc_nibble, int option) +{ + unsigned int unicast_reg; + unsigned int tbl_offset; + unsigned int reg_offset; + + /* Locate the Unicast table entry */ + uc_nibble = (0xf & uc_nibble); + tbl_offset = (uc_nibble / 4) * 4; /* Register offset from unicast table base */ + reg_offset = uc_nibble % 4; /* Entry offset within the above register */ + + switch (option) { + case REJECT_MAC_ADDR: + /* Clear accepts frame bit at specified unicast DA table entry */ + unicast_reg = MV_READ((MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg &= (0x0E << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + break; + + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at unicast DA filter table entry */ + unicast_reg = + MV_READ( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset)); + + unicast_reg |= (0x01 << (8 * reg_offset)); + + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + tbl_offset), unicast_reg); + + break; + + default: + return 0; + } + + return 1; +} + +/* + * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables + * + * DESCRIPTION: + * Go through all the DA filter tables (Unicast, Special Multicast & + * Other Multicast) and set each entry to 0. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Multicast and Unicast packets are rejected. + * + * RETURN: + * None. + */ +static void eth_port_init_mac_tables(unsigned int eth_port_num) +{ + int table_index; + + /* Clear DA filter unicast table (Ex_dFUT) */ + for (table_index = 0; table_index <= 0xC; table_index += 4) + MV_WRITE( + (MV64340_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + + for (table_index = 0; table_index <= 0xFC; table_index += 4) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + MV_WRITE( + (MV64340_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + /* Clear DA filter other multicast table (Ex_dFOMT) */ + MV_WRITE((MV64340_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE + (eth_port_num) + table_index), 0); + } +} + +/* + * eth_clear_mib_counters - Clear all MIB counters + * + * DESCRIPTION: + * This function clears all MIB counters of a specific ethernet port. + * A read from the MIB counter will reset the counter. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * After reading all MIB counters, the counters resets. + * + * RETURN: + * MIB counter value. + * + */ +static void eth_clear_mib_counters(unsigned int eth_port_num) +{ + int i; + + /* Perform dummy reads from MIB counters */ + for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION; i += 4) + MV_READ(MV64340_ETH_MIB_COUNTERS_BASE(eth_port_num) + i); +} + + +#ifdef MDD_CUT +/* + * ethernet_phy_set - Set the ethernet port PHY address. + * + * DESCRIPTION: + * This routine set the ethernet port PHY address according to given + * parameter. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Set PHY Address Register with given PHY address parameter. + * + * RETURN: + * None. + */ +static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr) +{ + unsigned int reg_data; + + reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG); + + reg_data &= ~(0x1F << (5 * eth_port_num)); + reg_data |= (phy_addr << (5 * eth_port_num)); + + MV_WRITE(MV64340_ETH_PHY_ADDR_REG, reg_data); + + return; +} +#endif + +/* + * ethernet_phy_get - Get the ethernet port PHY address. + * + * DESCRIPTION: + * This routine returns the given ethernet port PHY address. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * PHY address. + * + */ +static int ethernet_phy_get(unsigned int eth_port_num) +{ + unsigned int reg_data; + + reg_data = MV_READ(MV64340_ETH_PHY_ADDR_REG); + + return ((reg_data >> (5 * eth_port_num)) & 0x1f); +} + +/* + * ethernet_phy_reset - Reset Ethernet port PHY. + * + * DESCRIPTION: + * This routine utilize the SMI interface to reset the ethernet port PHY. + * The routine waits until the link is up again or link up is timeout. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * The ethernet port PHY renew its link. + * + * RETURN: + * None. + * + */ +static int ethernet_phy_reset(unsigned int eth_port_num) +{ + unsigned int time_out = 50; + unsigned int phy_reg_data; + + /* Reset the PHY */ + eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); + phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ + eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); + + /* Poll on the PHY LINK */ + do { + eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data); + + if (time_out-- == 0) + return 0; + } while (!(phy_reg_data & 0x20)); + + return 1; +} + +/* + * eth_port_reset - Reset Ethernet port + * + * DESCRIPTION: + * This routine resets the chip by aborting any SDMA engine activity and + * clearing the MIB counters. The Receiver and the Transmit unit are in + * idle state after this command is performed and the port is disabled. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * Channel activity is halted. + * + * RETURN: + * None. + * + */ +static void eth_port_reset(unsigned int eth_port_num) +{ + unsigned int reg_data; + + /* Stop Tx port activity. Check port Tx activity. */ + reg_data = + MV_READ(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Tx activity to terminate. */ + do { + /* Check port cause register that all Tx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + /* Stop Rx port activity. Check port Rx activity. */ + reg_data = + MV_READ(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num), (reg_data << 8)); + + /* Wait for all Rx activity to terminate. */ + do { + /* Check port cause register that all Rx queues are stopped */ + reg_data = + MV_READ + (MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG + (eth_port_num)); + } + while (reg_data & 0xFF); + } + + + /* Clear all MIB counters */ + eth_clear_mib_counters(eth_port_num); + + /* Reset the Enable bit in the Configuration Register */ + reg_data = + MV_READ(MV64340_ETH_PORT_SERIAL_CONTROL_REG (eth_port_num)); + reg_data &= ~ETH_SERIAL_PORT_ENABLE; + MV_WRITE(MV64340_ETH_PORT_SERIAL_CONTROL_REG(eth_port_num), reg_data); + + return; +} + +/* + * ethernet_set_config_reg - Set specified bits in configuration register. + * + * DESCRIPTION: + * This function sets specified bits in the given ethernet + * configuration register. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int value 32 bit value. + * + * OUTPUT: + * The set bits in the value parameter are set in the configuration + * register. + * + * RETURN: + * None. + * + */ +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value) +{ + unsigned int eth_config_reg; + + eth_config_reg = + MV_READ(MV64340_ETH_PORT_CONFIG_REG(eth_port_num)); + eth_config_reg |= value; + MV_WRITE(MV64340_ETH_PORT_CONFIG_REG(eth_port_num), + eth_config_reg); +} + +/* + * ethernet_get_config_reg - Get the port configuration register + * + * DESCRIPTION: + * This function returns the configuration register value of the given + * ethernet port. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * + * OUTPUT: + * None. + * + * RETURN: + * Port configuration register value. + */ +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num) +{ + unsigned int eth_config_reg; + + eth_config_reg = MV_READ(MV64340_ETH_PORT_CONFIG_EXTEND_REG + (eth_port_num)); + return eth_config_reg; +} + + +/* + * eth_port_read_smi_reg - Read PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform PHY register read. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int *value Register value buffer. + * + * OUTPUT: + * Write the value of a specified PHY register into given buffer. + * + * RETURN: + * false if the PHY is busy or read data is not in valid state. + * true otherwise. + * + */ +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int *value) +{ + int phy_addr = ethernet_phy_get(eth_port_num); + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + + MV_WRITE(MV64340_ETH_SMI_REG, + (phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ); + + time_out = PHY_BUSY_TIMEOUT; /* initialize the time out var again */ + + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_READ_VALID); + + /* Wait for the data to update in the SMI register */ + for (time_out = 0; time_out < PHY_BUSY_TIMEOUT; time_out++); + + reg_value = MV_READ(MV64340_ETH_SMI_REG); + + *value = reg_value & 0xffff; + + return 1; +} + +/* + * eth_port_write_smi_reg - Write to PHY registers + * + * DESCRIPTION: + * This routine utilize the SMI interface to interact with the PHY in + * order to perform writes to PHY registers. + * + * INPUT: + * unsigned int eth_port_num Ethernet Port number. + * unsigned int phy_reg PHY register address offset. + * unsigned int value Register value. + * + * OUTPUT: + * Write the given value to the specified PHY register. + * + * RETURN: + * false if the PHY is busy. + * true otherwise. + * + */ +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, unsigned int value) +{ + unsigned int time_out = PHY_BUSY_TIMEOUT; + unsigned int reg_value; + int phy_addr; + + phy_addr = ethernet_phy_get(eth_port_num); + + /* first check that it is not busy */ + do { + reg_value = MV_READ(MV64340_ETH_SMI_REG); + if (time_out-- == 0) + return 0; + } while (reg_value & ETH_SMI_BUSY); + + /* not busy */ + MV_WRITE(MV64340_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) | + ETH_SMI_OPCODE_WRITE | (value & 0xffff)); + + return 1; +} + +/* + * eth_port_send - Send an Ethernet packet + * + * DESCRIPTION: + * This routine send a given packet described by p_pktinfo parameter. It + * supports transmitting of a packet spaned over multiple buffers. The + * routine updates 'curr' and 'first' indexes according to the packet + * segment passed to the routine. In case the packet segment is first, + * the 'first' index is update. In any case, the 'curr' index is updated. + * If the routine get into Tx resource error it assigns 'curr' index as + * 'first'. This way the function can abort Tx process of multiple + * descriptors per packet. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'curr' and 'first' indexes are updated. + * + * RETURN: + * ETH_QUEUE_FULL in case of Tx resource error. + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. + * ETH_OK otherwise. + * + */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX +/* + * Modified to include the first descriptor pointer in case of SG + */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc; + volatile struct eth_tx_desc *current_descriptor; + volatile struct eth_tx_desc *first_descriptor; + u32 command_status, first_chip_ptr; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + if (current_descriptor == NULL) + return ETH_ERROR; + + tx_next_desc = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + + if (command_status & ETH_TX_FIRST_DESC) { + tx_first_desc = tx_desc_curr; + mp->tx_first_desc_q = tx_first_desc; + + /* fill first descriptor */ + first_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + first_descriptor->l4i_chk = p_pkt_info->l4i_chk; + first_descriptor->cmd_sts = command_status; + first_descriptor->byte_cnt = p_pkt_info->byte_cnt; + first_descriptor->buf_ptr = p_pkt_info->buf_ptr; + first_descriptor->next_desc_ptr = + (struct eth_tx_desc *) mp->tx_desc_dma + tx_next_desc; + wmb(); + } else { + tx_first_desc = mp->tx_first_desc_q; + first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; + if (first_descriptor == NULL) { + printk("First desc is NULL !!\n"); + return ETH_ERROR; + } + if (command_status & ETH_TX_LAST_DESC) + current_descriptor->next_desc_ptr = 0x00000000; + else { + command_status |= ETH_BUFFER_OWNED_BY_DMA; + current_descriptor->next_desc_ptr = + (struct eth_tx_desc *) mp->tx_desc_dma + tx_next_desc; + } + } + + if (p_pkt_info->byte_cnt < 8) { + printk(" < 8 problem \n"); + return ETH_ERROR; + } + + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + current_descriptor->l4i_chk = p_pkt_info->l4i_chk; + current_descriptor->cmd_sts = command_status; + + mp->tx_skb[tx_desc_curr] = (struct sk_buff*) p_pkt_info->return_info; + + wmb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + if (command_status & ETH_TX_LAST_DESC) { + current_descriptor->cmd_sts = command_status | + ETH_TX_ENABLE_INTERRUPT | + ETH_BUFFER_OWNED_BY_DMA; + + if (!(command_status & ETH_TX_FIRST_DESC)) + first_descriptor->cmd_sts |= ETH_BUFFER_OWNED_BY_DMA; + wmb(); + + first_chip_ptr = MV_READ(MV64340_ETH_CURRENT_SERVED_TX_DESC_PTR(mp->port_num)); + + /* Apply send command */ + if (first_chip_ptr == 0x00000000) + MV_WRITE(MV64340_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(mp->port_num), (struct eth_tx_desc *) mp->tx_desc_dma + tx_first_desc); + + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* + * Finish Tx packet. Update first desc in case of Tx resource + * error */ + tx_first_desc = tx_next_desc; + mp->tx_first_desc_q = tx_first_desc; + } else { + if (! (command_status & ETH_TX_FIRST_DESC) ) { + current_descriptor->cmd_sts = command_status; + wmb(); + } + } + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_next_desc == tx_desc_used) { + mp->tx_resource_err = 1; + mp->tx_curr_desc_q = tx_first_desc; + + return ETH_QUEUE_LAST_RESOURCE; + } + + mp->tx_curr_desc_q = tx_next_desc; + wmb(); + + return ETH_OK; +} +#else +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_curr; + int tx_desc_used; + volatile struct eth_tx_desc* current_descriptor; + unsigned int command_status; + + /* Do not process Tx ring in case of Tx ring resource error */ + if (mp->tx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; + current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; + + if (current_descriptor == NULL) + return ETH_ERROR; + + command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; + +/* XXX Is this for real ?!?!? */ + /* Buffers with a payload smaller than 8 bytes must be aligned to a + * 64-bit boundary. We use the memory allocated for Tx descriptor. + * This memory is located in TX_BUF_OFFSET_IN_DESC offset within the + * Tx descriptor. */ + if (p_pkt_info->byte_cnt <= 8) { + printk(KERN_ERR + "You have failed in the < 8 bytes errata - fixme\n"); + return ETH_ERROR; + } + current_descriptor->buf_ptr = p_pkt_info->buf_ptr; + current_descriptor->byte_cnt = p_pkt_info->byte_cnt; + mp->tx_skb[tx_desc_curr] = (struct sk_buff *) p_pkt_info->return_info; + + mb(); + + /* Set last desc with DMA ownership and interrupt enable. */ + current_descriptor->cmd_sts = command_status | + ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; + + /* Apply send command */ + ETH_ENABLE_TX_QUEUE(mp->port_num); + + /* Finish Tx packet. Update first desc in case of Tx resource error */ + tx_desc_curr = (tx_desc_curr + 1) % MV64340_TX_QUEUE_SIZE; + + /* Update the current descriptor */ + mp->tx_curr_desc_q = tx_desc_curr; + + /* Check for ring index overlap in the Tx desc ring */ + if (tx_desc_curr == tx_desc_used) { + mp->tx_resource_err = 1; + return ETH_QUEUE_LAST_RESOURCE; + } + + return ETH_OK; +} +#endif + +/* + * eth_tx_return_desc - Free all used Tx descriptors + * + * DESCRIPTION: + * This routine returns the transmitted packet information to the caller. + * It uses the 'first' index to support Tx desc return in case a transmit + * of a packet spanned over multiple buffer still in process. + * In case the Tx queue was in "resource error" condition, where there are + * no available Tx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Tx ring 'first' and 'used' indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Tx desc ring. + * ETH_RETRY in case there is transmission in process. + * ETH_END_OF_JOB if the routine has nothing to release. + * ETH_OK otherwise. + * + */ +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int tx_desc_used, tx_desc_curr; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc; +#endif + volatile struct eth_tx_desc *p_tx_desc_used; + unsigned int command_status; + + /* Get the Tx Desc ring indexes */ + tx_desc_curr = mp->tx_curr_desc_q; + tx_desc_used = mp->tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + tx_first_desc = mp->tx_first_desc_q; +#endif + p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; + + /* XXX Sanity check */ + if (p_tx_desc_used == NULL) + return ETH_ERROR; + + command_status = p_tx_desc_used->cmd_sts; + + /* Still transmitting... */ +#ifndef MV64340_CHECKSUM_OFFLOAD_TX + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_RETRY; +#endif + /* Stop release. About to overlap the current available Tx descriptor */ +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + if (tx_desc_used == tx_first_desc && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#else + if (tx_desc_used == tx_desc_curr && !mp->tx_resource_err) + return ETH_END_OF_JOB; +#endif + + /* Pass the packet information to the caller */ + p_pkt_info->cmd_sts = command_status; + p_pkt_info->return_info = mp->tx_skb[tx_desc_used]; + mp->tx_skb[tx_desc_used] = NULL; + + /* Update the next descriptor to release. */ + mp->tx_used_desc_q = (tx_desc_used + 1) % MV64340_TX_QUEUE_SIZE; + + /* Any Tx return cancels the Tx resource error status */ + mp->tx_resource_err = 0; + + return ETH_OK; +} + +/* + * eth_port_receive - Get received information from Rx ring. + * + * DESCRIPTION: + * This routine returns the received data to the caller. There is no + * data copying during routine operation. All information is returned + * using pointer to packet information struct passed from the caller. + * If the routine exhausts Rx ring resources then the resource error flag + * is set. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info User packet buffer. + * + * OUTPUT: + * Rx ring current and used indexes are updated. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_QUEUE_FULL if Rx ring resources are exhausted. + * ETH_END_OF_JOB if there is no received data. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int rx_next_curr_desc, rx_curr_desc, rx_used_desc; + volatile struct eth_rx_desc * p_rx_desc; + unsigned int command_status; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (mp->rx_resource_err) + return ETH_QUEUE_FULL; + + /* Get the Rx Desc ring 'curr and 'used' indexes */ + rx_curr_desc = mp->rx_curr_desc_q; + rx_used_desc = mp->rx_used_desc_q; + + p_rx_desc = &mp->p_rx_desc_area[rx_curr_desc]; + + /* The following parameters are used to save readings from memory */ + command_status = p_rx_desc->cmd_sts; + + /* Nothing to receive... */ + if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) + return ETH_END_OF_JOB; + + p_pkt_info->byte_cnt = (p_rx_desc->byte_cnt) - RX_BUF_OFFSET; + p_pkt_info->cmd_sts = command_status; + p_pkt_info->buf_ptr = (p_rx_desc->buf_ptr) + RX_BUF_OFFSET; + p_pkt_info->return_info = mp->rx_skb[rx_curr_desc]; + p_pkt_info->l4i_chk = p_rx_desc->buf_size; + + /* Clean the return info field to indicate that the packet has been */ + /* moved to the upper layers */ + mp->rx_skb[rx_curr_desc] = NULL; + + /* Update current index in data structure */ + rx_next_curr_desc = (rx_curr_desc + 1) % MV64340_RX_QUEUE_SIZE; + mp->rx_curr_desc_q = rx_next_curr_desc; + + /* Rx descriptors exhausted. Set the Rx ring resource error flag */ + if (rx_next_curr_desc == rx_used_desc) + mp->rx_resource_err = 1; + + mb(); + return ETH_OK; +} + +/* + * eth_rx_return_buff - Returns a Rx buffer back to the Rx ring. + * + * DESCRIPTION: + * This routine returns a Rx buffer back to the Rx ring. It retrieves the + * next 'used' descriptor and attached the returned buffer to it. + * In case the Rx ring was in "resource error" condition, where there are + * no available Rx resources, the function resets the resource error flag. + * + * INPUT: + * struct mv64340_private *mp Ethernet Port Control srtuct. + * struct pkt_info *p_pkt_info Information on the returned buffer. + * + * OUTPUT: + * New available Rx resource in Rx descriptor ring. + * + * RETURN: + * ETH_ERROR in case the routine can not access Rx desc ring. + * ETH_OK otherwise. + */ +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private * mp, + struct pkt_info * p_pkt_info) +{ + int used_rx_desc; /* Where to return Rx resource */ + volatile struct eth_rx_desc* p_used_rx_desc; + + /* Get 'used' Rx descriptor */ + used_rx_desc = mp->rx_used_desc_q; + p_used_rx_desc = &mp->p_rx_desc_area[used_rx_desc]; + + p_used_rx_desc->buf_ptr = p_pkt_info->buf_ptr; + p_used_rx_desc->buf_size = p_pkt_info->byte_cnt; + mp->rx_skb[used_rx_desc] = p_pkt_info->return_info; + + /* Flush the write pipe */ + mb(); + + /* Return the descriptor to DMA ownership */ + p_used_rx_desc->cmd_sts = + ETH_BUFFER_OWNED_BY_DMA | ETH_RX_ENABLE_INTERRUPT; + + /* Flush descriptor and CPU pipe */ + mb(); + + /* Move the used descriptor pointer to the next descriptor */ + mp->rx_used_desc_q = (used_rx_desc + 1) % MV64340_RX_QUEUE_SIZE; + + /* Any Rx return cancels the Rx resource error status */ + mp->rx_resource_err = 0; + + return ETH_OK; +} + +#ifdef MDD_CUT +/* + * eth_b_copy - Copy bytes from source to destination + * + * DESCRIPTION: + * This function supports the eight bytes limitation on Tx buffer size. + * The routine will zero eight bytes starting from the destination address + * followed by copying bytes from the source address to the destination. + * + * INPUT: + * unsigned int src_addr 32 bit source address. + * unsigned int dst_addr 32 bit destination address. + * int byte_count Number of bytes to copy. + * + * OUTPUT: + * See description. + * + * RETURN: + * None. + * + */ +static void eth_b_copy(unsigned int src_addr, unsigned int dst_addr, + int byte_count) +{ + /* Zero the dst_addr area */ + *(unsigned int *) dst_addr = 0x0; + + while (byte_count != 0) { + *(char *) dst_addr = *(char *) src_addr; + dst_addr++; + src_addr++; + byte_count--; + } +} +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/net/mv64340_eth.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,601 @@ +#ifndef __MV64340_ETH_H__ +#define __MV64340_ETH_H__ + +#include +#include +#include +#include +#include + +#include + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +/* + * The first part is the high level driver of the gigE ethernet ports. + */ + +#define ETH_PORT0_IRQ_NUM 48 /* main high register, bit0 */ +#define ETH_PORT1_IRQ_NUM ETH_PORT0_IRQ_NUM+1 /* main high register, bit1 */ +#define ETH_PORT2_IRQ_NUM ETH_PORT0_IRQ_NUM+2 /* main high register, bit1 */ + +/* Checksum offload for Tx works */ +#define MV64340_CHECKSUM_OFFLOAD_TX +#define MV64340_NAPI +#define MV64340_TX_FAST_REFILL +#undef MV64340_COAL + +/* + * Number of RX / TX descriptors on RX / TX rings. + * Note that allocating RX descriptors is done by allocating the RX + * ring AND a preallocated RX buffers (skb's) for each descriptor. + * The TX descriptors only allocates the TX descriptors ring, + * with no pre allocated TX buffers (skb's are allocated by higher layers. + */ + +/* Default TX ring size is 1000 descriptors */ +#define MV64340_TX_QUEUE_SIZE 1000 + +/* Default RX ring size is 400 descriptors */ +#define MV64340_RX_QUEUE_SIZE 400 + +#define MV64340_TX_COAL 100 +#ifdef MV64340_COAL +#define MV64340_RX_COAL 100 +#endif + + +/* + * The second part is the low level driver of the gigE ethernet ports. * + */ + + +/* + * Header File for : MV-643xx network interface header + * + * DESCRIPTION: + * This header file contains macros typedefs and function declaration for + * the Marvell Gig Bit Ethernet Controller. + * + * DEPENDENCIES: + * None. + * + */ + +/* Default port configuration value */ +#define PORT_CONFIG_VALUE \ + ETH_UNICAST_NORMAL_MODE | \ + ETH_DEFAULT_RX_QUEUE_0 | \ + ETH_DEFAULT_RX_ARP_QUEUE_0 | \ + ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP | \ + ETH_RECEIVE_BC_IF_IP | \ + ETH_RECEIVE_BC_IF_ARP | \ + ETH_CAPTURE_TCP_FRAMES_DIS | \ + ETH_CAPTURE_UDP_FRAMES_DIS | \ + ETH_DEFAULT_RX_TCP_QUEUE_0 | \ + ETH_DEFAULT_RX_UDP_QUEUE_0 | \ + ETH_DEFAULT_RX_BPDU_QUEUE_0 + +/* Default port extend configuration value */ +#define PORT_CONFIG_EXTEND_VALUE \ + ETH_SPAN_BPDU_PACKETS_AS_NORMAL | \ + ETH_PARTITION_DISABLE + + +/* Default sdma control value */ +#define PORT_SDMA_CONFIG_VALUE \ + ETH_RX_BURST_SIZE_16_64BIT | \ + GT_ETH_IPG_INT_RX(0) | \ + ETH_TX_BURST_SIZE_16_64BIT; + +#define GT_ETH_IPG_INT_RX(value) \ + ((value & 0x3fff) << 8) + +/* Default port serial control value */ +#define PORT_SERIAL_CONTROL_VALUE \ + ETH_FORCE_LINK_PASS | \ + ETH_ENABLE_AUTO_NEG_FOR_DUPLX | \ + ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \ + ETH_ADV_SYMMETRIC_FLOW_CTRL | \ + ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + ETH_FORCE_BP_MODE_NO_JAM | \ + BIT9 | \ + ETH_DO_NOT_FORCE_LINK_FAIL | \ + ETH_RETRANSMIT_16_ATTEMPTS | \ + ETH_ENABLE_AUTO_NEG_SPEED_GMII | \ + ETH_DTE_ADV_0 | \ + ETH_DISABLE_AUTO_NEG_BYPASS | \ + ETH_AUTO_NEG_NO_CHANGE | \ + ETH_MAX_RX_PACKET_9700BYTE | \ + ETH_CLR_EXT_LOOPBACK | \ + ETH_SET_FULL_DUPLEX_MODE | \ + ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX + +#define RX_BUFFER_MAX_SIZE 0x4000000 +#define TX_BUFFER_MAX_SIZE 0x4000000 + +/* MAC accepet/reject macros */ +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 + +/* Buffer offset from buffer pointer */ +#define RX_BUF_OFFSET 0x2 + +/* Gigabit Ethernet Unit Global Registers */ + +/* MIB Counters register definitions */ +#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0 +#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4 +#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8 +#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc +#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10 +#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14 +#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18 +#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c +#define ETH_MIB_FRAMES_64_OCTETS 0x20 +#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24 +#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28 +#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c +#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30 +#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34 +#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38 +#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c +#define ETH_MIB_GOOD_FRAMES_SENT 0x40 +#define ETH_MIB_EXCESSIVE_COLLISION 0x44 +#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48 +#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c +#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50 +#define ETH_MIB_FC_SENT 0x54 +#define ETH_MIB_GOOD_FC_RECEIVED 0x58 +#define ETH_MIB_BAD_FC_RECEIVED 0x5c +#define ETH_MIB_UNDERSIZE_RECEIVED 0x60 +#define ETH_MIB_FRAGMENTS_RECEIVED 0x64 +#define ETH_MIB_OVERSIZE_RECEIVED 0x68 +#define ETH_MIB_JABBER_RECEIVED 0x6c +#define ETH_MIB_MAC_RECEIVE_ERROR 0x70 +#define ETH_MIB_BAD_CRC_EVENT 0x74 +#define ETH_MIB_COLLISION 0x78 +#define ETH_MIB_LATE_COLLISION 0x7c + +/* Port serial status reg (PSR) */ +#define ETH_INTERFACE_GMII_MII 0 +#define ETH_INTERFACE_PCM BIT0 +#define ETH_LINK_IS_DOWN 0 +#define ETH_LINK_IS_UP BIT1 +#define ETH_PORT_AT_HALF_DUPLEX 0 +#define ETH_PORT_AT_FULL_DUPLEX BIT2 +#define ETH_RX_FLOW_CTRL_DISABLED 0 +#define ETH_RX_FLOW_CTRL_ENBALED BIT3 +#define ETH_GMII_SPEED_100_10 0 +#define ETH_GMII_SPEED_1000 BIT4 +#define ETH_MII_SPEED_10 0 +#define ETH_MII_SPEED_100 BIT5 +#define ETH_NO_TX 0 +#define ETH_TX_IN_PROGRESS BIT7 +#define ETH_BYPASS_NO_ACTIVE 0 +#define ETH_BYPASS_ACTIVE BIT8 +#define ETH_PORT_NOT_AT_PARTITION_STATE 0 +#define ETH_PORT_AT_PARTITION_STATE BIT9 +#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 +#define ETH_PORT_TX_FIFO_EMPTY BIT10 + + +/* These macros describes the Port configuration reg (Px_cR) bits */ +#define ETH_UNICAST_NORMAL_MODE 0 +#define ETH_UNICAST_PROMISCUOUS_MODE BIT0 +#define ETH_DEFAULT_RX_QUEUE_0 0 +#define ETH_DEFAULT_RX_QUEUE_1 BIT1 +#define ETH_DEFAULT_RX_QUEUE_2 BIT2 +#define ETH_DEFAULT_RX_QUEUE_3 (BIT2 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_4 BIT3 +#define ETH_DEFAULT_RX_QUEUE_5 (BIT3 | BIT1) +#define ETH_DEFAULT_RX_QUEUE_6 (BIT3 | BIT2) +#define ETH_DEFAULT_RX_QUEUE_7 (BIT3 | BIT2 | BIT1) +#define ETH_DEFAULT_RX_ARP_QUEUE_0 0 +#define ETH_DEFAULT_RX_ARP_QUEUE_1 BIT4 +#define ETH_DEFAULT_RX_ARP_QUEUE_2 BIT5 +#define ETH_DEFAULT_RX_ARP_QUEUE_3 (BIT5 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_4 BIT6 +#define ETH_DEFAULT_RX_ARP_QUEUE_5 (BIT6 | BIT4) +#define ETH_DEFAULT_RX_ARP_QUEUE_6 (BIT6 | BIT5) +#define ETH_DEFAULT_RX_ARP_QUEUE_7 (BIT6 | BIT5 | BIT4) +#define ETH_RECEIVE_BC_IF_NOT_IP_OR_ARP 0 +#define ETH_REJECT_BC_IF_NOT_IP_OR_ARP BIT7 +#define ETH_RECEIVE_BC_IF_IP 0 +#define ETH_REJECT_BC_IF_IP BIT8 +#define ETH_RECEIVE_BC_IF_ARP 0 +#define ETH_REJECT_BC_IF_ARP BIT9 +#define ETH_TX_AM_NO_UPDATE_ERROR_SUMMARY BIT12 +#define ETH_CAPTURE_TCP_FRAMES_DIS 0 +#define ETH_CAPTURE_TCP_FRAMES_EN BIT14 +#define ETH_CAPTURE_UDP_FRAMES_DIS 0 +#define ETH_CAPTURE_UDP_FRAMES_EN BIT15 +#define ETH_DEFAULT_RX_TCP_QUEUE_0 0 +#define ETH_DEFAULT_RX_TCP_QUEUE_1 BIT16 +#define ETH_DEFAULT_RX_TCP_QUEUE_2 BIT17 +#define ETH_DEFAULT_RX_TCP_QUEUE_3 (BIT17 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_4 BIT18 +#define ETH_DEFAULT_RX_TCP_QUEUE_5 (BIT18 | BIT16) +#define ETH_DEFAULT_RX_TCP_QUEUE_6 (BIT18 | BIT17) +#define ETH_DEFAULT_RX_TCP_QUEUE_7 (BIT18 | BIT17 | BIT16) +#define ETH_DEFAULT_RX_UDP_QUEUE_0 0 +#define ETH_DEFAULT_RX_UDP_QUEUE_1 BIT19 +#define ETH_DEFAULT_RX_UDP_QUEUE_2 BIT20 +#define ETH_DEFAULT_RX_UDP_QUEUE_3 (BIT20 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_4 (BIT21 +#define ETH_DEFAULT_RX_UDP_QUEUE_5 (BIT21 | BIT19) +#define ETH_DEFAULT_RX_UDP_QUEUE_6 (BIT21 | BIT20) +#define ETH_DEFAULT_RX_UDP_QUEUE_7 (BIT21 | BIT20 | BIT19) +#define ETH_DEFAULT_RX_BPDU_QUEUE_0 0 +#define ETH_DEFAULT_RX_BPDU_QUEUE_1 BIT22 +#define ETH_DEFAULT_RX_BPDU_QUEUE_2 BIT23 +#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 +#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) +#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) +#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) + + +/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ +#define ETH_CLASSIFY_EN BIT0 +#define ETH_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define ETH_SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 BIT1 +#define ETH_PARTITION_DISABLE 0 +#define ETH_PARTITION_ENABLE BIT2 + + +/* Tx/Rx queue command reg (RQCR/TQCR)*/ +#define ETH_QUEUE_0_ENABLE BIT0 +#define ETH_QUEUE_1_ENABLE BIT1 +#define ETH_QUEUE_2_ENABLE BIT2 +#define ETH_QUEUE_3_ENABLE BIT3 +#define ETH_QUEUE_4_ENABLE BIT4 +#define ETH_QUEUE_5_ENABLE BIT5 +#define ETH_QUEUE_6_ENABLE BIT6 +#define ETH_QUEUE_7_ENABLE BIT7 +#define ETH_QUEUE_0_DISABLE BIT8 +#define ETH_QUEUE_1_DISABLE BIT9 +#define ETH_QUEUE_2_DISABLE BIT10 +#define ETH_QUEUE_3_DISABLE BIT11 +#define ETH_QUEUE_4_DISABLE BIT12 +#define ETH_QUEUE_5_DISABLE BIT13 +#define ETH_QUEUE_6_DISABLE BIT14 +#define ETH_QUEUE_7_DISABLE BIT15 + + +/* These macros describes the Port Sdma configuration reg (SDCR) bits */ +#define ETH_RIFB BIT0 +#define ETH_RX_BURST_SIZE_1_64BIT 0 +#define ETH_RX_BURST_SIZE_2_64BIT BIT1 +#define ETH_RX_BURST_SIZE_4_64BIT BIT2 +#define ETH_RX_BURST_SIZE_8_64BIT (BIT2 | BIT1) +#define ETH_RX_BURST_SIZE_16_64BIT BIT3 +#define ETH_BLM_RX_NO_SWAP BIT4 +#define ETH_BLM_RX_BYTE_SWAP 0 +#define ETH_BLM_TX_NO_SWAP BIT5 +#define ETH_BLM_TX_BYTE_SWAP 0 +#define ETH_DESCRIPTORS_BYTE_SWAP BIT6 +#define ETH_DESCRIPTORS_NO_SWAP 0 +#define ETH_TX_BURST_SIZE_1_64BIT 0 +#define ETH_TX_BURST_SIZE_2_64BIT BIT22 +#define ETH_TX_BURST_SIZE_4_64BIT BIT23 +#define ETH_TX_BURST_SIZE_8_64BIT (BIT23 | BIT22) +#define ETH_TX_BURST_SIZE_16_64BIT BIT24 + + + +/* These macros describes the Port serial control reg (PSCR) bits */ +#define ETH_SERIAL_PORT_DISABLE 0 +#define ETH_SERIAL_PORT_ENABLE BIT0 +#define ETH_FORCE_LINK_PASS BIT1 +#define ETH_DO_NOT_FORCE_LINK_PASS 0 +#define ETH_ENABLE_AUTO_NEG_FOR_DUPLX 0 +#define ETH_DISABLE_AUTO_NEG_FOR_DUPLX BIT2 +#define ETH_ENABLE_AUTO_NEG_FOR_FLOW_CTRL 0 +#define ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL BIT3 +#define ETH_ADV_NO_FLOW_CTRL 0 +#define ETH_ADV_SYMMETRIC_FLOW_CTRL BIT4 +#define ETH_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define ETH_FORCE_FC_MODE_TX_PAUSE_DIS BIT5 +#define ETH_FORCE_BP_MODE_NO_JAM 0 +#define ETH_FORCE_BP_MODE_JAM_TX BIT7 +#define ETH_FORCE_BP_MODE_JAM_TX_ON_RX_ERR BIT8 +#define ETH_FORCE_LINK_FAIL 0 +#define ETH_DO_NOT_FORCE_LINK_FAIL BIT10 +#define ETH_RETRANSMIT_16_ATTEMPTS 0 +#define ETH_RETRANSMIT_FOREVER BIT11 +#define ETH_DISABLE_AUTO_NEG_SPEED_GMII BIT13 +#define ETH_ENABLE_AUTO_NEG_SPEED_GMII 0 +#define ETH_DTE_ADV_0 0 +#define ETH_DTE_ADV_1 BIT14 +#define ETH_DISABLE_AUTO_NEG_BYPASS 0 +#define ETH_ENABLE_AUTO_NEG_BYPASS BIT15 +#define ETH_AUTO_NEG_NO_CHANGE 0 +#define ETH_RESTART_AUTO_NEG BIT16 +#define ETH_MAX_RX_PACKET_1518BYTE 0 +#define ETH_MAX_RX_PACKET_1522BYTE BIT17 +#define ETH_MAX_RX_PACKET_1552BYTE BIT18 +#define ETH_MAX_RX_PACKET_9022BYTE (BIT18 | BIT17) +#define ETH_MAX_RX_PACKET_9192BYTE BIT19 +#define ETH_MAX_RX_PACKET_9700BYTE (BIT19 | BIT17) +#define ETH_SET_EXT_LOOPBACK BIT20 +#define ETH_CLR_EXT_LOOPBACK 0 +#define ETH_SET_FULL_DUPLEX_MODE BIT21 +#define ETH_SET_HALF_DUPLEX_MODE 0 +#define ETH_ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX BIT22 +#define ETH_DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define ETH_SET_GMII_SPEED_TO_10_100 0 +#define ETH_SET_GMII_SPEED_TO_1000 BIT23 +#define ETH_SET_MII_SPEED_TO_10 0 +#define ETH_SET_MII_SPEED_TO_100 BIT24 + + +/* SMI reg */ +#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ +#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ +#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ + +/* SDMA command status fields macros */ + +/* Tx & Rx descriptors status */ +#define ETH_ERROR_SUMMARY (BIT0) + +/* Tx & Rx descriptors command */ +#define ETH_BUFFER_OWNED_BY_DMA (BIT31) + +/* Tx descriptors status */ +#define ETH_LC_ERROR (0 ) +#define ETH_UR_ERROR (BIT1 ) +#define ETH_RL_ERROR (BIT2 ) +#define ETH_LLC_SNAP_FORMAT (BIT9 ) + +/* Rx descriptors status */ +#define ETH_CRC_ERROR (0 ) +#define ETH_OVERRUN_ERROR (BIT1 ) +#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) +#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) +#define ETH_VLAN_TAGGED (BIT19) +#define ETH_BPDU_FRAME (BIT20) +#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) +#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) +#define ETH_OTHER_FRAME_TYPE (BIT22) +#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) +#define ETH_FRAME_TYPE_IP_V_4 (BIT24) +#define ETH_FRAME_HEADER_OK (BIT25) +#define ETH_RX_LAST_DESC (BIT26) +#define ETH_RX_FIRST_DESC (BIT27) +#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) +#define ETH_RX_ENABLE_INTERRUPT (BIT29) +#define ETH_LAYER_4_CHECKSUM_OK (BIT30) + +/* Rx descriptors byte count */ +#define ETH_FRAME_FRAGMENTED (BIT2) + +/* Tx descriptors command */ +#define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) +#define ETH_FRAME_SET_TO_VLAN (BIT15) +#define ETH_TCP_FRAME (0 ) +#define ETH_UDP_FRAME (BIT16) +#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) +#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) +#define ETH_ZERO_PADDING (BIT19) +#define ETH_TX_LAST_DESC (BIT20) +#define ETH_TX_FIRST_DESC (BIT21) +#define ETH_GEN_CRC (BIT22) +#define ETH_TX_ENABLE_INTERRUPT (BIT23) +#define ETH_AUTO_MODE (BIT30) + +/* typedefs */ + +typedef enum _eth_func_ret_status { + ETH_OK, /* Returned as expected. */ + ETH_ERROR, /* Fundamental error. */ + ETH_RETRY, /* Could not process request. Try later. */ + ETH_END_OF_JOB, /* Ring has nothing to process. */ + ETH_QUEUE_FULL, /* Ring resource error. */ + ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */ +} ETH_FUNC_RET_STATUS; + +typedef enum _eth_target { + ETH_TARGET_DRAM, + ETH_TARGET_DEVICE, + ETH_TARGET_CBS, + ETH_TARGET_PCI0, + ETH_TARGET_PCI1 +} ETH_TARGET; + +/* These are for big-endian machines. Little endian needs different + * definitions. + */ +#if defined(__BIG_ENDIAN) +struct eth_rx_desc { + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 cmd_sts; /* Descriptor command status */ + u32 next_desc_ptr; /* Next descriptor pointer */ + u32 buf_ptr; /* Descriptor buffer pointer */ +}; + +struct eth_tx_desc { + u16 byte_cnt; /* buffer byte count */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u32 cmd_sts; /* Command/status field */ + u32 next_desc_ptr; /* Pointer to next descriptor */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ +}; + +#elif defined(__LITTLE_ENDIAN) +struct eth_rx_desc { + u32 cmd_sts; /* Descriptor command status */ + u16 buf_size; /* Buffer size */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ +}; + +struct eth_tx_desc { + u32 cmd_sts; /* Command/status field */ + u16 l4i_chk; /* CPU provided TCP checksum */ + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ + u32 next_desc_ptr; /* Pointer to next descriptor */ +}; +#else +#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined +#endif + +/* Unified struct for Rx and Tx operations. The user is not required to */ +/* be familier with neither Tx nor Rx descriptors. */ +struct pkt_info { + unsigned short byte_cnt; /* Descriptor buffer byte count */ + unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */ + unsigned int cmd_sts; /* Descriptor command status */ + dma_addr_t buf_ptr; /* Descriptor buffer pointer */ + struct sk_buff * return_info; /* User resource return information */ +}; + + +/* Ethernet port specific infomation */ + +struct mv64340_private { + int port_num; /* User Ethernet port number */ + u8 port_mac_addr[6]; /* User defined port MAC address. */ + u32 port_config; /* User port configuration value */ + u32 port_config_extend; /* User port config extend value */ + u32 port_sdma_config; /* User port SDMA config value */ + u32 port_serial_control; /* User port serial control value */ + u32 port_tx_queue_command; /* Port active Tx queues summary */ + u32 port_rx_queue_command; /* Port active Rx queues summary */ + + int rx_resource_err; /* Rx ring resource error flag */ + int tx_resource_err; /* Tx ring resource error flag */ + + /* Tx/Rx rings managment indexes fields. For driver use */ + + /* Next available and first returning Rx resource */ + int rx_curr_desc_q, rx_used_desc_q; + + /* Next available and first returning Tx resource */ + int tx_curr_desc_q, tx_used_desc_q; +#ifdef MV64340_CHECKSUM_OFFLOAD_TX + int tx_first_desc_q; +#endif + +#ifdef MV64340_TX_FAST_REFILL + u32 tx_clean_threshold; +#endif + + volatile struct eth_rx_desc * p_rx_desc_area; + dma_addr_t rx_desc_dma; + unsigned int rx_desc_area_size; + struct sk_buff * rx_skb[MV64340_RX_QUEUE_SIZE]; + + volatile struct eth_tx_desc * p_tx_desc_area; + dma_addr_t tx_desc_dma; + unsigned int tx_desc_area_size; + struct sk_buff * tx_skb[MV64340_TX_QUEUE_SIZE]; + + struct work_struct tx_timeout_task; + + /* + * Former struct mv64340_eth_priv members start here + */ + struct net_device_stats stats; + spinlock_t lock; + /* Size of Tx Ring per queue */ + unsigned int tx_ring_size; + /* Ammont of SKBs outstanding on Tx queue */ + unsigned int tx_ring_skbs; + /* Size of Rx Ring per queue */ + unsigned int rx_ring_size; + /* Ammount of SKBs allocated to Rx Ring per queue */ + unsigned int rx_ring_skbs; + + /* + * rx_task used to fill RX ring out of bottom half context + */ + struct work_struct rx_task; + + /* + * Used in case RX Ring is empty, which can be caused when + * system does not have resources (skb's) + */ + struct timer_list timeout; + long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES))); + unsigned rx_timer_flag; + + u32 rx_int_coal; + u32 tx_int_coal; +}; + +/* ethernet.h API list */ + +/* Port operation control routines */ +static void eth_port_init(struct mv64340_private *mp); +static void eth_port_reset(unsigned int eth_port_num); +static int eth_port_start(struct mv64340_private *mp); + +static void ethernet_set_config_reg(unsigned int eth_port_num, + unsigned int value); +static unsigned int ethernet_get_config_reg(unsigned int eth_port_num); + +/* Port MAC address routines */ +static void eth_port_uc_addr_set(unsigned int eth_port_num, + unsigned char *p_addr); + +/* PHY and MIB routines */ +static int ethernet_phy_reset(unsigned int eth_port_num); + +static int eth_port_write_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int value); + +static int eth_port_read_smi_reg(unsigned int eth_port_num, + unsigned int phy_reg, + unsigned int *value); + +static void eth_clear_mib_counters(unsigned int eth_port_num); + +/* Port data flow control routines */ +static ETH_FUNC_RET_STATUS eth_port_send(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_port_receive(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); +static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv64340_private *mp, + struct pkt_info * p_pkt_info); + +#endif /* __MV64340_ETH_H__ */ --- linux-2.6.8-rc1/drivers/net/natsemi.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/natsemi.c 2004-07-13 17:09:23.000000000 -0700 @@ -230,7 +230,14 @@ static int full_duplex[MAX_UNITS]; #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) #define NATSEMI_EEPROM_SIZE 24 /* 12 16-bit values */ -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +/* Buffer sizes: + * The nic writes 32-bit values, even if the upper bytes of + * a 32-bit value are beyond the end of the buffer. + */ +#define NATSEMI_HEADERS 22 /* 2*mac,type,vlan,crc */ +#define NATSEMI_PADDING 16 /* 2 bytes should be sufficient */ +#define NATSEMI_LONGPKT 1518 /* limit for normal packets */ +#define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = @@ -354,6 +361,18 @@ enum pcistuff { #define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +/* + * Support for fibre connections on Am79C874: + * This phy needs a special setup when connected to a fibre cable. + * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf + */ +#define PHYID_AM79C874 0x0022561b + +#define MII_MCTRL 0x15 /* mode control register */ +#define MII_FX_SEL 0x0001 /* 100BASE-FX (fiber) */ +#define MII_EN_SCRM 0x0004 /* enable scrambler (tp) */ + + /* array of board data directly indexed by pci_tbl[x].driver_data */ static struct { const char *name; @@ -457,6 +476,9 @@ enum EECtrl_bits { EE_DataIn = 0x01, EE_ChipSelect = 0x08, EE_DataOut = 0x02, + MII_Data = 0x10, + MII_Write = 0x20, + MII_ShiftClk = 0x40, }; enum PCIBusCfg_bits { @@ -518,6 +540,22 @@ enum TxConfig_bits { TxCarrierIgn = 0x80000000 }; +/* + * Tx Configuration: + * - 256 byte DMA burst length + * - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free) + * - 64 bytes initial drain threshold (i.e. begin actual transmission + * when 64 byte are in the fifo) + * - on tx underruns, increase drain threshold by 64. + * - at most use a drain threshold of 1472 bytes: The sum of the fill + * threshold and the drain threshold must be less than 2016 bytes. + * + */ +#define TX_FLTH_VAL ((512/32) << 8) +#define TX_DRTH_VAL_START (64/32) +#define TX_DRTH_VAL_INC 2 +#define TX_DRTH_VAL_LIMIT (1472/32) + enum RxConfig_bits { RxDrthMask = 0x3e, RxMxdmaMask = 0x700000, @@ -534,6 +572,7 @@ enum RxConfig_bits { RxAcceptRunt = 0x40000000, RxAcceptErr = 0x80000000 }; +#define RX_DRTH_VAL (128/8) enum ClkRun_bits { PMEEnable = 0x100, @@ -588,9 +627,12 @@ enum MIntrCtrl_bits { }; enum PhyCtrl_bits { - PhyAddrMask = 0xf, + PhyAddrMask = 0x1f, }; +#define PHY_ADDR_NONE 32 +#define PHY_ADDR_INTERNAL 1 + /* values we might find in the silicon revision register */ #define SRR_DP83815_C 0x0302 #define SRR_DP83815_D 0x0403 @@ -650,7 +692,9 @@ struct netdev_private { int oom; /* Do not touch the nic registers */ int hands_off; - /* These values are keep track of the transceiver/media in use */ + /* external phy that is used: only valid if dev->if_port != PORT_TP */ + int mii; + int phy_addr_external; unsigned int full_duplex; /* Rx filter */ u32 cur_rx_mode; @@ -663,6 +707,10 @@ struct netdev_private { u32 srr; /* expected DSPCFG value */ u16 dspcfg; + /* parms saved in ethtool format */ + u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ + u8 duplex; /* Duplex, half or full */ + u8 autoneg; /* Autonegotiation enabled */ /* MII transceiver section */ u16 advertising; unsigned int iosize; @@ -670,9 +718,14 @@ struct netdev_private { u32 msg_enable; }; +static void move_int_phy(struct net_device *dev, int addr); static int eeprom_read(long ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int reg); -static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 data); +static int mdio_read(struct net_device *dev, int reg); +static void mdio_write(struct net_device *dev, int reg, u16 data); +static void init_phy_fixup(struct net_device *dev); +static int miiport_read(struct net_device *dev, int phy_id, int reg); +static void miiport_write(struct net_device *dev, int phy_id, int reg, u16 data); +static int find_mii(struct net_device *dev); static void natsemi_reset(struct net_device *dev); static void natsemi_reload_eeprom(struct net_device *dev); static void natsemi_stop_rxtx(struct net_device *dev); @@ -696,6 +749,7 @@ static irqreturn_t intr_handler(int irq, static void netdev_error(struct net_device *dev, int intr_status); static void netdev_rx(struct net_device *dev); static void netdev_tx_done(struct net_device *dev); +static int natsemi_change_mtu(struct net_device *dev, int new_mtu); static void __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static void __get_stats(struct net_device *dev); @@ -712,6 +766,29 @@ static int netdev_close(struct net_devic static int netdev_get_regs(struct net_device *dev, u8 *buf); static int netdev_get_eeprom(struct net_device *dev, u8 *buf); +static void move_int_phy(struct net_device *dev, int addr) +{ + struct netdev_private *np = netdev_priv(dev); + int target = 31; + + /* + * The internal phy is visible on the external mii bus. Therefore we must + * move it away before we can send commands to an external phy. + * There are two addresses we must avoid: + * - the address on the external phy that is used for transmission. + * - the address that we want to access. User space can access phys + * on the mii bus with SIOCGMIIREG/SIOCSMIIREG, independant from the + * phy that is used for transmission. + */ + + if (target == addr) + target--; + if (target == np->phy_addr_external) + target--; + writew(target, dev->base_addr + PhyCtrl); + readw(dev->base_addr + PhyCtrl); + udelay(1); +} static int __devinit natsemi_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -782,7 +859,7 @@ static int __devinit natsemi_probe1 (str dev->base_addr = ioaddr; dev->irq = irq; - np = dev->priv; + np = netdev_priv(dev); np->pci_dev = pdev; pci_set_drvdata(pdev, dev); @@ -791,10 +868,32 @@ static int __devinit natsemi_probe1 (str np->msg_enable = (debug >= 0) ? (1<hands_off = 0; + /* Initial port: + * - If the nic was configured to use an external phy and if find_mii + * finds a phy: use external port, first phy that replies. + * - Otherwise: internal port. + * Note that the phy address for the internal phy doesn't matter: + * The address would be used to access a phy over the mii bus, but + * the internal phy is accessed through mapped registers. + */ + if (readl(dev->base_addr + ChipConfig) & CfgExtPhy) + dev->if_port = PORT_MII; + else + dev->if_port = PORT_TP; /* Reset the chip to erase previous misconfiguration. */ natsemi_reload_eeprom(dev); natsemi_reset(dev); + if (dev->if_port != PORT_TP) { + np->phy_addr_external = find_mii(dev); + if (np->phy_addr_external == PHY_ADDR_NONE) { + dev->if_port = PORT_TP; + np->phy_addr_external = PHY_ADDR_INTERNAL; + } + } else { + np->phy_addr_external = PHY_ADDR_INTERNAL; + } + option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; if (dev->mem_start) option = dev->mem_start; @@ -805,8 +904,8 @@ static int __devinit natsemi_probe1 (str np->full_duplex = 1; if (option & 15) printk(KERN_INFO - "%s: ignoring user supplied media type %d", - dev->name, option & 15); + "natsemi %s: ignoring user supplied media type %d", + pci_name(np->pci_dev), option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt]) np->full_duplex = 1; @@ -817,6 +916,7 @@ static int __devinit natsemi_probe1 (str dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; + dev->change_mtu = &natsemi_change_mtu; dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -824,45 +924,57 @@ static int __devinit natsemi_probe1 (str if (mtu) dev->mtu = mtu; - i = register_netdev(dev); - if (i) - goto err_register_netdev; - netif_carrier_off(dev); - if (netif_msg_drv(np)) { - printk(KERN_INFO "%s: %s at %#08lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - for (i = 0; i < ETH_ALEN-1; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq); - } + /* get the initial settings from hardware */ + tmp = mdio_read(dev, MII_BMCR); + np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10; + np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; + np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; + np->advertising= mdio_read(dev, MII_ADVERTISE); - np->advertising = mdio_read(dev, 1, MII_ADVERTISE); - if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 + if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL && netif_msg_probe(np)) { - u32 chip_config = readl(ioaddr + ChipConfig); - printk(KERN_INFO "%s: Transceiver default autonegotiation %s " + printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", - dev->name, - chip_config & CfgAnegEnable ? + pci_name(np->pci_dev), + (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)? "enabled, advertise" : "disabled, force", - chip_config & CfgAneg100 ? "0" : "", - chip_config & CfgAnegFull ? "full" : "half"); + (np->advertising & + (ADVERTISE_100FULL|ADVERTISE_100HALF))? + "0" : "", + (np->advertising & + (ADVERTISE_100FULL|ADVERTISE_10FULL))? + "full" : "half"); } if (netif_msg_probe(np)) printk(KERN_INFO - "%s: Transceiver status %#04x advertising %#04x.\n", - dev->name, mdio_read(dev, 1, MII_BMSR), + "natsemi %s: Transceiver status %#04x advertising %#04x.\n", + pci_name(np->pci_dev), mdio_read(dev, MII_BMSR), np->advertising); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); if (netif_msg_hw(np)) - printk(KERN_INFO "%s: silicon revision %#04x.\n", - dev->name, np->srr); + printk(KERN_INFO "natsemi %s: silicon revision %#04x.\n", + pci_name(np->pci_dev), np->srr); + i = register_netdev(dev); + if (i) + goto err_register_netdev; + if (netif_msg_drv(np)) { + printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr, + pci_name(np->pci_dev)); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x, IRQ %d", dev->dev_addr[i], irq); + if (dev->if_port == PORT_TP) + printk(", port TP.\n"); + else + printk(", port MII, phy ad %d.\n", np->phy_addr_external); + } return 0; err_register_netdev: @@ -933,25 +1045,335 @@ static int eeprom_read(long addr, int lo /* MII transceiver control section. * The 83815 series has an internal transceiver, and we present the - * management registers as if they were MII connected. */ + * internal management registers as if they were MII connected. + * External Phy registers are referenced through the MII interface. + */ + +/* clock transitions >= 20ns (25MHz) + * One readl should be good to PCI @ 100MHz + */ +#define mii_delay(dev) readl(dev->base_addr + EECtrl) + +static int mii_getbit (struct net_device *dev) +{ + int data; + + writel(MII_ShiftClk, dev->base_addr + EECtrl); + data = readl(dev->base_addr + EECtrl); + writel(0, dev->base_addr + EECtrl); + mii_delay(dev); + return (data & MII_Data)? 1 : 0; +} + +static void mii_send_bits (struct net_device *dev, u32 data, int len) +{ + u32 i; + + for (i = (1 << (len-1)); i; i >>= 1) + { + u32 mdio_val = MII_Write | ((data & i)? MII_Data : 0); + writel(mdio_val, dev->base_addr + EECtrl); + mii_delay(dev); + writel(mdio_val | MII_ShiftClk, dev->base_addr + EECtrl); + mii_delay(dev); + } + writel(0, dev->base_addr + EECtrl); + mii_delay(dev); +} + +static int miiport_read(struct net_device *dev, int phy_id, int reg) +{ + u32 cmd; + int i; + u32 retval = 0; + + /* Ensure sync */ + mii_send_bits (dev, 0xffffffff, 32); + /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */ + /* ST,OP = 0110'b for read operation */ + cmd = (0x06 << 10) | (phy_id << 5) | reg; + mii_send_bits (dev, cmd, 14); + /* Turnaround */ + if (mii_getbit (dev)) + return 0; + /* Read data */ + for (i = 0; i < 16; i++) { + retval <<= 1; + retval |= mii_getbit (dev); + } + /* End cycle */ + mii_getbit (dev); + return retval; +} -static int mdio_read(struct net_device *dev, int phy_id, int reg) +static void miiport_write(struct net_device *dev, int phy_id, int reg, u16 data) { - if (phy_id == 1 && reg < 32) - return readl(dev->base_addr+BasicControl+(reg<<2))&0xffff; + u32 cmd; + + /* Ensure sync */ + mii_send_bits (dev, 0xffffffff, 32); + /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */ + /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x5002 for write */ + cmd = (0x5002 << 16) | (phy_id << 23) | (reg << 18) | data; + mii_send_bits (dev, cmd, 32); + /* End cycle */ + mii_getbit (dev); +} + +static int mdio_read(struct net_device *dev, int reg) +{ + struct netdev_private *np = netdev_priv(dev); + + /* The 83815 series has two ports: + * - an internal transceiver + * - an external mii bus + */ + if (dev->if_port == PORT_TP) + return readw(dev->base_addr+BasicControl+(reg<<2)); else - return 0xffff; + return miiport_read(dev, np->phy_addr_external, reg); } -static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 data) +static void mdio_write(struct net_device *dev, int reg, u16 data) { - struct netdev_private *np = dev->priv; - if (phy_id == 1 && reg < 32) { + struct netdev_private *np = netdev_priv(dev); + + /* The 83815 series has an internal transceiver; handle separately */ + if (dev->if_port == PORT_TP) writew(data, dev->base_addr+BasicControl+(reg<<2)); - switch (reg) { - case MII_ADVERTISE: np->advertising = data; break; + else + miiport_write(dev, np->phy_addr_external, reg, data); +} + +static void init_phy_fixup(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + long ioaddr = dev->base_addr; + int i; + u32 cfg; + u16 tmp; + + /* restore stuff lost when power was out */ + tmp = mdio_read(dev, MII_BMCR); + if (np->autoneg == AUTONEG_ENABLE) { + /* renegotiate if something changed */ + if ((tmp & BMCR_ANENABLE) == 0 + || np->advertising != mdio_read(dev, MII_ADVERTISE)) + { + /* turn on autonegotiation and force negotiation */ + tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); + mdio_write(dev, MII_ADVERTISE, np->advertising); + } + } else { + /* turn off auto negotiation, set speed and duplexity */ + tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); + if (np->speed == SPEED_100) + tmp |= BMCR_SPEED100; + if (np->duplex == DUPLEX_FULL) + tmp |= BMCR_FULLDPLX; + /* + * Note: there is no good way to inform the link partner + * that our capabilities changed. The user has to unplug + * and replug the network cable after some changes, e.g. + * after switching from 10HD, autoneg off to 100 HD, + * autoneg off. + */ + } + mdio_write(dev, MII_BMCR, tmp); + readl(dev->base_addr + ChipConfig); + udelay(1); + + /* find out what phy this is */ + np->mii = (mdio_read(dev, MII_PHYSID1) << 16) + + mdio_read(dev, MII_PHYSID2); + + /* handle external phys here */ + switch (np->mii) { + case PHYID_AM79C874: + /* phy specific configuration for fibre/tp operation */ + tmp = mdio_read(dev, MII_MCTRL); + tmp &= ~(MII_FX_SEL | MII_EN_SCRM); + if (dev->if_port == PORT_FIBRE) + tmp |= MII_FX_SEL; + else + tmp |= MII_EN_SCRM; + mdio_write(dev, MII_MCTRL, tmp); + break; + default: + break; + } + cfg = readl(dev->base_addr + ChipConfig); + if (cfg & CfgExtPhy) + return; + + /* On page 78 of the spec, they recommend some settings for "optimum + performance" to be done in sequence. These settings optimize some + of the 100Mbit autodetection circuitry. They say we only want to + do this for rev C of the chip, but engineers at NSC (Bradley + Kennedy) recommends always setting them. If you don't, you get + errors on some autonegotiations that make the device unusable. + + It seems that the DSP needs a few usec to reinitialize after + the start of the phy. Just retry writing these values until they + stick. + */ + for (i=0;idspcfg = DSPCFG_VAL; + writew(np->dspcfg, ioaddr + DSPCFG); + writew(SDCFG_VAL, ioaddr + SDCFG); + writew(0, ioaddr + PGSEL); + readl(ioaddr + ChipConfig); + udelay(10); + + writew(1, ioaddr + PGSEL); + dspcfg = readw(ioaddr + DSPCFG); + writew(0, ioaddr + PGSEL); + if (np->dspcfg == dspcfg) + break; + } + + if (netif_msg_link(np)) { + if (i==NATSEMI_HW_TIMEOUT) { + printk(KERN_INFO + "%s: DSPCFG mismatch after retrying for %d usec.\n", + dev->name, i*10); + } else { + printk(KERN_INFO + "%s: DSPCFG accepted after %d usec.\n", + dev->name, i*10); + } + } + /* + * Enable PHY Specific event based interrupts. Link state change + * and Auto-Negotiation Completion are among the affected. + * Read the intr status to clear it (needed for wake events). + */ + readw(ioaddr + MIntrStatus); + writew(MICRIntEn, ioaddr + MIntrCtrl); +} + +static int switch_port_external(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + u32 cfg; + + cfg = readl(dev->base_addr + ChipConfig); + if (cfg & CfgExtPhy) + return 0; + + if (netif_msg_link(np)) { + printk(KERN_INFO "%s: switching to external transceiver.\n", + dev->name); + } + + /* 1) switch back to external phy */ + writel(cfg | (CfgExtPhy | CfgPhyDis), dev->base_addr + ChipConfig); + readl(dev->base_addr + ChipConfig); + udelay(1); + + /* 2) reset the external phy: */ + /* resetting the external PHY has been known to cause a hub supplying + * power over Ethernet to kill the power. We don't want to kill + * power to this computer, so we avoid resetting the phy. + */ + + /* 3) reinit the phy fixup, it got lost during power down. */ + move_int_phy(dev, np->phy_addr_external); + init_phy_fixup(dev); + + return 1; +} + +static int switch_port_internal(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + int i; + u32 cfg; + u16 bmcr; + + cfg = readl(dev->base_addr + ChipConfig); + if (!(cfg &CfgExtPhy)) + return 0; + + if (netif_msg_link(np)) { + printk(KERN_INFO "%s: switching to internal transceiver.\n", + dev->name); + } + /* 1) switch back to internal phy: */ + cfg = cfg & ~(CfgExtPhy | CfgPhyDis); + writel(cfg, dev->base_addr + ChipConfig); + readl(dev->base_addr + ChipConfig); + udelay(1); + + /* 2) reset the internal phy: */ + bmcr = readw(dev->base_addr+BasicControl+(MII_BMCR<<2)); + writel(bmcr | BMCR_RESET, dev->base_addr+BasicControl+(MII_BMCR<<2)); + readl(dev->base_addr + ChipConfig); + udelay(10); + for (i=0;ibase_addr+BasicControl+(MII_BMCR<<2)); + if (!(bmcr & BMCR_RESET)) + break; + udelay(10); + } + if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { + printk(KERN_INFO + "%s: phy reset did not complete in %d usec.\n", + dev->name, i*10); + } + /* 3) reinit the phy fixup, it got lost during power down. */ + init_phy_fixup(dev); + + return 1; +} + +/* Scan for a PHY on the external mii bus. + * There are two tricky points: + * - Do not scan while the internal phy is enabled. The internal phy will + * crash: e.g. reads from the DSPCFG register will return odd values and + * the nasty random phy reset code will reset the nic every few seconds. + * - The internal phy must be moved around, an external phy could + * have the same address as the internal phy. + */ +static int find_mii(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + int tmp; + int i; + int did_switch; + + /* Switch to external phy */ + did_switch = switch_port_external(dev); + + /* Scan the possible phy addresses: + * + * PHY address 0 means that the phy is in isolate mode. Not yet + * supported due to lack of test hardware. User space should + * handle it through ethtool. + */ + for (i = 1; i <= 31; i++) { + move_int_phy(dev, i); + tmp = miiport_read(dev, i, MII_BMSR); + if (tmp != 0xffff && tmp != 0x0000) { + /* found something! */ + np->mii = (mdio_read(dev, MII_PHYSID1) << 16) + + mdio_read(dev, MII_PHYSID2); + if (netif_msg_probe(np)) { + printk(KERN_INFO "natsemi %s: found external phy %08x at address %d.\n", + pci_name(np->pci_dev), np->mii, i); + } + break; } } + /* And switch back to internal phy: */ + if (did_switch) + switch_port_internal(dev); + return i; } /* CFG bits [13:16] [18:23] */ @@ -969,7 +1391,7 @@ static void natsemi_reset(struct net_dev u32 rfcr; u16 pmatch[3]; u16 sopass[3]; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* * Resetting the chip causes some registers to be lost. @@ -1013,6 +1435,11 @@ static void natsemi_reset(struct net_dev /* restore CFG */ cfg |= readl(dev->base_addr + ChipConfig) & ~CFG_RESET_SAVE; + /* turn on external phy if it was selected */ + if (dev->if_port == PORT_TP) + cfg &= ~(CfgExtPhy | CfgPhyDis); + else + cfg |= (CfgExtPhy | CfgPhyDis); writel(cfg, dev->base_addr + ChipConfig); /* restore WCSR */ wcsr |= readl(dev->base_addr + WOLCmd) & ~WCSR_RESET_SAVE; @@ -1034,7 +1461,7 @@ static void natsemi_reset(struct net_dev static void natsemi_reload_eeprom(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; writel(EepromReload, dev->base_addr + PCIBusCfg); @@ -1044,18 +1471,18 @@ static void natsemi_reload_eeprom(struct break; } if (i==NATSEMI_HW_TIMEOUT) { - printk(KERN_WARNING "%s: EEPROM did not reload in %d usec.\n", - dev->name, i*50); + printk(KERN_WARNING "natsemi %s: EEPROM did not reload in %d usec.\n", + pci_name(np->pci_dev), i*50); } else if (netif_msg_hw(np)) { - printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n", - dev->name, i*50); + printk(KERN_DEBUG "natsemi %s: EEPROM reloaded in %d usec.\n", + pci_name(np->pci_dev), i*50); } } static void natsemi_stop_rxtx(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; writel(RxOff | TxOff, ioaddr + ChipCmd); @@ -1075,7 +1502,7 @@ static void natsemi_stop_rxtx(struct net static int netdev_open(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; int i; @@ -1124,7 +1551,10 @@ static int netdev_open(struct net_device static void do_cable_magic(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); + + if (dev->if_port != PORT_TP) + return; if (np->srr >= SRR_DP83816_A5) return; @@ -1149,7 +1579,7 @@ static void do_cable_magic(struct net_de * (these values all come from National) */ if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* the bug has been triggered - fix the coefficient */ writew(TSTDAT_FIXED, dev->base_addr + TSTDAT); @@ -1165,7 +1595,10 @@ static void do_cable_magic(struct net_de static void undo_cable_magic(struct net_device *dev) { u16 data; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); + + if (dev->if_port != PORT_TP) + return; if (np->srr >= SRR_DP83816_A5) return; @@ -1180,12 +1613,19 @@ static void undo_cable_magic(struct net_ static void check_link(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; int duplex; - int chipcfg = readl(ioaddr + ChipConfig); + u16 bmsr; + + /* The link status field is latched: it remains low after a temporary + * link failure until it's read. We need the current link status, + * thus read twice. + */ + mdio_read(dev, MII_BMSR); + bmsr = mdio_read(dev, MII_BMSR); - if (!(chipcfg & CfgLink)) { + if (!(bmsr & BMSR_LSTATUS)) { if (netif_carrier_ok(dev)) { if (netif_msg_link(np)) printk(KERN_NOTICE "%s: link down.\n", @@ -1202,7 +1642,16 @@ static void check_link(struct net_device do_cable_magic(dev); } - duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0); + duplex = np->full_duplex; + if (!duplex) { + if (bmsr & BMSR_ANEGCOMPLETE) { + int tmp = mii_nway_result( + np->advertising & mdio_read(dev, MII_LPA)); + if (tmp == LPA_100FULL || tmp == LPA_10FULL) + duplex = 1; + } else if (mdio_read(dev, MII_BMCR) & BMCR_FULLDPLX) + duplex = 1; + } /* if duplex is set then bit 28 must be set, too */ if (duplex ^ !!(np->rx_config & RxAcceptTx)) { @@ -1225,42 +1674,10 @@ static void check_link(struct net_device static void init_registers(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; - int i; - - for (i=0;ibase_addr + ChipConfig) & CfgAnegDone) - break; - udelay(10); - } - if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) { - printk(KERN_INFO - "%s: autonegotiation did not complete in %d usec.\n", - dev->name, i*10); - } - /* On page 78 of the spec, they recommend some settings for "optimum - performance" to be done in sequence. These settings optimize some - of the 100Mbit autodetection circuitry. They say we only want to - do this for rev C of the chip, but engineers at NSC (Bradley - Kennedy) recommends always setting them. If you don't, you get - errors on some autonegotiations that make the device unusable. - */ - writew(1, ioaddr + PGSEL); - writew(PMDCSR_VAL, ioaddr + PMDCSR); - writew(TSTDAT_VAL, ioaddr + TSTDAT); - writew(DSPCFG_VAL, ioaddr + DSPCFG); - writew(SDCFG_VAL, ioaddr + SDCFG); - writew(0, ioaddr + PGSEL); - np->dspcfg = DSPCFG_VAL; - - /* Enable PHY Specific event based interrupts. Link state change - and Auto-Negotiation Completion are among the affected. - Read the intr status to clear it (needed for wake events). - */ - readw(ioaddr + MIntrStatus); - writew(MICRIntEn, ioaddr + MIntrCtrl); + init_phy_fixup(dev); /* clear any interrupts that are pending, such as wake events */ readl(ioaddr + IntrStatus); @@ -1283,13 +1700,18 @@ static void init_registers(struct net_de * ECRETRY=1 * ATP=1 */ - np->tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | (0x1002); + np->tx_config = TxAutoPad | TxCollRetry | TxMxdma_256 | + TX_FLTH_VAL | TX_DRTH_VAL_START; writel(np->tx_config, ioaddr + TxConfig); /* DRTH 0x10: start copying to memory if 128 bytes are in the fifo * MXDMA 0: up to 256 byte bursts */ - np->rx_config = RxMxdma_256 | 0x20; + np->rx_config = RxMxdma_256 | RX_DRTH_VAL; + /* if receive ring now has bigger buffers than normal, enable jumbo */ + if (np->rx_buf_sz > NATSEMI_LONGPKT) + np->rx_config |= RxAcceptLong; + writel(np->rx_config, ioaddr + RxConfig); /* Disable PME: @@ -1331,10 +1753,8 @@ static void init_registers(struct net_de static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int next_tick = 5*HZ; - long ioaddr = dev->base_addr; - u16 dspcfg; if (netif_msg_timer(np)) { /* DO NOT read the IntrStatus register, @@ -1344,33 +1764,41 @@ static void netdev_timer(unsigned long d dev->name); } - spin_lock_irq(&np->lock); + if (dev->if_port == PORT_TP) { + long ioaddr = dev->base_addr; + u16 dspcfg; - /* check for a nasty random phy-reset - use dspcfg as a flag */ - writew(1, ioaddr+PGSEL); - dspcfg = readw(ioaddr+DSPCFG); - writew(0, ioaddr+PGSEL); - if (dspcfg != np->dspcfg) { - if (!netif_queue_stopped(dev)) { - spin_unlock_irq(&np->lock); - if (netif_msg_hw(np)) - printk(KERN_NOTICE "%s: possible phy reset: " - "re-initializing\n", dev->name); - disable_irq(dev->irq); - spin_lock_irq(&np->lock); - natsemi_stop_rxtx(dev); - dump_ring(dev); - reinit_ring(dev); - init_registers(dev); - spin_unlock_irq(&np->lock); - enable_irq(dev->irq); + spin_lock_irq(&np->lock); + /* check for a nasty random phy-reset - use dspcfg as a flag */ + writew(1, ioaddr+PGSEL); + dspcfg = readw(ioaddr+DSPCFG); + writew(0, ioaddr+PGSEL); + if (dspcfg != np->dspcfg) { + if (!netif_queue_stopped(dev)) { + spin_unlock_irq(&np->lock); + if (netif_msg_hw(np)) + printk(KERN_NOTICE "%s: possible phy reset: " + "re-initializing\n", dev->name); + disable_irq(dev->irq); + spin_lock_irq(&np->lock); + natsemi_stop_rxtx(dev); + dump_ring(dev); + reinit_ring(dev); + init_registers(dev); + spin_unlock_irq(&np->lock); + enable_irq(dev->irq); + } else { + /* hurry back */ + next_tick = HZ; + spin_unlock_irq(&np->lock); + } } else { - /* hurry back */ - next_tick = HZ; + /* init_registers() calls check_link() for the above case */ + check_link(dev); spin_unlock_irq(&np->lock); } } else { - /* init_registers() calls check_link() for the above case */ + spin_lock_irq(&np->lock); check_link(dev); spin_unlock_irq(&np->lock); } @@ -1390,7 +1818,7 @@ static void netdev_timer(unsigned long d static void dump_ring(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); if (netif_msg_pktdata(np)) { int i; @@ -1413,7 +1841,7 @@ static void dump_ring(struct net_device static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; disable_irq(dev->irq); @@ -1444,7 +1872,7 @@ static void tx_timeout(struct net_device static int alloc_ring(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); np->rx_ring = pci_alloc_consistent(np->pci_dev, sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE), &np->ring_dma); @@ -1456,14 +1884,14 @@ static int alloc_ring(struct net_device static void refill_rx(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* Refill the Rx ring buffers. */ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { struct sk_buff *skb; int entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { - unsigned int buflen = np->rx_buf_sz + RX_OFFSET; + unsigned int buflen = np->rx_buf_sz+NATSEMI_PADDING; skb = dev_alloc_skb(buflen); np->rx_skbuff[entry] = skb; if (skb == NULL) @@ -1482,10 +1910,19 @@ static void refill_rx(struct net_device } } +static void set_bufsize(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + if (dev->mtu <= ETH_DATA_LEN) + np->rx_buf_sz = ETH_DATA_LEN + NATSEMI_HEADERS; + else + np->rx_buf_sz = dev->mtu + NATSEMI_HEADERS; +} + /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; /* 1) TX ring */ @@ -1501,8 +1938,9 @@ static void init_ring(struct net_device /* 2) RX ring */ np->dirty_rx = 0; np->cur_rx = RX_RING_SIZE; - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); np->oom = 0; + set_bufsize(dev); + np->rx_head_desc = &np->rx_ring[0]; /* Please be carefull before changing this loop - at least gcc-2.95.1 @@ -1522,7 +1960,7 @@ static void init_ring(struct net_device static void drain_tx(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; for (i = 0; i < TX_RING_SIZE; i++) { @@ -1537,10 +1975,10 @@ static void drain_tx(struct net_device * } } -static void drain_ring(struct net_device *dev) +static void drain_rx(struct net_device *dev) { - struct netdev_private *np = dev->priv; - unsigned int buflen = np->rx_buf_sz + RX_OFFSET; + struct netdev_private *np = netdev_priv(dev); + unsigned int buflen = np->rx_buf_sz; int i; /* Free all the skbuffs in the Rx queue. */ @@ -1555,28 +1993,27 @@ static void drain_ring(struct net_device } np->rx_skbuff[i] = NULL; } +} + +static void drain_ring(struct net_device *dev) +{ + drain_rx(dev); drain_tx(dev); } static void free_ring(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); pci_free_consistent(np->pci_dev, sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE), np->rx_ring, np->ring_dma); } -static void reinit_ring(struct net_device *dev) +static void reinit_rx(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int i; - /* drain TX ring */ - drain_tx(dev); - np->dirty_tx = np->cur_tx = 0; - for (i=0;itx_ring[i].cmd_status = 0; - /* RX Ring */ np->dirty_rx = 0; np->cur_rx = RX_RING_SIZE; @@ -1588,9 +2025,23 @@ static void reinit_ring(struct net_devic refill_rx(dev); } +static void reinit_ring(struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + int i; + + /* drain TX ring */ + drain_tx(dev); + np->dirty_tx = np->cur_tx = 0; + for (i=0;itx_ring[i].cmd_status = 0; + + reinit_rx(dev); +} + static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); unsigned entry; /* Note: Ordering is important here, set the field with the @@ -1637,7 +2088,7 @@ static int start_tx(struct sk_buff *skb, static void netdev_tx_done(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; @@ -1683,7 +2134,7 @@ static void netdev_tx_done(struct net_de static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; int boguscnt = max_interrupt_work; unsigned int handled = 0; @@ -1741,20 +2192,22 @@ static irqreturn_t intr_handler(int irq, for clarity and better register allocation. */ static void netdev_rx(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); - unsigned int buflen = np->rx_buf_sz + RX_OFFSET; + unsigned int buflen = np->rx_buf_sz; /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ + int pkt_len; if (netif_msg_rx_status(np)) printk(KERN_DEBUG " netdev_rx() entry %d status was %#08x.\n", entry, desc_status); if (--boguscnt < 0) break; + pkt_len = (desc_status & DescSizeMask) - 4; if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { if (netif_msg_rx_err(np)) @@ -1777,10 +2230,14 @@ static void netdev_rx(struct net_device if (desc_status & DescRxCRC) np->stats.rx_crc_errors++; } + } else if (pkt_len > np->rx_buf_sz) { + /* if this is the tail of a double buffer + * packet, we've already counted the error + * on the first part. Ignore the second half. + */ } else { struct sk_buff *skb; /* Omit CRC size. */ - int pkt_len = (desc_status & DescSizeMask) - 4; /* Check if the packet is long enough to accept * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak @@ -1826,19 +2283,18 @@ static void netdev_rx(struct net_device static void netdev_error(struct net_device *dev, int intr_status) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; spin_lock(&np->lock); if (intr_status & LinkChange) { - u16 adv = mdio_read(dev, 1, MII_ADVERTISE); - u16 lpa = mdio_read(dev, 1, MII_LPA); - if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE + u16 lpa = mdio_read(dev, MII_LPA); + if (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE && netif_msg_link(np)) { printk(KERN_INFO "%s: Autonegotiation advertising" " %#04x partner %#04x.\n", dev->name, - adv, lpa); + np->advertising, lpa); } /* read MII int status to clear the flag */ @@ -1849,12 +2305,18 @@ static void netdev_error(struct net_devi __get_stats(dev); } if (intr_status & IntrTxUnderrun) { - if ((np->tx_config & TxDrthMask) < 62) - np->tx_config += 2; - if (netif_msg_tx_err(np)) - printk(KERN_NOTICE - "%s: increased Tx threshold, txcfg %#08x.\n", - dev->name, np->tx_config); + if ((np->tx_config & TxDrthMask) < TX_DRTH_VAL_LIMIT) { + np->tx_config += TX_DRTH_VAL_INC; + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: increased tx threshold, txcfg %#08x.\n", + dev->name, np->tx_config); + } else { + if (netif_msg_tx_err(np)) + printk(KERN_NOTICE + "%s: tx underrun with maximum tx threshold, txcfg %#08x.\n", + dev->name, np->tx_config); + } writel(np->tx_config, ioaddr + TxConfig); } if (intr_status & WOLPkt && netif_msg_wol(np)) { @@ -1882,7 +2344,7 @@ static void netdev_error(struct net_devi static void __get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* The chip only need report frame silently dropped. */ np->stats.rx_crc_errors += readl(ioaddr + RxCRCErrs); @@ -1891,7 +2353,7 @@ static void __get_stats(struct net_devic static struct net_device_stats *get_stats(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); /* The chip only need report frame silently dropped. */ spin_lock_irq(&np->lock); @@ -1906,7 +2368,7 @@ static struct net_device_stats *get_stat static void __set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u8 mc_filter[64]; /* Multicast hash filter */ u32 rx_mode; @@ -1941,9 +2403,39 @@ static void __set_rx_mode(struct net_dev np->cur_rx_mode = rx_mode; } +static int natsemi_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < 64 || new_mtu > NATSEMI_RX_LIMIT-NATSEMI_HEADERS) + return -EINVAL; + + dev->mtu = new_mtu; + + /* synchronized against open : rtnl_lock() held by caller */ + if (netif_running(dev)) { + struct netdev_private *np = netdev_priv(dev); + long ioaddr = dev->base_addr; + + disable_irq(dev->irq); + spin_lock(&np->lock); + /* stop engines */ + natsemi_stop_rxtx(dev); + /* drain rx queue */ + drain_rx(dev); + /* change buffers */ + set_bufsize(dev); + reinit_rx(dev); + writel(np->ring_dma, ioaddr + RxRingPtr); + /* restart engines */ + writel(RxOn | TxOn, ioaddr + ChipCmd); + spin_unlock(&np->lock); + enable_irq(dev->irq); + } + return 0; +} + static void set_rx_mode(struct net_device *dev) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); spin_lock_irq(&np->lock); if (!np->hands_off) __set_rx_mode(dev); @@ -1952,7 +2444,7 @@ static void set_rx_mode(struct net_devic static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u32 cmd; if (get_user(cmd, (u32 __user *)useraddr)) @@ -2066,10 +2558,10 @@ static int netdev_ethtool_ioctl(struct n int tmp; int r = -EINVAL; /* if autoneg is off, it's an error */ - tmp = mdio_read(dev, 1, MII_BMCR); + tmp = mdio_read(dev, MII_BMCR); if (tmp & BMCR_ANENABLE) { tmp |= (BMCR_ANRESTART); - mdio_write(dev, 1, MII_BMCR, tmp); + mdio_write(dev, MII_BMCR, tmp); r = 0; } return r; @@ -2078,8 +2570,8 @@ static int netdev_ethtool_ioctl(struct n case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; /* LSTATUS is latched low until a read - so read twice */ - mdio_read(dev, 1, MII_BMSR); - edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; + mdio_read(dev, MII_BMSR); + edata.data = (mdio_read(dev, MII_BMSR)&BMSR_LSTATUS) ? 1:0; if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; @@ -2123,7 +2615,7 @@ static int netdev_ethtool_ioctl(struct n static int netdev_set_wol(struct net_device *dev, u32 newval) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u32 data = readl(dev->base_addr + WOLCmd) & ~WakeOptsSummary; /* translate to bitmasks this chip understands */ @@ -2152,7 +2644,7 @@ static int netdev_set_wol(struct net_dev static int netdev_get_wol(struct net_device *dev, u32 *supported, u32 *cur) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u32 regval = readl(dev->base_addr + WOLCmd); *supported = (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST @@ -2187,7 +2679,7 @@ static int netdev_get_wol(struct net_dev static int netdev_set_sopass(struct net_device *dev, u8 *newval) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u16 *sval = (u16 *)newval; u32 addr; @@ -2218,7 +2710,7 @@ static int netdev_set_sopass(struct net_ static int netdev_get_sopass(struct net_device *dev, u8 *data) { - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); u16 *sval = (u16 *)data; u32 addr; @@ -2246,56 +2738,75 @@ static int netdev_get_sopass(struct net_ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) { + struct netdev_private *np = netdev_priv(dev); u32 tmp; - ecmd->supported = - (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); - - /* only supports twisted-pair or MII */ - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgExtPhy) - ecmd->port = PORT_MII; - else - ecmd->port = PORT_TP; - - /* only supports internal transceiver */ - ecmd->transceiver = XCVR_INTERNAL; - - /* not sure what this is for */ - ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask; - - ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; - tmp = mdio_read(dev, 1, MII_ADVERTISE); - if (tmp & ADVERTISE_10HALF) + ecmd->port = dev->if_port; + ecmd->speed = np->speed; + ecmd->duplex = np->duplex; + ecmd->autoneg = np->autoneg; + ecmd->advertising = 0; + if (np->advertising & ADVERTISE_10HALF) ecmd->advertising |= ADVERTISED_10baseT_Half; - if (tmp & ADVERTISE_10FULL) + if (np->advertising & ADVERTISE_10FULL) ecmd->advertising |= ADVERTISED_10baseT_Full; - if (tmp & ADVERTISE_100HALF) + if (np->advertising & ADVERTISE_100HALF) ecmd->advertising |= ADVERTISED_100baseT_Half; - if (tmp & ADVERTISE_100FULL) + if (np->advertising & ADVERTISE_100FULL) ecmd->advertising |= ADVERTISED_100baseT_Full; + ecmd->supported = (SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_FIBRE); + ecmd->phy_address = np->phy_addr_external; + /* + * We intentionally report the phy address of the external + * phy, even if the internal phy is used. This is necessary + * to work around a deficiency of the ethtool interface: + * It's only possible to query the settings of the active + * port. Therefore + * # ethtool -s ethX port mii + * actually sends an ioctl to switch to port mii with the + * settings that are used for the current active port. + * If we would report a different phy address in this + * command, then + * # ethtool -s ethX port tp;ethtool -s ethX port mii + * would unintentionally change the phy address. + * + * Fortunately the phy address doesn't matter with the + * internal phy... + */ - tmp = mdio_read(dev, 1, MII_BMCR); - if (tmp & BMCR_ANENABLE) { - ecmd->advertising |= ADVERTISED_Autoneg; - ecmd->autoneg = AUTONEG_ENABLE; - } else { - ecmd->autoneg = AUTONEG_DISABLE; - } - - tmp = readl(dev->base_addr + ChipConfig); - if (tmp & CfgSpeed100) { - ecmd->speed = SPEED_100; - } else { - ecmd->speed = SPEED_10; + /* set information based on active port type */ + switch (ecmd->port) { + default: + case PORT_TP: + ecmd->advertising |= ADVERTISED_TP; + ecmd->transceiver = XCVR_INTERNAL; + break; + case PORT_MII: + ecmd->advertising |= ADVERTISED_MII; + ecmd->transceiver = XCVR_EXTERNAL; + break; + case PORT_FIBRE: + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->transceiver = XCVR_EXTERNAL; + break; } - if (tmp & CfgFullDuplex) { - ecmd->duplex = DUPLEX_FULL; - } else { - ecmd->duplex = DUPLEX_HALF; + /* if autonegotiation is on, try to return the active speed/duplex */ + if (ecmd->autoneg == AUTONEG_ENABLE) { + ecmd->advertising |= ADVERTISED_Autoneg; + tmp = mii_nway_result( + np->advertising & mdio_read(dev, MII_LPA)); + if (tmp == LPA_100FULL || tmp == LPA_100HALF) + ecmd->speed = SPEED_100; + else + ecmd->speed = SPEED_10; + if (tmp == LPA_100FULL || tmp == LPA_10FULL) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; } /* ignore maxtxpkt, maxrxpkt for now */ @@ -2305,39 +2816,75 @@ static int netdev_get_ecmd(struct net_de static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct netdev_private *np = dev->priv; - u32 tmp; + struct netdev_private *np = netdev_priv(dev); - if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + if (ecmd->port != PORT_TP && ecmd->port != PORT_MII && ecmd->port != PORT_FIBRE) return -EINVAL; - if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + if (ecmd->transceiver != XCVR_INTERNAL && ecmd->transceiver != XCVR_EXTERNAL) return -EINVAL; - if (ecmd->port != PORT_TP && ecmd->port != PORT_MII) - return -EINVAL; - if (ecmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) + if (ecmd->autoneg == AUTONEG_ENABLE) { + if ((ecmd->advertising & (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full)) == 0) { + return -EINVAL; + } + } else if (ecmd->autoneg == AUTONEG_DISABLE) { + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + return -EINVAL; + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + } else { return -EINVAL; - /* ignore phy_address, maxtxpkt, maxrxpkt for now */ + } + + /* + * maxtxpkt, maxrxpkt: ignored for now. + * + * transceiver: + * PORT_TP is always XCVR_INTERNAL, PORT_MII and PORT_FIBRE are always + * XCVR_EXTERNAL. The implementation thus ignores ecmd->transceiver and + * selects based on ecmd->port. + * + * Actually PORT_FIBRE is nearly identical to PORT_MII: it's for fibre + * phys that are connected to the mii bus. It's used to apply fibre + * specific updates. + */ /* WHEW! now lets bang some bits */ - tmp = mdio_read(dev, 1, MII_BMCR); - if (ecmd->autoneg == AUTONEG_ENABLE) { - /* turn on autonegotiation */ - tmp |= BMCR_ANENABLE; - np->advertising = mdio_read(dev, 1, MII_ADVERTISE); + /* save the parms */ + dev->if_port = ecmd->port; + np->autoneg = ecmd->autoneg; + np->phy_addr_external = ecmd->phy_address & PhyAddrMask; + if (np->autoneg == AUTONEG_ENABLE) { + /* advertise only what has been requested */ + np->advertising &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (ecmd->advertising & ADVERTISED_10baseT_Half) + np->advertising |= ADVERTISE_10HALF; + if (ecmd->advertising & ADVERTISED_10baseT_Full) + np->advertising |= ADVERTISE_10FULL; + if (ecmd->advertising & ADVERTISED_100baseT_Half) + np->advertising |= ADVERTISE_100HALF; + if (ecmd->advertising & ADVERTISED_100baseT_Full) + np->advertising |= ADVERTISE_100FULL; } else { - /* turn off auto negotiation, set speed and duplexity */ - tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX); - if (ecmd->speed == SPEED_100) - tmp |= BMCR_SPEED100; - if (ecmd->duplex == DUPLEX_FULL) - tmp |= BMCR_FULLDPLX; - else + np->speed = ecmd->speed; + np->duplex = ecmd->duplex; + /* user overriding the initial full duplex parm? */ + if (np->duplex == DUPLEX_HALF) np->full_duplex = 0; } - mdio_write(dev, 1, MII_BMCR, tmp); + + /* get the right phy enabled */ + if (ecmd->port == PORT_TP) + switch_port_internal(dev); + else + switch_port_external(dev); + + /* set parms and see how this affected our link status */ + init_phy_fixup(dev); + check_link(dev); return 0; } @@ -2348,11 +2895,15 @@ static int netdev_get_regs(struct net_de u32 rfcr; u32 *rbuf = (u32 *)buf; - /* read all of page 0 of registers */ - for (i = 0; i < NATSEMI_PG0_NREGS; i++) { + /* read non-mii page 0 of registers */ + for (i = 0; i < NATSEMI_PG0_NREGS/2; i++) { rbuf[i] = readl(dev->base_addr + i*4); } + /* read current mii registers */ + for (i = NATSEMI_PG0_NREGS/2; i < NATSEMI_PG0_NREGS; i++) + rbuf[i] = mdio_read(dev, i & 0x1f); + /* read only the 'magic' registers from page 1 */ writew(1, dev->base_addr + PGSEL); rbuf[i++] = readw(dev->base_addr + PMDCSR); @@ -2407,27 +2958,56 @@ static int netdev_get_eeprom(struct net_ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct mii_ioctl_data *data = if_mii(rq); + struct netdev_private *np = netdev_priv(dev); switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, rq->ifr_data); case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ - data->phy_id = 1; + data->phy_id = np->phy_addr_external; /* Fall Through */ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ - data->val_out = mdio_read(dev, data->phy_id & 0x1f, - data->reg_num & 0x1f); + /* The phy_id is not enough to uniquely identify + * the intended target. Therefore the command is sent to + * the given mii on the current port. + */ + if (dev->if_port == PORT_TP) { + if ((data->phy_id & 0x1f) == np->phy_addr_external) + data->val_out = mdio_read(dev, + data->reg_num & 0x1f); + else + data->val_out = 0; + } else { + move_int_phy(dev, data->phy_id & 0x1f); + data->val_out = miiport_read(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f); + } return 0; case SIOCSMIIREG: /* Write MII PHY register. */ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, - data->val_in); + if (dev->if_port == PORT_TP) { + if ((data->phy_id & 0x1f) == np->phy_addr_external) { + if ((data->reg_num & 0x1f) == MII_ADVERTISE) + np->advertising = data->val_in; + mdio_write(dev, data->reg_num & 0x1f, + data->val_in); + } + } else { + if ((data->phy_id & 0x1f) == np->phy_addr_external) { + if ((data->reg_num & 0x1f) == MII_ADVERTISE) + np->advertising = data->val_in; + } + move_int_phy(dev, data->phy_id & 0x1f); + miiport_write(dev, data->phy_id & 0x1f, + data->reg_num & 0x1f, + data->val_in); + } return 0; default: return -EOPNOTSUPP; @@ -2437,7 +3017,7 @@ static int netdev_ioctl(struct net_devic static void enable_wol_mode(struct net_device *dev, int enable_intr) { long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); if (netif_msg_wol(np)) printk(KERN_INFO "%s: remaining active for wake-on-lan\n", @@ -2470,7 +3050,7 @@ static void enable_wol_mode(struct net_d static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); if (netif_msg_ifdown(np)) printk(KERN_DEBUG @@ -2582,7 +3162,7 @@ static void __devexit natsemi_remove1 (s static int natsemi_suspend (struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; rtnl_lock(); @@ -2629,7 +3209,7 @@ static int natsemi_suspend (struct pci_d static int natsemi_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct netdev_private *np = dev->priv; + struct netdev_private *np = netdev_priv(dev); rtnl_lock(); if (netif_device_present(dev)) --- linux-2.6.8-rc1/drivers/net/ne2k-pci.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/net/ne2k-pci.c 2004-07-13 17:09:13.000000000 -0700 @@ -132,7 +132,7 @@ static struct { {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, {"Winbond W89C940(misprogrammed)", 0}, - {0,} + {NULL,} }; --- linux-2.6.8-rc1/drivers/net/pcmcia/3c574_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/3c574_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -519,6 +519,7 @@ static void tc574_config(dev_link_t *lin link->state &= ~DEV_CONFIG_PENDING; link->dev = &lp->node; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/pcmcia/3c589_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/3c589_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -391,6 +391,7 @@ static void tc589_config(dev_link_t *lin link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/pcmcia/axnet_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/axnet_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -458,6 +458,7 @@ static void axnet_config(dev_link_t *lin info->phy_id = (i < 32) ? i : -1; link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/pcmcia/com20020_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/com20020_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -394,6 +394,7 @@ static void com20020_config(dev_link_t * link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); i = com20020_found(dev, 0); /* calls register_netdev */ --- linux-2.6.8-rc1/drivers/net/pcmcia/fmvj18x_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/fmvj18x_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -591,6 +591,7 @@ static void fmvj18x_config(dev_link_t *l lp->cardtype = cardtype; link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/pcmcia/ibmtr_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/ibmtr_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -366,6 +366,7 @@ static void ibmtr_config(dev_link_t *lin link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); i = ibmtr_probe_card(dev); if (i != 0) { --- linux-2.6.8-rc1/drivers/net/pcmcia/nmclan_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/nmclan_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -775,6 +775,7 @@ static void nmclan_config(dev_link_t *li link->dev = &lp->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); i = register_netdev(dev); if (i != 0) { --- linux-2.6.8-rc1/drivers/net/pcmcia/pcnet_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/pcnet_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -722,6 +722,7 @@ static void pcnet_config(dev_link_t *lin link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ei_poll; --- linux-2.6.8-rc1/drivers/net/pcmcia/smc91c92_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/smc91c92_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -1022,6 +1022,7 @@ static void smc91c92_config(dev_link_t * link->dev = &smc->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); @@ -1272,7 +1273,7 @@ static int smc_open(struct net_device *d link->open++; netif_start_queue(dev); - smc->saved_skb = 0; + smc->saved_skb = NULL; smc->packets_waiting = 0; smc_reset(dev); --- linux-2.6.8-rc1/drivers/net/pcmcia/xirc2ps_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcmcia/xirc2ps_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -815,7 +815,7 @@ xirc2ps_config(dev_link_t * link) cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - local->dingo_ccr = 0; + local->dingo_ccr = NULL; DEBUG(0, "config(0x%p)\n", link); @@ -1121,6 +1121,7 @@ xirc2ps_config(dev_link_t * link) link->dev = &local->node; link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/pcnet32.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pcnet32.c 2004-07-13 17:09:13.000000000 -0700 @@ -1839,7 +1839,7 @@ pcnet32_interrupt(int irq, void *dev_id, pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = 0; + lp->tx_skbuff[entry] = NULL; lp->tx_dma_addr[entry] = 0; } dirty_tx++; --- linux-2.6.8-rc1/drivers/net/pppoe.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/pppoe.c 2004-07-13 17:09:54.000000000 -0700 @@ -79,6 +79,8 @@ #define PPPOE_HASH_BITS 4 #define PPPOE_HASH_SIZE (1<. May 20 2002 - Add link status force-mode and TBI mode support. ========================================================================= - 1. The media can be forced in 5 modes. + 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes. Command: 'insmod r8169 media = SET_MEDIA' Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex. @@ -41,6 +41,7 @@ VERSION 1.2 <2002/11/30> #include #include #include +#include #include #include #include @@ -64,6 +65,14 @@ VERSION 1.2 <2002/11/30> #define dprintk(fmt, args...) do {} while (0) #endif /* RTL8169_DEBUG */ +#ifdef CONFIG_R8169_NAPI +#define rtl8169_rx_skb netif_receive_skb +#define rtl8169_rx_quota(count, quota) min(count, quota) +#else +#define rtl8169_rx_skb netif_rx +#define rtl8169_rx_quota(count, quota) count +#endif + /* media options */ #define MAX_UNITS 8 static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; @@ -90,15 +99,16 @@ static int multicast_filter_limit = 32; #define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ +#define R8169_NAPI_WEIGHT 64 #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ +#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ #define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) #define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 #define RTL8169_TX_TIMEOUT (6*HZ) -#define RTL8169_PHY_TIMEOUT (HZ) +#define RTL8169_PHY_TIMEOUT (10*HZ) /* write/read MMIO register */ #define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) @@ -194,7 +204,7 @@ enum RTL8169_register_content { SWInt = 0x0100, TxDescUnavail = 0x80, RxFIFOOver = 0x40, - RxUnderrun = 0x20, + LinkChg = 0x20, RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, @@ -233,6 +243,14 @@ enum RTL8169_register_content { TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + /* TBICSR p.28 */ + TBIReset = 0x80000000, + TBILoopback = 0x40000000, + TBINwEnable = 0x20000000, + TBINwRestart = 0x10000000, + TBILinkOk = 0x02000000, + TBINwComplete = 0x01000000, + /* CPlusCmd p.31 */ RxVlan = (1 << 6), RxChkSum = (1 << 5), @@ -306,10 +324,10 @@ struct RxDesc { }; struct rtl8169_private { - void *mmio_addr; /* memory map physical address */ + void *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device_stats stats; /* statistics of net device */ - spinlock_t lock; /* spin lock flag */ + spinlock_t lock; /* spin lock flag */ int chipset; int mac_version; int phy_version; @@ -317,15 +335,23 @@ struct rtl8169_private { u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; u32 dirty_tx; - struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ - struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ + struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ + struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ dma_addr_t TxPhyAddr; dma_addr_t RxPhyAddr; struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ - struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ + struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Tx data buffers */ struct timer_list timer; - unsigned long phy_link_down_cnt; u16 cp_cmd; + u16 intr_mask; + int phy_auto_nego_reg; + int phy_1000_ctrl_reg; + + int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); + void (*get_settings)(struct net_device *, struct ethtool_cmd *); + void (*phy_reset_enable)(void *); + unsigned int (*phy_reset_pending)(void *); + unsigned int (*link_ok)(void *); }; MODULE_AUTHOR("Realtek"); @@ -344,9 +370,14 @@ static int rtl8169_close(struct net_devi static void rtl8169_set_rx_mode(struct net_device *dev); static void rtl8169_tx_timeout(struct net_device *dev); static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev); +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget); +#endif static const u16 rtl8169_intr_mask = - RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; + LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; +static const u16 rtl8169_napi_event = + RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr; static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); @@ -364,11 +395,9 @@ static void mdio_write(void *ioaddr, int for (i = 2000; i > 0; i--) { // Check if the RTL8169 has completed writing to the specified MII register - if (!(RTL_R32(PHYAR) & 0x80000000)) { + if (!(RTL_R32(PHYAR) & 0x80000000)) break; - } else { - udelay(100); - } + udelay(100); } } @@ -390,18 +419,264 @@ static int mdio_read(void *ioaddr, int R return value; } +static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBIReset; +} + +static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) +{ + return mdio_read(ioaddr, 0) & 0x8000; +} + +static unsigned int rtl8169_tbi_link_ok(void *ioaddr) +{ + return RTL_R32(TBICSR) & TBILinkOk; +} + +static unsigned int rtl8169_xmii_link_ok(void *ioaddr) +{ + return RTL_R8(PHYstatus) & LinkStatus; +} + +static void rtl8169_tbi_reset_enable(void *ioaddr) +{ + RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); +} + +static void rtl8169_xmii_reset_enable(void *ioaddr) +{ + unsigned int val; + + val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff; + mdio_write(ioaddr, PHY_CTRL_REG, val); +} + +static void rtl8169_check_link_status(struct net_device *dev, + struct rtl8169_private *tp, void *ioaddr) +{ + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + if (tp->link_ok(ioaddr)) { + netif_carrier_on(dev); + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else + netif_carrier_off(dev); + spin_unlock_irqrestore(&tp->lock, flags); +} + +static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex) +{ + struct { + u16 speed; + u8 duplex; + u8 autoneg; + u8 media; + } link_settings[] = { + { SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE, _10_Half }, + { SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE, _10_Full }, + { SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE, _100_Half }, + { SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE, _100_Full }, + { SPEED_1000, DUPLEX_FULL, AUTONEG_DISABLE, _1000_Full }, + /* Make TBI happy */ + { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff } + }, *p; + unsigned char option; + + option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff; + + if ((option != 0xff) && !idx) + printk(KERN_WARNING PFX "media option is deprecated.\n"); + + for (p = link_settings; p->media != 0xff; p++) { + if (p->media == option) + break; + } + *autoneg = p->autoneg; + *speed = p->speed; + *duplex = p->duplex; +} + static void rtl8169_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); strcpy(info->driver, RTL8169_DRIVER_NAME); strcpy(info->version, RTL8169_VERSION ); strcpy(info->bus_info, pci_name(tp->pci_dev)); } +static int rtl8169_set_speed_tbi(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int ret = 0; + u32 reg; + + reg = RTL_R32(TBICSR); + if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && + (duplex == DUPLEX_FULL)) { + RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); + } else if (autoneg == AUTONEG_ENABLE) + RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); + else { + printk(KERN_WARNING PFX + "%s: incorrect speed setting refused in TBI mode\n", + dev->name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int rtl8169_set_speed_xmii(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + int auto_nego, giga_ctrl; + + auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); + auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG); + giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null); + + if (autoneg == AUTONEG_ENABLE) { + auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full | + PHY_Cap_100_Half | PHY_Cap_100_Full); + giga_ctrl |= PHY_Cap_1000_Full; + } else { + if (speed == SPEED_10) + auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full; + else if (speed == SPEED_100) + auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full; + else if (speed == SPEED_1000) + giga_ctrl |= PHY_Cap_1000_Full; + + if (duplex == DUPLEX_HALF) + auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full); + } + + tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + + mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego); + mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl); + mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | + PHY_Restart_Auto_Nego); + return 0; +} + +static int rtl8169_set_speed(struct net_device *dev, + u8 autoneg, u16 speed, u8 duplex) +{ + struct rtl8169_private *tp = netdev_priv(dev); + int ret; + + ret = tp->set_speed(dev, autoneg, speed, duplex); + + if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT); + + return ret; +} + +static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&tp->lock, flags); + ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex); + spin_unlock_irqrestore(&tp->lock, flags); + + return ret; +} + +static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u32 status; + + cmd->supported = + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + cmd->transceiver = XCVR_INTERNAL; + + status = RTL_R32(TBICSR); + cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0; + cmd->autoneg = !!(status & TBINwEnable); + + cmd->speed = SPEED_1000; + cmd->duplex = DUPLEX_FULL; /* Always set */ +} + +static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + u8 status; + + cmd->supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_TP; + + cmd->autoneg = 1; + cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg; + + if (tp->phy_auto_nego_reg & PHY_Cap_10_Half) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_10_Full) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Half) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (tp->phy_auto_nego_reg & PHY_Cap_100_Full) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full) + cmd->advertising |= ADVERTISED_1000baseT_Full; + + status = RTL_R8(PHYstatus); + + if (status & _1000bpsF) + cmd->speed = SPEED_1000; + else if (status & _100bps) + cmd->speed = SPEED_100; + else if (status & _10bps) + cmd->speed = SPEED_10; + + cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ? + DUPLEX_FULL : DUPLEX_HALF; +} + +static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + tp->get_settings(dev, cmd); + + spin_unlock_irqrestore(&tp->lock, flags); + return 0; +} + + static struct ethtool_ops rtl8169_ethtool_ops = { .get_drvinfo = rtl8169_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_settings = rtl8169_get_settings, + .set_settings = rtl8169_set_settings, }; static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum, @@ -500,7 +775,7 @@ static void rtl8169_print_phy_version(st static void rtl8169_hw_phy_config(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; struct { u16 regs[5]; /* Beware of bit-sign propagation */ @@ -566,61 +841,47 @@ static void rtl8169_hw_phy_config(struct mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0 } -static void rtl8169_hw_phy_reset(struct net_device *dev) -{ - struct rtl8169_private *tp = dev->priv; - void *ioaddr = tp->mmio_addr; - int i, val; - - printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name); - - val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff; - mdio_write(ioaddr, 0, val); - - for (i = 50; i >= 0; i--) { - if (!(mdio_read(ioaddr, 0) & 0x8000)) - break; - udelay(100); /* Gross */ - } - - if (i < 0) { - printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n", - dev->name); - } -} - static void rtl8169_phy_timer(unsigned long __opaque) { struct net_device *dev = (struct net_device *)__opaque; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; void *ioaddr = tp->mmio_addr; + unsigned long timeout = RTL8169_PHY_TIMEOUT; assert(tp->mac_version > RTL_GIGA_MAC_VER_B); assert(tp->phy_version < RTL_GIGA_PHY_VER_G); - if (RTL_R8(PHYstatus) & LinkStatus) - tp->phy_link_down_cnt = 0; - else { - tp->phy_link_down_cnt++; - if (tp->phy_link_down_cnt >= 12) { - int reg; - - // If link on 1000, perform phy reset. - reg = mdio_read(ioaddr, PHY_1000_CTRL_REG); - if (reg & PHY_Cap_1000_Full) - rtl8169_hw_phy_reset(dev); + if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)) + return; - tp->phy_link_down_cnt = 0; - } + spin_lock_irq(&tp->lock); + + if (tp->phy_reset_pending(ioaddr)) { + /* + * A busy loop could burn quite a few cycles on nowadays CPU. + * Let's delay the execution of the timer for a few ticks. + */ + timeout = HZ/10; + goto out_mod_timer; } - mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); + if (tp->link_ok(ioaddr)) + goto out_unlock; + + printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name); + + tp->phy_reset_enable(ioaddr); + +out_mod_timer: + mod_timer(timer, jiffies + timeout); +out_unlock: + spin_unlock_irq(&tp->lock); } static inline void rtl8169_delete_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || @@ -628,21 +889,17 @@ static inline void rtl8169_delete_timer( return; del_timer_sync(timer); - - tp->phy_link_down_cnt = 0; } static inline void rtl8169_request_timer(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct timer_list *timer = &tp->timer; if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) || (tp->phy_version >= RTL_GIGA_PHY_VER_G)) return; - tp->phy_link_down_cnt = 0; - init_timer(timer); timer->expires = jiffies + RTL8169_PHY_TIMEOUT; timer->data = (unsigned long)(dev); @@ -681,7 +938,7 @@ rtl8169_init_board(struct pci_dev *pdev, // enable device (incl. PCI PM wakeup and hotplug setup) rc = pci_enable_device(pdev); if (rc) { - printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name); goto err_out; } @@ -693,7 +950,8 @@ rtl8169_init_board(struct pci_dev *pdev, pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command); acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } else { - printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n"); + printk(KERN_ERR PFX + "Cannot find PowerManagement capability, aborting.\n"); goto err_out_free_res; } @@ -718,7 +976,8 @@ rtl8169_init_board(struct pci_dev *pdev, rc = pci_request_regions(pdev, MODULENAME); if (rc) { - printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name); + printk(KERN_ERR PFX "%s: could not request regions.\n", + pdev->slot_name); goto err_out_disable; } @@ -800,8 +1059,9 @@ rtl8169_init_one(struct pci_dev *pdev, c void *ioaddr = NULL; static int board_idx = -1; static int printed_version = 0; + u8 autoneg, duplex; + u16 speed; int i, rc; - int option = -1, Cap10_100 = 0, Cap1000 = 0; assert(pdev != NULL); assert(ent != NULL); @@ -822,6 +1082,22 @@ rtl8169_init_one(struct pci_dev *pdev, c assert(dev != NULL); assert(tp != NULL); + if (RTL_R8(PHYstatus) & TBI_Enable) { + tp->set_speed = rtl8169_set_speed_tbi; + tp->get_settings = rtl8169_gset_tbi; + tp->phy_reset_enable = rtl8169_tbi_reset_enable; + tp->phy_reset_pending = rtl8169_tbi_reset_pending; + tp->link_ok = rtl8169_tbi_link_ok; + + tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */ + } else { + tp->set_speed = rtl8169_set_speed_xmii; + tp->get_settings = rtl8169_gset_xmii; + tp->phy_reset_enable = rtl8169_xmii_reset_enable; + tp->phy_reset_pending = rtl8169_xmii_reset_pending; + tp->link_ok = rtl8169_xmii_link_ok; + } + // Get MAC address. FIXME: read EEPROM for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); @@ -836,9 +1112,12 @@ rtl8169_init_one(struct pci_dev *pdev, c dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; -// dev->do_ioctl = mii_ioctl; - - tp = dev->priv; // private data // +#ifdef CONFIG_R8169_NAPI + dev->poll = rtl8169_poll; + dev->weight = R8169_NAPI_WEIGHT; + printk(KERN_INFO PFX "NAPI enabled\n"); +#endif + tp->intr_mask = 0xffff; tp->pci_dev = pdev; tp->mmio_addr = ioaddr; @@ -885,95 +1164,12 @@ rtl8169_init_one(struct pci_dev *pdev, c mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 } - // if TBI is not endbled - if (!(RTL_R8(PHYstatus) & TBI_Enable)) { - int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG); - - option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; - // Force RTL8169 in 10/100/1000 Full/Half mode. - if (option > 0) { - printk(KERN_INFO "%s: Force-mode Enabled.\n", - dev->name); - Cap10_100 = 0, Cap1000 = 0; - switch (option) { - case _10_Half: - Cap10_100 = PHY_Cap_10_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _10_Full: - Cap10_100 = PHY_Cap_10_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Half: - Cap10_100 = PHY_Cap_100_Half_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _100_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_Null; - break; - case _1000_Full: - Cap10_100 = PHY_Cap_100_Full_Or_Less; - Cap1000 = PHY_Cap_1000_Full; - break; - default: - break; - } - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000); - } else { - printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", - dev->name); + rtl8169_link_option(board_idx, &autoneg, &speed, &duplex); - // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged - mdio_write(ioaddr, PHY_AUTO_NEGO_REG, - PHY_Cap_100_Full_Or_Less | (val & 0x1f)); - - // enable 1000 Full Mode - mdio_write(ioaddr, PHY_1000_CTRL_REG, - PHY_Cap_1000_Full); - - } - - // Enable auto-negotiation and restart auto-nigotiation - mdio_write(ioaddr, PHY_CTRL_REG, - PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego); - udelay(100); - - // wait for auto-negotiation process - for (i = 10000; i > 0; i--) { - //check if auto-negotiation complete - if (mdio_read(ioaddr, PHY_STAT_REG) & - PHY_Auto_Neco_Comp) { - udelay(100); - option = RTL_R8(PHYstatus); - if (option & _1000bpsF) { - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation.\n", - dev->name); - } else { - printk(KERN_INFO - "%s: %sMbps %s-duplex operation.\n", - dev->name, - (option & _100bps) ? "100" : - "10", - (option & FullDup) ? "Full" : - "Half"); - } - break; - } else { - udelay(100); - } - } // end for-loop to wait for auto-negotiation process - - } else { - udelay(100); - printk(KERN_INFO - "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n", - dev->name, - (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed"); - - } + rtl8169_set_speed(dev, autoneg, speed, duplex); + + if (RTL_R8(PHYstatus) & TBI_Enable) + printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); return 0; } @@ -982,7 +1178,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); assert(dev != NULL); assert(tp != NULL); @@ -1001,7 +1197,7 @@ rtl8169_remove_one(struct pci_dev *pdev) static int rtl8169_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -1042,7 +1238,7 @@ static int rtl8169_resume(struct pci_dev static int rtl8169_open(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; int retval; @@ -1074,6 +1270,8 @@ rtl8169_open(struct net_device *dev) rtl8169_hw_start(dev); rtl8169_request_timer(dev); + + rtl8169_check_link_status(dev, tp, tp->mmio_addr); out: return retval; @@ -1091,7 +1289,7 @@ err_free_irq: static void rtl8169_hw_start(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u32 i; @@ -1102,8 +1300,7 @@ rtl8169_hw_start(struct net_device *dev) for (i = 1000; i > 0; i--) { if ((RTL_R8(ChipCmd) & CmdReset) == 0) break; - else - udelay(10); + udelay(10); } RTL_W8(Cfg9346, Cfg9346_Unlock); @@ -1114,8 +1311,8 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(RxMaxSize, RxPacketMaxSize); // Set Rx Config register - i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset]. - RxConfigMask); + i = rtl8169_rx_config | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, i); /* Set DMA burst size and Interframe Gap Time */ @@ -1126,7 +1323,8 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(CPlusCmd, tp->cp_cmd); if (tp->mac_version == RTL_GIGA_MAC_VER_D) { - dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n"); + dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. " + "Bit-3 and bit-14 MUST be 1\n"); tp->cp_cmd |= (1 << 14) | PCIMulRW; RTL_W16(CPlusCmd, tp->cp_cmd); } @@ -1151,7 +1349,6 @@ rtl8169_hw_start(struct net_device *dev) RTL_W16(IntrMask, rtl8169_intr_mask); netif_start_queue(dev); - } static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) @@ -1248,7 +1445,7 @@ static inline void rtl8169_mark_as_last_ static int rtl8169_init_ring(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); tp->cur_rx = tp->dirty_rx = 0; tp->cur_tx = tp->dirty_tx = 0; @@ -1302,10 +1499,11 @@ rtl8169_tx_clear(struct rtl8169_private static void rtl8169_tx_timeout(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; u8 tmp8; + printk(KERN_INFO "%s: TX Timeout\n", dev->name); /* disable Tx, if not already */ tmp8 = RTL_R8(ChipCmd); if (tmp8 & CmdTxEnb) @@ -1328,9 +1526,9 @@ rtl8169_tx_timeout(struct net_device *de static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; - int entry = tp->cur_tx % NUM_TX_DESC; + unsigned int entry = tp->cur_tx % NUM_TX_DESC; u32 len = skb->len; if (unlikely(skb->len < ETH_ZLEN)) { @@ -1340,10 +1538,9 @@ rtl8169_start_xmit(struct sk_buff *skb, len = ETH_ZLEN; } - spin_lock_irq(&tp->lock); - if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) { dma_addr_t mapping; + u32 status; mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE); @@ -1351,24 +1548,30 @@ rtl8169_start_xmit(struct sk_buff *skb, tp->Tx_skbuff[entry] = skb; tp->TxDescArray[entry].addr = cpu_to_le64(mapping); - tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit | - LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC))); + /* anti gcc 2.95.3 bugware */ + status = OWNbit | FSbit | LSbit | len | + (EORbit * !((entry + 1) % NUM_TX_DESC)); + tp->TxDescArray[entry].status = cpu_to_le32(status); RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; + smp_wmb(); } else goto err_drop; - if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { + u32 dirty = tp->dirty_tx; + netif_stop_queue(dev); + smp_rmb(); + if (dirty != tp->dirty_tx) + netif_wake_queue(dev); } -out: - spin_unlock_irq(&tp->lock); +out: return 0; err_drop: @@ -1382,17 +1585,18 @@ static void rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long dirty_tx, tx_left; + unsigned int dirty_tx, tx_left; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); dirty_tx = tp->dirty_tx; + smp_rmb(); tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { - int entry = dirty_tx % NUM_TX_DESC; + unsigned int entry = dirty_tx % NUM_TX_DESC; struct sk_buff *skb = tp->Tx_skbuff[entry]; u32 status; @@ -1415,6 +1619,7 @@ rtl8169_tx_interrupt(struct net_device * if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; + smp_wmb(); if (netif_queue_stopped(dev)) netif_wake_queue(dev); } @@ -1442,11 +1647,11 @@ static inline int rtl8169_try_rx_copy(st return ret; } -static void +static int rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - unsigned long cur_rx, rx_left; + unsigned int cur_rx, rx_left, count; int delta; assert(dev != NULL); @@ -1455,9 +1660,10 @@ rtl8169_rx_interrupt(struct net_device * cur_rx = tp->cur_rx; rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; + rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota); while (rx_left > 0) { - int entry = cur_rx % NUM_RX_DESC; + unsigned int entry = cur_rx % NUM_RX_DESC; u32 status; rmb(); @@ -1494,7 +1700,7 @@ rtl8169_rx_interrupt(struct net_device * skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + rtl8169_rx_skb(skb); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; @@ -1505,13 +1711,15 @@ rtl8169_rx_interrupt(struct net_device * rx_left--; } + count = cur_rx - tp->cur_rx; tp->cur_rx = cur_rx; delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); - if (delta > 0) - tp->dirty_rx += delta; - else if (delta < 0) + if (delta < 0) { printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + delta = 0; + } + tp->dirty_rx += delta; /* * FIXME: until there is periodic timer to try and refill the ring, @@ -1522,6 +1730,8 @@ rtl8169_rx_interrupt(struct net_device * */ if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); + + return count; } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -1529,7 +1739,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0; @@ -1543,26 +1753,37 @@ rtl8169_interrupt(int irq, void *dev_ins break; handled = 1; -/* - if (status & RxUnderrun) - link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; -*/ + + status &= tp->intr_mask; RTL_W16(IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); if (!(status & rtl8169_intr_mask)) break; + if (status & LinkChg) + rtl8169_check_link_status(dev, tp, ioaddr); + +#ifdef CONFIG_R8169_NAPI + RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event); + tp->intr_mask = ~rtl8169_napi_event; + + if (likely(netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + else { + printk(KERN_INFO "%s: interrupt %x taken in poll\n", + dev->name, status); + } + break; +#else // Rx interrupt - if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) { + if (status & (RxOK | RxOverflow | RxFIFOOver)) { rtl8169_rx_interrupt(dev, tp, ioaddr); } // Tx interrupt - if (status & (TxOK | TxErr)) { - spin_lock(&tp->lock); + if (status & (TxOK | TxErr)) rtl8169_tx_interrupt(dev, tp, ioaddr); - spin_unlock(&tp->lock); - } +#endif boguscnt--; } while (boguscnt > 0); @@ -1576,10 +1797,40 @@ rtl8169_interrupt(int irq, void *dev_ins return IRQ_RETVAL(handled); } +#ifdef CONFIG_R8169_NAPI +static int rtl8169_poll(struct net_device *dev, int *budget) +{ + unsigned int work_done, work_to_do = min(*budget, dev->quota); + struct rtl8169_private *tp = netdev_priv(dev); + void *ioaddr = tp->mmio_addr; + + work_done = rtl8169_rx_interrupt(dev, tp, ioaddr); + rtl8169_tx_interrupt(dev, tp, ioaddr); + + *budget -= work_done; + dev->quota -= work_done; + + if ((work_done < work_to_do) || !netif_running(dev)) { + netif_rx_complete(dev); + tp->intr_mask = 0xffff; + /* + * 20040426: the barrier is not strictly required but the + * behavior of the irq handler could be less predictable + * without it. Btw, the lack of flush for the posted pci + * write is safe - FR + */ + smp_wmb(); + RTL_W16(IntrMask, rtl8169_intr_mask); + } + + return (work_done >= work_to_do); +} +#endif + static int rtl8169_close(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; @@ -1621,7 +1872,7 @@ rtl8169_close(struct net_device *dev) static void rtl8169_set_rx_mode(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ @@ -1655,10 +1906,8 @@ rtl8169_set_rx_mode(struct net_device *d spin_lock_irqsave(&tp->lock, flags); - tmp = - rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & - rtl_chip_info[tp->chipset]. - RxConfigMask); + tmp = rtl8169_rx_config | rx_mode | + (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); RTL_W32(RxConfig, tmp); RTL_W32(MAR0 + 0, mc_filter[0]); @@ -1675,7 +1924,7 @@ rtl8169_set_rx_mode(struct net_device *d */ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) { - struct rtl8169_private *tp = dev->priv; + struct rtl8169_private *tp = netdev_priv(dev); void *ioaddr = tp->mmio_addr; unsigned long flags; --- linux-2.6.8-rc1/drivers/net/rrunner.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/rrunner.c 2004-07-13 17:09:13.000000000 -0700 @@ -197,7 +197,8 @@ static int __devinit rr_init_one(struct * Don't access any register before this point! */ #ifdef __BIG_ENDIAN - writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); + writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP, + &rrpriv->regs->HostCtrl); #endif /* * Need to add a case for little-endian 64-bit hosts here. @@ -633,7 +634,7 @@ static int rr_init1(struct net_device *d for (i = 0; i < TX_RING_ENTRIES; i++) { rrpriv->tx_ring[i].size = 0; set_rraddr(&rrpriv->tx_ring[i].addr, 0); - rrpriv->tx_skbuff[i] = 0; + rrpriv->tx_skbuff[i] = NULL; } rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; @@ -743,7 +744,7 @@ static int rr_init1(struct net_device *d rrpriv->rx_ring[i].size = 0; set_rraddr(&rrpriv->rx_ring[i].addr, 0); dev_kfree_skb(skb); - rrpriv->rx_skbuff[i] = 0; + rrpriv->rx_skbuff[i] = NULL; } } return ecode; --- linux-2.6.8-rc1/drivers/net/sis900.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/sis900.c 2004-07-13 17:09:23.000000000 -0700 @@ -116,6 +116,7 @@ static struct mii_chip_info { #define HOME 0x0001 #define LAN 0x0002 #define MIX 0x0003 +#define UNKNOWN 0x0 } mii_chip_table[] = { { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, @@ -577,9 +578,11 @@ static int __init sis900_mii_probe (stru break; } - if( !mii_chip_table[i].phy_id1 ) + if( !mii_chip_table[i].phy_id1 ) { printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n", - net_dev->name, phy_addr); + net_dev->name, phy_addr); + mii_phy->phy_types = UNKNOWN; + } } if (sis_priv->mii == NULL) { @@ -644,15 +647,15 @@ static int __init sis900_mii_probe (stru static u16 sis900_default_phy(struct net_device * net_dev) { struct sis900_private * sis_priv = net_dev->priv; - struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL; + struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL; u16 status; for( phy=sis_priv->first_mii; phy; phy=phy->next ){ status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); status = mdio_read(net_dev, phy->phy_addr, MII_STATUS); - /* Link ON & Not select deafalut PHY */ - if ( (status & MII_STAT_LINK) && !(default_phy) ) + /* Link ON & Not select default PHY & not ghost PHY */ + if ( (status & MII_STAT_LINK) && !default_phy && (phy->phy_types != UNKNOWN) ) default_phy = phy; else{ status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL); @@ -660,12 +663,16 @@ static u16 sis900_default_phy(struct net status | MII_CNTL_AUTO | MII_CNTL_ISOLATE); if( phy->phy_types == HOME ) phy_home = phy; + else if (phy->phy_types == LAN) + phy_lan = phy; } } - if( (!default_phy) && phy_home ) + if( !default_phy && phy_home ) default_phy = phy_home; - else if(!default_phy) + else if( !default_phy && phy_lan ) + default_phy = phy_lan; + else if ( !default_phy ) default_phy = sis_priv->first_mii; if( sis_priv->mii != default_phy ){ --- linux-2.6.8-rc1/drivers/net/sk98lin/h/skdrv2nd.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/sk98lin/h/skdrv2nd.h 2004-07-13 17:09:23.000000000 -0700 @@ -53,60 +53,6 @@ #include "h/skrlmt.h" #include "h/skgedrv.h" -#define SK_PCI_ISCOMPLIANT(result, pdev) { \ - result = SK_FALSE; /* default */ \ - /* 3Com (0x10b7) */ \ - if (pdev->vendor == 0x10b7) { \ - /* Gigabit Ethernet Adapter (0x1700) */ \ - if ((pdev->device == 0x1700) || \ - (pdev->device == 0x80eb)) { \ - result = SK_TRUE; \ - } \ - /* SysKonnect (0x1148) */ \ - } else if (pdev->vendor == 0x1148) { \ - /* SK-98xx Gigabit Ethernet Server Adapter (0x4300) */ \ - /* SK-98xx V2.0 Gigabit Ethernet Adapter (0x4320) */ \ - if ((pdev->device == 0x4300) || \ - (pdev->device == 0x4320)) { \ - result = SK_TRUE; \ - } \ - /* D-Link (0x1186) */ \ - } else if (pdev->vendor == 0x1186) { \ - /* Gigabit Ethernet Adapter (0x4c00) */ \ - if ((pdev->device == 0x4c00)) { \ - result = SK_TRUE; \ - } \ - /* Marvell (0x11ab) */ \ - } else if (pdev->vendor == 0x11ab) { \ - /* Gigabit Ethernet Adapter (0x4320) */ \ - /* Gigabit Ethernet Adapter (0x4360) */ \ - /* Gigabit Ethernet Adapter (0x4361) */ \ - /* Belkin (0x5005) */ \ - if ((pdev->device == 0x4320) || \ - (pdev->device == 0x4360) || \ - (pdev->device == 0x4361) || \ - (pdev->device == 0x5005)) { \ - result = SK_TRUE; \ - } \ - /* CNet (0x1371) */ \ - } else if (pdev->vendor == 0x1371) { \ - /* GigaCard Network Adapter (0x434e) */ \ - if ((pdev->device == 0x434e)) { \ - result = SK_TRUE; \ - } \ - /* Linksys (0x1737) */ \ - } else if (pdev->vendor == 0x1737) { \ - /* Gigabit Network Adapter (0x1032) */ \ - /* Gigabit Network Adapter (0x1064) */ \ - if ((pdev->device == 0x1032) || \ - (pdev->device == 0x1064)) { \ - result = SK_TRUE; \ - } \ - } else { \ - result = SK_FALSE; \ - } \ -} - extern SK_MBUF *SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned); extern void SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*); --- linux-2.6.8-rc1/drivers/net/sk98lin/skaddr.c 2004-03-10 20:41:28.000000000 -0800 +++ 25/drivers/net/sk98lin/skaddr.c 2004-07-13 17:09:50.000000000 -0700 @@ -892,7 +892,7 @@ SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); @@ -1424,7 +1424,7 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { - int ReturnCode; + int ReturnCode = 0; #if (!defined(SK_SLIM) || defined(DEBUG)) if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); --- linux-2.6.8-rc1/drivers/net/sk98lin/skge.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/sk98lin/skge.c 2004-07-13 17:09:44.000000000 -0700 @@ -239,7 +239,7 @@ static int SkDrvDeInitAdapter(SK_AC #ifdef CONFIG_PROC_FS static const char SK_Root_Dir_entry[] = "sk98lin"; -static struct proc_dir_entry *pSkRootDir = NULL; +static struct proc_dir_entry *pSkRootDir; extern struct file_operations sk_proc_fops; #endif @@ -255,303 +255,13 @@ static void DumpLong(char*, int); #endif /* global variables *********************************************************/ -static const char *BootString = BOOT_STRING; struct SK_NET_DEVICE *SkGeRootDev = NULL; -static int probed __initdata = 0; static SK_BOOL DoPrintInterfaceChange = SK_TRUE; /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *pSkRootDir; -#endif - - - -/***************************************************************************** - * - * skge_probe - find all SK-98xx adapters - * - * Description: - * This function scans the PCI bus for SK-98xx adapters. Resources for - * each adapter are allocated and the adapter is brought into Init 1 - * state. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_probe (void) -{ - int boards_found = 0; - int vendor_flag = SK_FALSE; - SK_AC *pAC; - DEV_NET *pNet = NULL; - struct pci_dev *pdev = NULL; - struct SK_NET_DEVICE *dev = NULL; - SK_BOOL DeviceFound = SK_FALSE; - SK_BOOL BootStringCount = SK_FALSE; - int retval; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *pProcFile; -#endif - - if (probed) - return -ENODEV; - probed++; - - - while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { - - if (pci_enable_device(pdev)) { - continue; - } - dev = NULL; - pNet = NULL; - - /* Don't handle Yukon2 cards at the moment */ - /* 12-feb-2004 ---- mlindner@syskonnect.de */ - if (pdev->vendor == 0x11ab) { - if ( (pdev->device == 0x4360) || (pdev->device == 0x4361) ) - continue; - } - - SK_PCI_ISCOMPLIANT(vendor_flag, pdev); - if (!vendor_flag) - continue; - - /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && - pci_set_dma_mask(pdev, (u64) 0xffffffff)) - continue; - - - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pNet = dev->priv; - pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); - if (pNet->pAC == NULL){ - free_netdev(dev); - printk(KERN_ERR "Unable to allocate adapter " - "structure!\n"); - break; - } - - /* Print message */ - if (!BootStringCount) { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - BootStringCount = SK_TRUE; - printk("%s\n", BootString); - } - - memset(pNet->pAC, 0, sizeof(SK_AC)); - pAC = pNet->pAC; - pAC->PciDev = pdev; - pAC->PciDevId = pdev->device; - pAC->dev[0] = dev; - pAC->dev[1] = dev; - sprintf(pAC->Name, "SysKonnect SK-98xx"); - pAC->CheckQueue = SK_FALSE; - - pNet->Mtu = 1500; - pNet->Up = 0; - dev->irq = pdev->irq; - retval = SkGeInitPCI(pAC); - if (retval) { - printk("SKGE: PCI setup failed: %i\n", retval); - free_netdev(dev); - continue; - } - - SET_MODULE_OWNER(dev); - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - SET_NETDEV_DEV(dev, &pdev->dev); - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - - if (pAC->ChipsetType) { - /* Use only if yukon hardware */ - /* SK and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - pAC->Index = boards_found; - - if (SkGeBoardInit(dev, pAC)) { - free_netdev(dev); - continue; - } - - /* Register net device */ - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - FreeResources(dev); - free_netdev(dev); - continue; - } - - /* Print adapter specific string from vpd */ - ProductStr(pAC); - printk("%s: %s\n", dev->name, pAC->DeviceStr); - - /* Print configuration settings */ - printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, - (pAC->RlmtMode==0) ? "Check Link State" : - ((pAC->RlmtMode==1) ? "Check Link State" : - ((pAC->RlmtMode==3) ? "Check Local Port" : - ((pAC->RlmtMode==7) ? "Check Segmentation" : - ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); - - SkGeYellowLED(pAC, pAC->IoBase, 1); - - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); - - /* First adapter... Create proc and print message */ -#ifdef CONFIG_PROC_FS - if (!DeviceFound) { - DeviceFound = SK_TRUE; - SK_MEMCPY(&SK_Root_Dir_entry, BootString, - sizeof(SK_Root_Dir_entry) - 1); - - /*Create proc (directory)*/ - if(!pSkRootDir) { - pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); - if (!pSkRootDir) { - printk(KERN_WARNING "%s: Unable to create /proc/net/%s", - dev->name, SK_Root_Dir_entry); - } else { - pSkRootDir->owner = THIS_MODULE; - } - } - } - - /* Create proc file */ - if (pSkRootDir && - (pProcFile = create_proc_entry(dev->name, S_IRUGO, - pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } - -#endif - - pNet->PortNr = 0; - pNet->NetNr = 0; - - boards_found++; - - /* More then one port found */ - if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { - printk(KERN_ERR "Unable to allocate etherdev " - "structure!\n"); - break; - } - - pAC->dev[1] = dev; - pNet = dev->priv; - pNet->PortNr = 1; - pNet->NetNr = 1; - pNet->pAC = pAC; - pNet->Mtu = 1500; - pNet->Up = 0; - - dev->open = &SkGeOpen; - dev->stop = &SkGeClose; - dev->hard_start_xmit = &SkGeXmit; - dev->get_stats = &SkGeStats; - dev->last_stats = &SkGeStats; - dev->set_multicast_list = &SkGeSetRxMode; - dev->set_mac_address = &SkGeSetMacAddr; - dev->do_ioctl = &SkGeIoctl; - dev->change_mtu = &SkGeChangeMtu; - dev->flags &= ~IFF_RUNNING; - -#ifdef SK_ZEROCOPY -#ifdef USE_SK_TX_CHECKSUM - if (pAC->ChipsetType) { - /* SG and ZEROCOPY - fly baby... */ - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } -#endif -#endif - - if (register_netdev(dev)) { - printk(KERN_ERR "SKGE: Could not register device.\n"); - free_netdev(dev); - pAC->dev[1] = pAC->dev[0]; - } else { -#ifdef CONFIG_PROC_FS - if (pSkRootDir - && (pProcFile = create_proc_entry(dev->name, - S_IRUGO, pSkRootDir))) { - pProcFile->proc_fops = &sk_proc_fops; - pProcFile->data = dev; - } -#endif - - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); - - printk("%s: %s\n", dev->name, pAC->DeviceStr); - printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); - } - } - - /* Save the hardware revision */ - pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + - (pAC->GIni.GIPciHwRev & 0x0F); - - /* Set driver globals */ - pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; - pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; - - SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA)); - SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), - sizeof(SK_PNMI_STRUCT_DATA)); - - /* - * This is bollocks, but we need to tell the net-init - * code that it shall go for the next device. - */ -#ifndef MODULE - dev->base_addr = 0; -#endif - } - - /* - * If we're at this point we're going through skge_probe() for - * the first time. Return success (0) if we've initialized 1 - * or more boards. Otherwise, return failure (-ENODEV). - */ - - return boards_found; -} /* skge_probe */ - - /***************************************************************************** * * SkGeInitPCI - Init the PCI resources @@ -666,9 +376,6 @@ MODULE_PARM(Role_B, "1-" __MODULE_STRING MODULE_PARM(ConType, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(PrefPort, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); MODULE_PARM(RlmtMode, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); -/* not used, just there because every driver should have them: */ -MODULE_PARM(options, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); -MODULE_PARM(debug, "i"); /* used for interrupt moderation */ MODULE_PARM(IntsPerSec, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); MODULE_PARM(Moderation, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -755,123 +462,12 @@ static char *RlmtMode[SK_MAX_CARD_PARAM] static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", }; #endif -static int debug = 0; /* not used */ -static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ - static int IntsPerSec[SK_MAX_CARD_PARAM]; static char *Moderation[SK_MAX_CARD_PARAM]; static char *ModerationMask[SK_MAX_CARD_PARAM]; static char *AutoSizing[SK_MAX_CARD_PARAM]; static char *Stats[SK_MAX_CARD_PARAM]; - -/***************************************************************************** - * - * skge_init_module - module initialization function - * - * Description: - * Very simple, only call skge_probe and return approriate result. - * - * Returns: - * 0, if everything is ok - * !=0, on error - */ -static int __init skge_init_module(void) -{ - int cards; - SkGeRootDev = NULL; - - /* just to avoid warnings ... */ - debug = 0; - options[0] = 0; - - cards = skge_probe(); - if (cards == 0) { - printk("sk98lin: No adapter found.\n"); - } - return cards ? 0 : -ENODEV; -} /* skge_init_module */ - - -/***************************************************************************** - * - * skge_cleanup_module - module unload function - * - * Description: - * Disable adapter if it is still running, free resources, - * free device struct. - * - * Returns: N/A - */ -static void __exit skge_cleanup_module(void) -{ -DEV_NET *pNet; -SK_AC *pAC; -struct SK_NET_DEVICE *next; -unsigned long Flags; -SK_EVPARA EvPara; - - while (SkGeRootDev) { - pNet = (DEV_NET*) SkGeRootDev->priv; - pAC = pNet->pAC; - next = pAC->Next; - - netif_stop_queue(SkGeRootDev); - SkGeYellowLED(pAC, pAC->IoBase, 0); - - if(pAC->BoardLevel == SK_INIT_RUN) { - /* board is still alive */ - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - EvPara.Para32[0] = 0; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - EvPara.Para32[0] = 1; - EvPara.Para32[1] = -1; - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - SkEventDispatcher(pAC, pAC->IoBase); - /* disable interrupts */ - SK_OUT32(pAC->IoBase, B0_IMSK, 0); - SkGeDeInit(pAC, pAC->IoBase); - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - pAC->BoardLevel = SK_INIT_DATA; - /* We do NOT check here, if IRQ was pending, of course*/ - } - - if(pAC->BoardLevel == SK_INIT_IO) { - /* board is still alive */ - SkGeDeInit(pAC, pAC->IoBase); - pAC->BoardLevel = SK_INIT_DATA; - } - - if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ - unregister_netdev(pAC->dev[1]); - free_netdev(pAC->dev[1]); - } - - FreeResources(SkGeRootDev); - - SkGeRootDev->get_stats = NULL; - /* - * otherwise unregister_netdev calls get_stats with - * invalid IO ... :-( - */ - unregister_netdev(SkGeRootDev); - free_netdev(SkGeRootDev); - kfree(pAC); - SkGeRootDev = next; - } - -#ifdef CONFIG_PROC_FS - /* clear proc-dir */ - remove_proc_entry(pSkRootDir->name, proc_net); -#endif - -} /* skge_cleanup_module */ - -module_init(skge_init_module); -module_exit(skge_cleanup_module); - - /***************************************************************************** * * SkGeBoardInit - do level 0 and 1 initialization @@ -3094,8 +2690,7 @@ SK_EVPARA EvPara; SkEventDispatcher(pAC, pAC->IoBase); for (i=0; iGIni.GIMacsFound; i++) { - spin_lock_irqsave( - &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); netif_stop_queue(pAC->dev[i]); } @@ -4774,12 +4369,10 @@ SK_BOOL DualNet; spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST); SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4792,8 +4385,7 @@ SK_BOOL DualNet; spin_lock_irqsave( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); - spin_lock_irqsave( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); pAC->ActivePort = ToPort; #if 0 SetQueueSizes(pAC); @@ -4808,8 +4400,7 @@ SK_BOOL DualNet; pAC, pAC->ActivePort, DualNet)) { - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -4835,8 +4426,7 @@ SK_BOOL DualNet; SkGePollTxD(pAC, IoC, ToPort, SK_TRUE); ClearAndStartRx(pAC, FromPort); ClearAndStartRx(pAC, ToPort); - spin_unlock_irqrestore( - &pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags); + spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock); spin_unlock_irqrestore( &pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock, Flags); @@ -5311,8 +4901,319 @@ int l; #endif -/******************************************************************************* - * - * End of file - * - ******************************************************************************/ +static int __devinit skge_probe_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + SK_AC *pAC; + DEV_NET *pNet = NULL; + struct net_device *dev = NULL; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pProcFile; +#endif + static int boards_found = 0; + int error = -ENODEV; + + if (pci_enable_device(pdev)) + goto out; + + /* Configure DMA attributes. */ + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && + pci_set_dma_mask(pdev, (u64) 0xffffffff)) + goto out_disable_device; + + + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == NULL) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out_disable_device; + } + + pNet = dev->priv; + pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + if (!pNet->pAC) { + printk(KERN_ERR "Unable to allocate adapter " + "structure!\n"); + goto out_free_netdev; + } + + memset(pNet->pAC, 0, sizeof(SK_AC)); + pAC = pNet->pAC; + pAC->PciDev = pdev; + pAC->PciDevId = pdev->device; + pAC->dev[0] = dev; + pAC->dev[1] = dev; + sprintf(pAC->Name, "SysKonnect SK-98xx"); + pAC->CheckQueue = SK_FALSE; + + pNet->Mtu = 1500; + pNet->Up = 0; + dev->irq = pdev->irq; + error = SkGeInitPCI(pAC); + if (error) { + printk("SKGE: PCI setup failed: %i\n", error); + goto out_free_netdev; + } + + SET_MODULE_OWNER(dev); + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + SET_NETDEV_DEV(dev, &pdev->dev); + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* Use only if yukon hardware */ + /* SK and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + pAC->Index = boards_found++; + + if (SkGeBoardInit(dev, pAC)) + goto out_free_netdev; + + /* Register net device */ + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + goto out_free_resources; + } + + /* Print adapter specific string from vpd */ + ProductStr(pAC); + printk("%s: %s\n", dev->name, pAC->DeviceStr); + + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + + SkGeYellowLED(pAC, pAC->IoBase, 1); + + + memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6); + +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + pNet->PortNr = 0; + pNet->NetNr = 0; + + boards_found++; + + /* More then one port found */ + if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { + if ((dev = alloc_etherdev(sizeof(DEV_NET))) == 0) { + printk(KERN_ERR "Unable to allocate etherdev " + "structure!\n"); + goto out; + } + + pAC->dev[1] = dev; + pNet = dev->priv; + pNet->PortNr = 1; + pNet->NetNr = 1; + pNet->pAC = pAC; + pNet->Mtu = 1500; + pNet->Up = 0; + + dev->open = &SkGeOpen; + dev->stop = &SkGeClose; + dev->hard_start_xmit = &SkGeXmit; + dev->get_stats = &SkGeStats; + dev->last_stats = &SkGeStats; + dev->set_multicast_list = &SkGeSetRxMode; + dev->set_mac_address = &SkGeSetMacAddr; + dev->do_ioctl = &SkGeIoctl; + dev->change_mtu = &SkGeChangeMtu; + dev->flags &= ~IFF_RUNNING; + +#ifdef SK_ZEROCOPY +#ifdef USE_SK_TX_CHECKSUM + if (pAC->ChipsetType) { + /* SG and ZEROCOPY - fly baby... */ + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + } +#endif +#endif + + if (register_netdev(dev)) { + printk(KERN_ERR "SKGE: Could not register device.\n"); + free_netdev(dev); + pAC->dev[1] = pAC->dev[0]; + } else { +#ifdef CONFIG_PROC_FS + pProcFile = create_proc_entry(dev->name, S_IRUGO, + pSkRootDir); + if (pProcFile) { + pProcFile->proc_fops = &sk_proc_fops; + pProcFile->data = dev; + pProcFile->owner = THIS_MODULE; + } +#endif + + memcpy(&dev->dev_addr, + &pAC->Addr.Net[1].CurrentMacAddress, 6); + + printk("%s: %s\n", dev->name, pAC->DeviceStr); + printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + } + } + + /* Save the hardware revision */ + pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) + + (pAC->GIni.GIPciHwRev & 0x0F); + + /* Set driver globals */ + pAC->Pnmi.pDriverFileName = DRIVER_FILE_NAME; + pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE; + + memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA)); + memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA)); + + pci_set_drvdata(pdev, dev); + return 0; + + out_free_resources: + FreeResources(dev); + out_free_netdev: + free_netdev(dev); + out_disable_device: + pci_disable_device(pdev); + out: + return error; +} + +static void __devexit skge_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + DEV_NET *pNet = (DEV_NET *) dev->priv; + SK_AC *pAC = pNet->pAC; + int have_second_mac = 0; + + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2) + have_second_mac = 1; + + remove_proc_entry(dev->name, pSkRootDir); + unregister_netdev(dev); + if (have_second_mac) { + remove_proc_entry(pAC->dev[1]->name, pSkRootDir); + unregister_netdev(pAC->dev[1]); + } + + SkGeYellowLED(pAC, pAC->IoBase, 0); + + if (pAC->BoardLevel == SK_INIT_RUN) { + SK_EVPARA EvPara; + unsigned long Flags; + + /* board is still alive */ + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + SkGeDeInit(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + pAC->BoardLevel = SK_INIT_DATA; + /* We do NOT check here, if IRQ was pending, of course*/ + } + + if (pAC->BoardLevel == SK_INIT_IO) { + /* board is still alive */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = SK_INIT_DATA; + } + + FreeResources(dev); + free_netdev(dev); + if (have_second_mac) + free_netdev(pAC->dev[1]); + kfree(pAC); +} + +static struct pci_device_id skge_pci_tbl[] = { + { PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#if 0 /* don't handle Yukon2 cards at the moment -- mlindner@syskonnect.de */ + { PCI_VENDOR_ID_MARVELL, 0x4360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_MARVELL, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver skge_driver = { + .name = "skge", + .id_table = skge_pci_tbl, + .probe = skge_probe_one, + .remove = __devexit_p(skge_remove_one), +}; + +static int __init skge_init(void) +{ + int error; + + memcpy(&SK_Root_Dir_entry, BOOT_STRING, sizeof(SK_Root_Dir_entry) - 1); + +#ifdef CONFIG_PROC_FS + pSkRootDir = proc_mkdir(SK_Root_Dir_entry, proc_net); + if (!pSkRootDir) { + printk(KERN_WARNING "Unable to create /proc/net/%s", + SK_Root_Dir_entry); + return -ENOMEM; + } + pSkRootDir->owner = THIS_MODULE; +#endif + + error = pci_module_init(&skge_driver); + if (error) { +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif + } + + return error; +} + +static void __exit skge_exit(void) +{ + pci_unregister_driver(&skge_driver); +#ifdef CONFIG_PROC_FS + remove_proc_entry(pSkRootDir->name, proc_net); +#endif +} + +module_init(skge_init); +module_exit(skge_exit); --- linux-2.6.8-rc1/drivers/net/sk98lin/sktimer.c 2004-03-10 20:41:29.000000000 -0800 +++ 25/drivers/net/sk98lin/sktimer.c 2004-07-13 17:09:13.000000000 -0700 @@ -62,7 +62,7 @@ int Level) /* Init Level */ { switch (Level) { case SK_INIT_DATA: - pAC->Tim.StQueue = 0; + pAC->Tim.StQueue = NULL; break; case SK_INIT_IO: SkHwtInit(pAC, Ioc); @@ -145,7 +145,7 @@ SK_EVPARA Para) /* Event Parameter for if (!pAC->Tim.StQueue) { /* First Timer to be started */ pAC->Tim.StQueue = pTimer; - pTimer->TmNext = 0; + pTimer->TmNext = NULL; pTimer->TmDelta = Time; SkHwtStart(pAC, Ioc, Time); @@ -228,7 +228,7 @@ int Restart) /* Do we need to restart t Done = 1; } } - *ppLast = 0; + *ppLast = NULL; /* * pTm points to the first Timer that did not run out. * StQueue points to the first Timer that run out. --- linux-2.6.8-rc1/drivers/net/sk98lin/skvpd.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/sk98lin/skvpd.c 2004-07-13 17:09:13.000000000 -0700 @@ -556,7 +556,7 @@ SK_VPD_PARA *p) /* parameter descriptio if (*v != (char)RES_ID) { SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, ("Error: 0x%x missing\n", RES_ID)); - return(0); + return NULL; } if (strcmp(key, VPD_NAME) == 0) { @@ -600,7 +600,7 @@ SK_VPD_PARA *p) /* parameter descriptio ("Key/Len Encoding error\n")); } #endif /* DEBUG */ - return(0); + return NULL; } /* @@ -751,7 +751,7 @@ int op) /* operation to do: ADD_KEY o vpd_size = pAC->vpd.vpd_size; rtv = 0; - ip = 0; + ip = NULL; if (type == VPD_RW_KEY) { /* end tag is "RW" */ free = pAC->vpd.v.vpd_free_rw; --- linux-2.6.8-rc1/drivers/net/tokenring/ibmtr.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/tokenring/ibmtr.c 2004-07-13 17:09:13.000000000 -0700 @@ -383,7 +383,7 @@ static int __devinit ibmtr_probe1(struct { unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; - void * t_mmio = 0; + void * t_mmio = NULL; struct tok_info *ti = dev->priv; void *cd_chanid; unsigned char *tchanid, ctemp; --- linux-2.6.8-rc1/drivers/net/tokenring/lanstreamer.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/tokenring/lanstreamer.c 2004-07-13 17:09:13.000000000 -0700 @@ -446,7 +446,7 @@ static int streamer_reset(struct net_dev __u8 *streamer_mmio; unsigned long t; unsigned int uaa_addr; - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; __u16 misr; streamer_priv = (struct streamer_private *) dev->priv; --- linux-2.6.8-rc1/drivers/net/tokenring/olympic.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/tokenring/olympic.c 2004-07-13 17:09:13.000000000 -0700 @@ -268,7 +268,7 @@ static int __devinit olympic_probe(struc char proc_name[20] ; strcpy(proc_name,"net/olympic_") ; strcat(proc_name,dev->name) ; - create_proc_read_entry(proc_name,0,0,olympic_proc_info,(void *)dev) ; + create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ; printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); } return 0 ; --- linux-2.6.8-rc1/drivers/net/tokenring/smctr.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/tokenring/smctr.c 2004-07-13 17:09:13.000000000 -0700 @@ -4939,7 +4939,7 @@ static int smctr_send_rq_init(struct net tmf->dc_sc = DC_RPS | SC_RS; tmf->vl = 4; - smctr_make_8025_hdr(dev, 0L, tmf, AC_FC_RQ_INIT); + smctr_make_8025_hdr(dev, NULL, tmf, AC_FC_RQ_INIT); tsv = (MAC_SUB_VECTOR *)((__u32)tmf + sizeof(MAC_HEADER)); smctr_make_product_id(dev, tsv); --- linux-2.6.8-rc1/drivers/net/tokenring/tms380tr.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/net/tokenring/tms380tr.c 2004-07-13 17:09:13.000000000 -0700 @@ -252,6 +252,7 @@ int tms380tr_open(struct net_device *dev /* Reset the hardware here. Don't forget to set the station address. */ +#ifdef CONFIG_ISA if(dev->dma > 0) { unsigned long flags=claim_dma_lock(); @@ -260,6 +261,7 @@ int tms380tr_open(struct net_device *dev enable_dma(dev->dma); release_dma_lock(flags); } +#endif err = tms380tr_chipset_init(dev); if(err) @@ -1149,12 +1151,14 @@ int tms380tr_close(struct net_device *de del_timer(&tp->timer); tms380tr_disable_interrupts(dev); +#ifdef CONFIG_ISA if(dev->dma > 0) { unsigned long flags=claim_dma_lock(); disable_dma(dev->dma); release_dma_lock(flags); } +#endif SIFWRITEW(0xFF00, SIFCMD); #if 0 --- linux-2.6.8-rc1/drivers/net/tulip/de4x5.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/tulip/de4x5.c 2004-07-13 17:09:13.000000000 -0700 @@ -4721,8 +4721,8 @@ type1_infoblock(struct net_device *dev, if (lp->state == INITIALISED) { lp->ibn = 1; lp->active = *p++; - lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1); - lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1); + lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1); + lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1); lp->phy[lp->active].mc = TWIDDLE(p); p += 2; lp->phy[lp->active].ana = TWIDDLE(p); p += 2; lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; @@ -4802,8 +4802,8 @@ type3_infoblock(struct net_device *dev, lp->ibn = 3; lp->active = *p++; if (MOTO_SROM_BUG) lp->active = 0; - lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1); - lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1); + lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1); + lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1); lp->phy[lp->active].mc = TWIDDLE(p); p += 2; lp->phy[lp->active].ana = TWIDDLE(p); p += 2; lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; --- linux-2.6.8-rc1/drivers/net/tulip/eeprom.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/tulip/eeprom.c 2004-07-13 17:09:13.000000000 -0700 @@ -62,7 +62,7 @@ static struct eeprom_fixup eeprom_fixups */ { 0x1e00, 0x0000, 0x000b, 0x8f01, 0x0103, 0x0300, 0x0821, 0x000, 0x0001, 0x0000, 0x01e1 } }, - {0, 0, 0, 0, {}}}; + {NULL}}; static const char *block_name[] __devinitdata = { @@ -136,7 +136,7 @@ void __devinit tulip_parse_eeprom(struct unsigned char *ee_data = tp->eeprom; int i; - tp->mtable = 0; + tp->mtable = NULL; /* Detect an old-style (SA only) EEPROM layout: memcmp(eedata, eedata+16, 8). */ for (i = 0; i < 8; i ++) --- linux-2.6.8-rc1/drivers/net/tulip/tulip_core.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/tulip/tulip_core.c 2004-07-13 17:09:28.000000000 -0700 @@ -1535,7 +1535,7 @@ static int __devinit tulip_init_one (str } } /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02) && dev->dev_addr[1] == 0x00) for (i = 0; i < 6; i+=2) { char tmp = dev->dev_addr[i]; --- linux-2.6.8-rc1/drivers/net/tulip/winbond-840.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/tulip/winbond-840.c 2004-07-13 17:09:13.000000000 -0700 @@ -251,7 +251,7 @@ static struct pci_id_info pci_id_tbl[] = W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, - {0,}, /* 0 terminated list. */ + {NULL,}, /* 0 terminated list. */ }; /* This driver was written to use PCI memory space, however some x86 systems @@ -851,7 +851,7 @@ static void init_rxtx_rings(struct net_d for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].length = np->rx_buf_sz; np->rx_ring[i].status = 0; - np->rx_skbuff[i] = 0; + np->rx_skbuff[i] = NULL; } /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].length |= DescEndRing; @@ -875,7 +875,7 @@ static void init_rxtx_rings(struct net_d /* Initialize the Tx descriptors */ for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = 0; + np->tx_skbuff[i] = NULL; np->tx_ring[i].status = 0; } np->tx_full = 0; @@ -900,7 +900,7 @@ static void free_rxtx_rings(struct netde PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } - np->rx_skbuff[i] = 0; + np->rx_skbuff[i] = NULL; } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) { @@ -910,7 +910,7 @@ static void free_rxtx_rings(struct netde PCI_DMA_TODEVICE); dev_kfree_skb(np->tx_skbuff[i]); } - np->tx_skbuff[i] = 0; + np->tx_skbuff[i] = NULL; } } @@ -1145,7 +1145,7 @@ static void netdev_tx_done(struct net_de PCI_DMA_TODEVICE); np->tx_q_bytes -= np->tx_skbuff[entry]->len; dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = 0; + np->tx_skbuff[entry] = NULL; } if (np->tx_full && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN_RESTART && --- linux-2.6.8-rc1/drivers/net/via-rhine.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/via-rhine.c 2004-07-13 17:09:23.000000000 -0700 @@ -125,11 +125,16 @@ LK1.1.19 (Roger Luethi) - Increase Tx threshold for unspecified errors + LK1.2.0-2.6 (Roger Luethi) + - Massive clean-up + - Rewrite PHY, media handling (remove options, full_duplex, backoff) + - Fix Tx engine race for good + */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.20-2.6" -#define DRV_RELDATE "May-23-2004" +#define DRV_VERSION "1.2.0-2.6" +#define DRV_RELDATE "June-10-2004" /* A few user-configurable values. @@ -142,22 +147,10 @@ static int max_interrupt_work = 20; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; -/* Select a backoff algorithm (Ethernet capture effect) */ -static int backoff; - -/* Used to pass the media type, etc. - Both 'options[]' and 'full_duplex[]' should exist for driver - interoperability. - The media type is usually passed in 'options[]'. - The default is autonegotiation for speed and duplex. - This should rarely be overridden. - Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps. - Use option values 0x10 and 0x100 for forcing half duplex fixed speed. - Use option values 0x20 and 0x200 for forcing full duplex operation. -*/ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* + * In case you are looking for 'options[]' or 'full_duplex[]', they + * are gone. Use ethtool(8) instead. + */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Rhine has a 64 element 8390-like hash table. */ @@ -210,9 +203,6 @@ static const int multicast_filter_limit static char version[] __devinitdata = KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"; -static char shortname[] = DRV_NAME; - - /* This driver was written to use PCI memory space. Some early versions of the Rhine may only work correctly with I/O space accesses. */ #ifdef CONFIG_VIA_RHINE_MMIO @@ -239,15 +229,9 @@ MODULE_LICENSE("GPL"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(backoff, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(backoff, "VIA Rhine: Bits 0-3: backoff algorithm"); -MODULE_PARM_DESC(options, "VIA Rhine: Bits 0-3: media type, bit 17: full duplex"); -MODULE_PARM_DESC(full_duplex, "VIA Rhine full duplex setting(s) (1)"); /* Theory of Operation @@ -350,24 +334,24 @@ The chip does not pad to minimum transmi enum rhine_revs { VT86C100A = 0x00, + VTunknown0 = 0x20, VT6102 = 0x40, VT8231 = 0x50, /* Integrated MAC */ VT8233 = 0x60, /* Integrated MAC */ VT8235 = 0x74, /* Integrated MAC */ VT8237 = 0x78, /* Integrated MAC */ - VTunknown0 = 0x7C, + VTunknown1 = 0x7C, VT6105 = 0x80, VT6105_B0 = 0x83, VT6105L = 0x8A, VT6107 = 0x8C, - VTunknown1 = 0x8E, + VTunknown2 = 0x8E, VT6105M = 0x90, }; enum rhine_quirks { rqWOL = 0x0001, /* Wake-On-LAN support */ rqForceReset = 0x0002, - rqDavicomPhy = 0x0020, rq6patterns = 0x0040, /* 6 instead of 4 patterns for WOL */ rqStatusWBRace = 0x0080, /* Tx Status Writeback Error possible */ rqRhineI = 0x0100, /* See comment below */ @@ -395,6 +379,7 @@ MODULE_DEVICE_TABLE(pci, rhine_pci_tbl); /* Offsets to the device registers. */ enum register_offsets { StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, + ChipCmd1=0x09, IntrStatus=0x0C, IntrEnable=0x0E, MulticastFilter0=0x10, MulticastFilter1=0x14, RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, @@ -403,8 +388,8 @@ enum register_offsets { ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, StickyHW=0x83, IntrStatus2=0x84, - WOLcrSet=0xA0, WOLcrClr=0xA4, WOLcrClr1=0xA6, - WOLcgClr=0xA7, + WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4, + WOLcrClr1=0xA6, WOLcgClr=0xA7, PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD, }; @@ -436,6 +421,15 @@ enum intr_status_bits { IntrTxErrSummary=0x082218, }; +/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */ +enum wol_bits { + WOLucast = 0x10, + WOLmagic = 0x20, + WOLbmcast = 0x30, + WOLlnkon = 0x40, + WOLlnkoff = 0x80, +}; + /* The Rx and Tx buffer descriptors. */ struct rx_desc { s32 rx_status; @@ -464,13 +458,12 @@ enum desc_status_bits { /* Bits in ChipCmd. */ enum chip_cmd_bits { - CmdInit=0x0001, CmdStart=0x0002, CmdStop=0x0004, CmdRxOn=0x0008, - CmdTxOn=0x0010, CmdTxDemand=0x0020, CmdRxDemand=0x0040, - CmdEarlyRx=0x0100, CmdEarlyTx=0x0200, CmdFDuplex=0x0400, - CmdNoTxPoll=0x0800, CmdReset=0x8000, + CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08, + CmdTxOn=0x10, Cmd1TxDemand=0x20, CmdRxDemand=0x40, + Cmd1EarlyRx=0x01, Cmd1EarlyTx=0x02, Cmd1FDuplex=0x04, + Cmd1NoTxPoll=0x08, Cmd1Reset=0x80, }; -#define MAX_MII_CNT 4 struct rhine_private { /* Descriptor rings */ struct rx_desc *rx_ring; @@ -493,7 +486,6 @@ struct rhine_private { struct pci_dev *pdev; struct net_device_stats stats; - struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ @@ -502,23 +494,16 @@ struct rhine_private { unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ - u16 chip_cmd; /* Current setting for ChipCmd */ + u8 wolopts; - /* These values are keep track of the transceiver/media in use. */ u8 tx_thresh, rx_thresh; - /* MII transceiver section. */ - unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ - unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ - u16 mii_status; /* last read MII status */ struct mii_if_info mii_if; }; static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); -static void rhine_check_duplex(struct net_device *dev); -static void rhine_timer(unsigned long data); static void rhine_tx_timeout(struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); @@ -530,6 +515,16 @@ static struct net_device_stats *rhine_ge static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); +static void rhine_shutdown (struct device *gdev); + +#define RHINE_WAIT_FOR(condition) do { \ + int i=1024; \ + while (!(condition) && --i) \ + ; \ + if (debug > 1 && i < 512) \ + printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \ + DRV_NAME, 1024-i, __func__, __LINE__); \ +} while(0) static inline u32 get_intr_status(struct net_device *dev) { @@ -546,12 +541,13 @@ static inline u32 get_intr_status(struct /* * Get power related registers into sane state. - * Returns content of power-event (WOL) registers. + * Notify user about past WOL event. */ static void rhine_power_init(struct net_device *dev) { long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); + u16 wolstat; if (rp->quirks & rqWOL) { /* Make sure chip is in power state D0 */ @@ -566,63 +562,109 @@ static void rhine_power_init(struct net_ if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + WOLcrClr1); + /* Save power-event status bits */ + wolstat = readb(ioaddr + PwrcsrSet); + if (rp->quirks & rq6patterns) + wolstat |= (readb(ioaddr + PwrcsrSet1) & 0x03) << 8; + /* Clear power-event status bits */ writeb(0xFF, ioaddr + PwrcsrClr); if (rp->quirks & rq6patterns) writeb(0x03, ioaddr + PwrcsrClr1); + + if (wolstat) { + char *reason; + switch (wolstat) { + case WOLmagic: + reason = "Magic packet"; + break; + case WOLlnkon: + reason = "Link went up"; + break; + case WOLlnkoff: + reason = "Link went down"; + break; + case WOLucast: + reason = "Unicast packet"; + break; + case WOLbmcast: + reason = "Multicast/broadcast packet"; + break; + default: + reason = "Unknown"; + } + printk("%s: Woke system up. Reason: %s.\n", + DRV_NAME, reason); + } } } -static void wait_for_reset(struct net_device *dev, u32 quirks, char *name) +static void rhine_chip_reset(struct net_device *dev) { long ioaddr = dev->base_addr; - int boguscnt = 20; + struct rhine_private *rp = netdev_priv(dev); + writeb(Cmd1Reset, ioaddr + ChipCmd1); IOSYNC; - if (readw(ioaddr + ChipCmd) & CmdReset) { + if (readb(ioaddr + ChipCmd1) & Cmd1Reset) { printk(KERN_INFO "%s: Reset not complete yet. " - "Trying harder.\n", name); + "Trying harder.\n", DRV_NAME); - /* Rhine-II needs to be forced sometimes */ - if (quirks & rqForceReset) + /* Force reset */ + if (rp->quirks & rqForceReset) writeb(0x40, ioaddr + MiscCmd); - /* VT86C100A may need long delay after reset (dlink) */ - /* Seen on Rhine-II as well (rl) */ - while ((readw(ioaddr + ChipCmd) & CmdReset) && --boguscnt) - udelay(5); - + /* Reset can take somewhat longer (rare) */ + RHINE_WAIT_FOR(!(readb(ioaddr + ChipCmd1) & Cmd1Reset)); } if (debug > 1) - printk(KERN_INFO "%s: Reset %s.\n", name, - boguscnt ? "succeeded" : "failed"); + printk(KERN_INFO "%s: Reset %s.\n", dev->name, + (readb(ioaddr + ChipCmd1) & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO -static void __devinit enable_mmio(long ioaddr, u32 quirks) +static void __devinit enable_mmio(long pioaddr, u32 quirks) { int n; if (quirks & rqRhineI) { /* More recent docs say that this bit is reserved ... */ - n = inb(ioaddr + ConfigA) | 0x20; - outb(n, ioaddr + ConfigA); + n = inb(pioaddr + ConfigA) | 0x20; + outb(n, pioaddr + ConfigA); } else { - n = inb(ioaddr + ConfigD) | 0x80; - outb(n, ioaddr + ConfigD); + n = inb(pioaddr + ConfigD) | 0x80; + outb(n, pioaddr + ConfigD); } } #endif -static void __devinit reload_eeprom(long ioaddr) +/* + * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM + * (plus 0x6C for Rhine-I/II) + */ +static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) { - int i; - outb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) - break; + long ioaddr = dev->base_addr; + struct rhine_private *rp = netdev_priv(dev); + + outb(0x20, pioaddr + MACRegEEcsr); + RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20)); + +#ifdef USE_MMIO + /* + * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable + * MMIO. If reloading EEPROM was done first this could be avoided, but + * it is not known if that still works with the "win98-reboot" problem. + */ + enable_mmio(pioaddr, rp->quirks); +#endif + + /* Turn off EEPROM-controlled wake-up (magic packet) */ + if (rp->quirks & rqWOL) + writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); + } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -634,23 +676,34 @@ static void rhine_poll(struct net_device } #endif +static void rhine_hw_init(struct net_device *dev, long pioaddr) +{ + struct rhine_private *rp = netdev_priv(dev); + + /* Reset the chip to erase previous misconfiguration. */ + rhine_chip_reset(dev); + + /* Rhine-I needs extra time to recuperate before EEPROM reload */ + if (rp->quirks & rqRhineI) + msleep(5); + + /* Reload EEPROM controlled bytes cleared by soft reset */ + rhine_reload_eeprom(pioaddr, dev); +} + static int __devinit rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct rhine_private *rp; - int i, option, rc; + int i, rc; u8 pci_rev; u32 quirks; - static int card_idx = -1; - long ioaddr; + long pioaddr; long memaddr; - int io_size; - int phy, phy_idx = 0; -#ifdef USE_MMIO - long ioaddr0; -#endif - const char *name; + long ioaddr; + int io_size, phy_id; + const char *name, *mname; /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -659,26 +712,47 @@ static int __devinit rhine_init_one(stru printk(version); #endif - card_idx++; - option = card_idx < MAX_UNITS ? options[card_idx] : 0; pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev); io_size = 256; - if (pci_rev < VT6102) { - quirks = rqRhineI | rqDavicomPhy; + phy_id = 0; + quirks = 0; + name = "Rhine"; + mname = "unknown"; + if (pci_rev < VTunknown0) { + quirks = rqRhineI; io_size = 128; - name = "VT86C100A Rhine"; + mname = "VT86C100A"; } - else { + else if (pci_rev >= VT6102) { quirks = rqWOL | rqForceReset; if (pci_rev < VT6105) { name = "Rhine II"; quirks |= rqStatusWBRace; /* Rhine-II exclusive */ + if (pci_rev < VT8231) + mname = "VT6102"; + else if (pci_rev < VT8233) + mname = "VT8231"; + else if (pci_rev < VT8235) + mname = "VT8233"; + else if (pci_rev < VT8237) + mname = "VT8235"; + else if (pci_rev < VTunknown1) + mname = "VT8237"; } else { name = "Rhine III"; + phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */ if (pci_rev >= VT6105_B0) quirks |= rq6patterns; + if (pci_rev < VT6105L) + mname = "VT6105"; + else if (pci_rev < VT6107) + mname = "VT6105L"; + else if (pci_rev < VT6105M) + mname = "VT6107"; + else if (pci_rev >= VT6105M) + mname = "Management Adapter VT6105M"; } } @@ -702,28 +776,26 @@ static int __devinit rhine_init_one(stru goto err_out; } - ioaddr = pci_resource_start(pdev, 0); + pioaddr = pci_resource_start(pdev, 0); memaddr = pci_resource_start(pdev, 1); pci_set_master(pdev); - dev = alloc_etherdev(sizeof(*rp)); - if (dev == NULL) { + dev = alloc_etherdev(sizeof(struct rhine_private)); + if (!dev) { rc = -ENOMEM; - printk(KERN_ERR "init_ethernet failed for card #%d\n", - card_idx); + printk(KERN_ERR "alloc_etherdev failed\n"); goto err_out; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - rc = pci_request_regions(pdev, shortname); + rc = pci_request_regions(pdev, DRV_NAME); if (rc) goto err_out_free_netdev; #ifdef USE_MMIO - ioaddr0 = ioaddr; - enable_mmio(ioaddr0, quirks); + enable_mmio(pioaddr, quirks); ioaddr = (long) ioremap(memaddr, io_size); if (!ioaddr) { @@ -737,7 +809,7 @@ static int __devinit rhine_init_one(stru i = 0; while (mmio_verify_registers[i]) { int reg = mmio_verify_registers[i++]; - unsigned char a = inb(ioaddr0+reg); + unsigned char a = inb(pioaddr+reg); unsigned char b = readb(ioaddr+reg); if (a != b) { rc = -EIO; @@ -746,65 +818,41 @@ static int __devinit rhine_init_one(stru goto err_out_unmap; } } +#else + ioaddr = pioaddr; #endif /* USE_MMIO */ + dev->base_addr = ioaddr; + rp = netdev_priv(dev); + rp->quirks = quirks; + /* Get chip registers into a sane state */ rhine_power_init(dev); - - /* Reset the chip to erase previous misconfiguration. */ - writew(CmdReset, ioaddr + ChipCmd); - - wait_for_reset(dev, quirks, shortname); - - /* Reload the station address from the EEPROM. */ -#ifdef USE_MMIO - reload_eeprom(ioaddr0); - /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. - If reload_eeprom() was done first this could be avoided, but it is - not known if that still works with the "win98-reboot" problem. */ - enable_mmio(ioaddr0, quirks); -#else - reload_eeprom(ioaddr); -#endif + rhine_hw_init(dev, pioaddr); for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); if (!is_valid_ether_addr(dev->dev_addr)) { rc = -EIO; - printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx); + printk(KERN_ERR "Invalid MAC address\n"); goto err_out_unmap; } - if (quirks & rqWOL) { - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - writeb(readb(ioaddr + ConfigA) & 0xFE, ioaddr + ConfigA); - } - - /* Select backoff algorithm */ - if (backoff) - writeb(readb(ioaddr + ConfigD) & (0xF0 | backoff), - ioaddr + ConfigD); + /* For Rhine-I/II, phy_id is loaded from EEPROM */ + if (!phy_id) + phy_id = readb(ioaddr + 0x6C); dev->irq = pdev->irq; - rp = netdev_priv(dev); spin_lock_init(&rp->lock); rp->pdev = pdev; - rp->quirks = quirks; rp->mii_if.dev = dev; rp->mii_if.mdio_read = mdio_read; rp->mii_if.mdio_write = mdio_write; rp->mii_if.phy_id_mask = 0x1f; rp->mii_if.reg_num_mask = 0x1f; - if (dev->mem_start) - option = dev->mem_start; - /* The chip-specific entries in the device structure. */ dev->open = rhine_open; dev->hard_start_xmit = rhine_start_tx; @@ -826,22 +874,8 @@ static int __devinit rhine_init_one(stru if (rc) goto err_out_unmap; - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - } - if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) - rp->mii_if.full_duplex = 1; - - if (rp->mii_if.full_duplex) { - printk(KERN_INFO "%s: Set to forced full duplex, " - "autonegotiation disabled.\n", dev->name); - rp->mii_if.force_media = 1; - } - - printk(KERN_INFO "%s: VIA %s at 0x%lx, ", - dev->name, name, + printk(KERN_INFO "%s: VIA %s (%s) at 0x%lx, ", + dev->name, name, mname, #ifdef USE_MMIO memaddr #else @@ -855,17 +889,15 @@ static int __devinit rhine_init_one(stru pci_set_drvdata(pdev, dev); - rp->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, 1); + { + int mii_status = mdio_read(dev, phy_id, 1); if (mii_status != 0xffff && mii_status != 0x0000) { - rp->phys[phy_idx++] = phy; - rp->mii_if.advertising = mdio_read(dev, phy, 4); + rp->mii_if.advertising = mdio_read(dev, phy_id, 4); printk(KERN_INFO "%s: MII PHY found at address " "%d, status 0x%4.4x advertising %4.4x " - "Link %4.4x.\n", dev->name, phy, + "Link %4.4x.\n", dev->name, phy_id, mii_status, rp->mii_if.advertising, - mdio_read(dev, phy, 5)); + mdio_read(dev, phy_id, 5)); /* set IFF_RUNNING */ if (mii_status & BMSR_LSTATUS) @@ -873,27 +905,9 @@ static int __devinit rhine_init_one(stru else netif_carrier_off(dev); - break; - } - } - rp->mii_cnt = phy_idx; - rp->mii_if.phy_id = rp->phys[0]; - - /* Allow forcing the media type. */ - if (option > 0) { - if (option & 0x220) - rp->mii_if.full_duplex = 1; - if (option & 0x330) { - printk(KERN_INFO " Forcing %dMbs %s-duplex " - "operation.\n", - (option & 0x300 ? 100 : 10), - (option & 0x220 ? "full" : "half")); - if (rp->mii_cnt) - mdio_write(dev, rp->phys[0], MII_BMCR, - ((option & 0x300) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */ } } + rp->mii_if.phy_id = phy_id; return 0; @@ -1065,6 +1079,21 @@ static void free_tbufs(struct net_device } } +static void rhine_check_media(struct net_device *dev, unsigned int init_media) +{ + struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; + + mii_check_media(&rp->mii_if, debug, init_media); + + if (rp->mii_if.full_duplex) + writeb(readb(ioaddr + ChipCmd1) | Cmd1FDuplex, + ioaddr + ChipCmd1); + else + writeb(readb(ioaddr + ChipCmd1) & ~Cmd1FDuplex, + ioaddr + ChipCmd1); +} + static void init_registers(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1080,7 +1109,6 @@ static void init_registers(struct net_de writeb(0x20, ioaddr + TxConfig); rp->tx_thresh = 0x20; rp->rx_thresh = 0x60; /* Written in rhine_set_rx_mode(). */ - rp->mii_if.full_duplex = 0; writel(rp->rx_ring_dma, ioaddr + RxRingPtr); writel(rp->tx_ring_dma, ioaddr + TxRingPtr); @@ -1094,17 +1122,44 @@ static void init_registers(struct net_de IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - rp->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (rp->mii_if.force_media) - rp->chip_cmd |= CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); - - rhine_check_duplex(dev); - - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - mdio_write(dev, rp->phys[0], 0x17, mdio_read(dev, rp->phys[0], 0x17) | - 0x0001); + writew(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8), + ioaddr + ChipCmd); + rhine_check_media(dev, 1); +} + +/* Enable MII link status auto-polling (required for IntrLinkChange) */ +static void rhine_enable_linkmon(long ioaddr) +{ + writeb(0, ioaddr + MIICmd); + writeb(MII_BMSR, ioaddr + MIIRegAddr); + writeb(0x80, ioaddr + MIICmd); + + RHINE_WAIT_FOR((readb(ioaddr + MIIRegAddr) & 0x20)); + + writeb(MII_BMSR | 0x40, ioaddr + MIIRegAddr); +} + +/* Disable MII link status auto-polling (required for MDIO access) */ +static void rhine_disable_linkmon(long ioaddr, u32 quirks) +{ + writeb(0, ioaddr + MIICmd); + + if (quirks & rqRhineI) { + writeb(0x01, ioaddr + MIIRegAddr); // MII_BMSR + + /* Can be called from ISR. Evil. */ + mdelay(1); + + /* 0x80 must be set immediately before turning it off */ + writeb(0x80, ioaddr + MIICmd); + + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x20); + + /* Heh. Now clear 0x80 again. */ + writeb(0, ioaddr + MIICmd); + } + else + RHINE_WAIT_FOR(readb(ioaddr + MIIRegAddr) & 0x80); } /* Read and write over the MII Management Data I/O (MDIO) interface. */ @@ -1112,156 +1167,72 @@ static void init_registers(struct net_de static int mdio_read(struct net_device *dev, int phy_id, int regnum) { long ioaddr = dev->base_addr; - int boguscnt = 1024; + struct rhine_private *rp = netdev_priv(dev); + int result; - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + rhine_disable_linkmon(ioaddr, rp->quirks); + + writeb(0, ioaddr + MIICmd); writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writeb(0x40, ioaddr + MIICmd); /* Trigger read */ - boguscnt = 1024; - while ((readb(ioaddr + MIICmd) & 0x40) && --boguscnt > 0) - ; - return readw(ioaddr + MIIData); + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x40)); + result = readw(ioaddr + MIIData); + + rhine_enable_linkmon(ioaddr); + return result; } static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int boguscnt = 1024; - if (phy_id == rp->phys[0]) { - switch (regnum) { - case MII_BMCR: /* Is user forcing speed/duplex? */ - if (value & 0x9000) /* Autonegotiation. */ - rp->mii_if.force_media = 0; - else - rp->mii_if.full_duplex = (value & 0x0100) ? 1 : 0; - break; - case MII_ADVERTISE: - rp->mii_if.advertising = value; - break; - } - } + rhine_disable_linkmon(ioaddr, rp->quirks); - /* Wait for a previous command to complete. */ - while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0) - ; - writeb(0x00, ioaddr + MIICmd); + writeb(0, ioaddr + MIICmd); writeb(phy_id, ioaddr + MIIPhyAddr); writeb(regnum, ioaddr + MIIRegAddr); writew(value, ioaddr + MIIData); - writeb(0x20, ioaddr + MIICmd); /* Trigger write. */ -} + writeb(0x20, ioaddr + MIICmd); /* Trigger write */ + RHINE_WAIT_FOR(!(readb(ioaddr + MIICmd) & 0x20)); + rhine_enable_linkmon(ioaddr); +} static int rhine_open(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); long ioaddr = dev->base_addr; - int i; - - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); + int rc; - i = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, + rc = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name, dev); - if (i) - return i; + if (rc) + return rc; if (debug > 1) printk(KERN_DEBUG "%s: rhine_open() irq %d.\n", dev->name, rp->pdev->irq); - i = alloc_ring(dev); - if (i) - return i; + rc = alloc_ring(dev); + if (rc) + return rc; alloc_rbufs(dev); alloc_tbufs(dev); - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); - /* Set the timer to check for link beat. */ - init_timer(&rp->timer); - rp->timer.expires = jiffies + 2 * HZ/100; - rp->timer.data = (unsigned long)dev; - rp->timer.function = &rhine_timer; /* timer handler */ - add_timer(&rp->timer); - return 0; } -static void rhine_check_duplex(struct net_device *dev) -{ - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int mii_lpa = mdio_read(dev, rp->phys[0], MII_LPA); - int negotiated = mii_lpa & rp->mii_if.advertising; - int duplex; - - if (rp->mii_if.force_media || mii_lpa == 0xffff) - return; - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (rp->mii_if.full_duplex != duplex) { - rp->mii_if.full_duplex = duplex; - if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on " - "MII #%d link partner capability of %4.4x.\n", - dev->name, duplex ? "full" : "half", - rp->phys[0], mii_lpa); - if (duplex) - rp->chip_cmd |= CmdFDuplex; - else - rp->chip_cmd &= ~CmdFDuplex; - writew(rp->chip_cmd, ioaddr + ChipCmd); - } -} - - -static void rhine_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rhine_private *rp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int next_tick = 10*HZ; - int mii_status; - - if (debug > 3) { - printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", - dev->name, readw(ioaddr + IntrStatus)); - } - - spin_lock_irq (&rp->lock); - - rhine_check_duplex(dev); - - /* make IFF_RUNNING follow the MII status bit "Link established" */ - mii_status = mdio_read(dev, rp->phys[0], MII_BMSR); - if ((mii_status & BMSR_LSTATUS) != (rp->mii_status & BMSR_LSTATUS)) { - if (mii_status & BMSR_LSTATUS) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - } - rp->mii_status = mii_status; - - spin_unlock_irq(&rp->lock); - - rp->timer.expires = jiffies + next_tick; - add_timer(&rp->timer); -} - - static void rhine_tx_timeout(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); @@ -1270,16 +1241,13 @@ static void rhine_tx_timeout(struct net_ printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " "%4.4x, resetting...\n", dev->name, readw(ioaddr + IntrStatus), - mdio_read(dev, rp->phys[0], MII_BMSR)); + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); /* protect against concurrent rx interrupts */ disable_irq(rp->pdev->irq); spin_lock(&rp->lock); - /* Reset the chip. */ - writew(CmdReset, ioaddr + ChipCmd); - /* clear all descriptors */ free_tbufs(dev); free_rbufs(dev); @@ -1287,7 +1255,7 @@ static void rhine_tx_timeout(struct net_ alloc_rbufs(dev); /* Reinitialize the hardware. */ - wait_for_reset(dev, rp->quirks, dev->name); + rhine_chip_reset(dev); init_registers(dev); spin_unlock(&rp->lock); @@ -1301,8 +1269,8 @@ static void rhine_tx_timeout(struct net_ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); + long ioaddr = dev->base_addr; unsigned entry; - u32 intr_status; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -1353,14 +1321,9 @@ static int rhine_start_tx(struct sk_buff /* Non-x86 Todo: explicitly flush cache lines here. */ - /* - * Wake the potentially-idle transmit channel unless errors are - * pending (the ISR must sort them out first). - */ - intr_status = get_intr_status(dev); - if ((intr_status & IntrTxErrSummary) == 0) { - writew(CmdTxDemand | rp->chip_cmd, dev->base_addr + ChipCmd); - } + /* Wake the potentially-idle transmit channel */ + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN) @@ -1408,11 +1371,10 @@ static irqreturn_t rhine_interrupt(int i if (intr_status & (IntrTxErrSummary | IntrTxDone)) { if (intr_status & IntrTxErrSummary) { - int cnt = 20; /* Avoid scavenging before Tx engine turned off */ - while ((readw(ioaddr+ChipCmd) & CmdTxOn) && --cnt) - udelay(5); - if (debug > 2 && !cnt) + RHINE_WAIT_FOR(!(readb(ioaddr+ChipCmd) & CmdTxOn)); + if (debug > 2 && + readb(ioaddr+ChipCmd) & CmdTxOn) printk(KERN_WARNING "%s: " "rhine_interrupt() Tx engine" "still on.\n", dev->name); @@ -1572,10 +1534,6 @@ static void rhine_rx(struct net_device * rp->rx_buf_sz, PCI_DMA_FROMDEVICE); - /* *_IP_COPYSUM isn't defined anywhere and - eth_copy_and_sum is memcpy for all archs so - this is kind of pointless right now - ... or? */ eth_copy_and_sum(skb, rp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1627,10 +1585,6 @@ static void rhine_rx(struct net_device * } rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } - - /* Pre-emptively restart Rx engine. */ - writew(readw(dev->base_addr + ChipCmd) | CmdRxOn | CmdRxDemand, - dev->base_addr + ChipCmd); } /* @@ -1664,7 +1618,10 @@ static void rhine_restart_tx(struct net_ writel(rp->tx_ring_dma + entry * sizeof(struct tx_desc), ioaddr + TxRingPtr); - writew(CmdTxDemand | rp->chip_cmd, ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd) | CmdTxOn, + ioaddr + ChipCmd); + writeb(readb(ioaddr + ChipCmd1) | Cmd1TxDemand, + ioaddr + ChipCmd1); IOSYNC; } else { @@ -1684,20 +1641,8 @@ static void rhine_error(struct net_devic spin_lock(&rp->lock); - if (intr_status & (IntrLinkChange)) { - if (readb(ioaddr + MIIStatus) & 0x02) { - /* Link failed, restart autonegotiation. */ - if (rp->quirks & rqRhineI) - mdio_write(dev, rp->phys[0], MII_BMCR, 0x3300); - } else - rhine_check_duplex(dev); - if (debug) - printk(KERN_ERR "%s: MII status changed: " - "Autonegotiation advertising %4.4x partner " - "%4.4x.\n", dev->name, - mdio_read(dev, rp->phys[0], MII_ADVERTISE), - mdio_read(dev, rp->phys[0], MII_LPA)); - } + if (intr_status & IntrLinkChange) + rhine_check_media(dev, 0); if (intr_status & IntrStatsMax) { rp->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs); rp->stats.rx_missed_errors += readw(ioaddr + RxMissed); @@ -1790,7 +1735,7 @@ static void rhine_set_rx_mode(struct net i++, mclist = mclist->next) { int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31)); + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); @@ -1856,6 +1801,39 @@ static void netdev_set_msglevel(struct n debug = value; } +static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + + if (!(rp->quirks & rqWOL)) + return; + + spin_lock_irq(&rp->lock); + wol->supported = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + wol->wolopts = rp->wolopts; + spin_unlock_irq(&rp->lock); +} + +static int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct rhine_private *rp = netdev_priv(dev); + u32 support = WAKE_PHY | WAKE_MAGIC | + WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ + + if (!(rp->quirks & rqWOL)) + return -EINVAL; + + if (wol->wolopts & ~support) + return -EINVAL; + + spin_lock_irq(&rp->lock); + rp->wolopts = wol->wolopts; + spin_unlock_irq(&rp->lock); + + return 0; +} + static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, @@ -1864,6 +1842,8 @@ static struct ethtool_ops netdev_ethtool .get_link = netdev_get_link, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, + .get_wol = rhine_get_wol, + .set_wol = rhine_set_wol, .get_sg = ethtool_op_get_sg, .get_tx_csum = ethtool_op_get_tx_csum, }; @@ -1888,8 +1868,6 @@ static int rhine_close(struct net_device long ioaddr = dev->base_addr; struct rhine_private *rp = netdev_priv(dev); - del_timer_sync(&rp->timer); - spin_lock_irq(&rp->lock); netif_stop_queue(dev); @@ -1936,12 +1914,51 @@ static void __devexit rhine_remove_one(s pci_set_drvdata(pdev, NULL); } +static void rhine_shutdown (struct device *gendev) +{ + struct pci_dev *pdev = to_pci_dev(gendev); + struct net_device *dev = pci_get_drvdata(pdev); + struct rhine_private *rp = netdev_priv(dev); + + long ioaddr = dev->base_addr; + + rhine_power_init(dev); + + /* Make sure we use pattern 0, 1 and not 4, 5 */ + if (rp->quirks & rq6patterns) + writeb(0x04, ioaddr + 0xA7); + + if (rp->wolopts & WAKE_MAGIC) + writeb(WOLmagic, ioaddr + WOLcrSet); + + if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST)) + writeb(WOLbmcast, ioaddr + WOLcgSet); + + if (rp->wolopts & WAKE_PHY) + writeb(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet); + + if (rp->wolopts & WAKE_UCAST) + writeb(WOLucast, ioaddr + WOLcrSet); + + /* Enable legacy WOL (for old motherboards) */ + writeb(0x01, ioaddr + PwcfgSet); + writeb(readb(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW); + + /* Hit power state D3 (sleep) */ + writeb(readb(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + + /* TODO: Check use of pci_enable_wake() */ + +} static struct pci_driver rhine_driver = { - .name = "via-rhine", + .name = DRV_NAME, .id_table = rhine_pci_tbl, .probe = rhine_init_one, .remove = __devexit_p(rhine_remove_one), + .driver = { + .shutdown = rhine_shutdown, + } }; --- linux-2.6.8-rc1/drivers/net/via-velocity.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/via-velocity.c 2004-07-13 17:09:51.000000000 -0700 @@ -78,6 +78,8 @@ #include #include #include +#include +#include #include "via-velocity.h" @@ -226,7 +228,10 @@ VELOCITY_PARAM(wol_opts, "Wake On Lan op VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); -static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent); +static int rx_copybreak = 200; +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); + static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info); static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev); static void velocity_print_info(struct velocity_info *vptr); @@ -238,10 +243,8 @@ static void velocity_set_multi(struct ne static struct net_device_stats *velocity_get_stats(struct net_device *dev); static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int velocity_close(struct net_device *dev); -static int velocity_rx_srv(struct velocity_info *vptr, int status); static int velocity_receive_frame(struct velocity_info *, int idx); static int velocity_alloc_rx_buf(struct velocity_info *, int idx); -static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type); static void velocity_free_rd_ring(struct velocity_info *vptr); static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *); static int velocity_soft_reset(struct velocity_info *vptr); @@ -254,12 +257,8 @@ static void enable_flow_control_ability( static void enable_mii_autopoll(struct mac_regs * regs); static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); -static int velocity_set_wol(struct velocity_info *vptr); -static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context); -static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context); static u32 mii_check_media_mode(struct mac_regs * regs); static u32 check_connection_type(struct mac_regs * regs); -static void velocity_init_cam_filter(struct velocity_info *vptr); static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status); #ifdef CONFIG_PM @@ -269,8 +268,9 @@ static int velocity_resume(struct pci_de static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr); static struct notifier_block velocity_inetaddr_notifier = { - notifier_call:velocity_netdev_event, + .notifier_call = velocity_netdev_event, }; +static int velocity_notifier_registered; #endif /* CONFIG_PM */ @@ -289,8 +289,9 @@ static struct velocity_info_tbl chip_inf */ static struct pci_device_id velocity_id_table[] __devinitdata = { - {0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]}, - {0,} + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table}, + {0, } }; MODULE_DEVICE_TABLE(pci, velocity_id_table); @@ -463,6 +464,12 @@ static void velocity_init_cam_filter(str } } +static inline void velocity_give_rx_desc(struct rx_desc *rd) +{ + *(u32 *)&rd->rdesc0 = 0; + rd->rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); +} + /** * velocity_rx_reset - handle a receive reset * @vptr: velocity we are resetting @@ -477,13 +484,13 @@ static void velocity_rx_reset(struct vel struct mac_regs * regs = vptr->mac_regs; int i; - vptr->rd_used = vptr->rd_curr = 0; + vptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0; /* * Init state, all RD entries belong to the NIC */ for (i = 0; i < vptr->options.numrx; ++i) - vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC); + velocity_give_rx_desc(vptr->rd_ring + i); writew(vptr->options.numrx, ®s->RBRDU); writel(vptr->rd_pool_dma, ®s->RDBaseLo); @@ -776,6 +783,12 @@ static int __devinit velocity_found1(str pci_set_power_state(pdev, 3); out: +#ifdef CONFIG_PM + if (ret == 0 && !velocity_notifier_registered) { + velocity_notifier_registered = 1; + register_inetaddr_notifier(&velocity_inetaddr_notifier); + } +#endif return ret; err_iounmap: @@ -966,6 +979,60 @@ static void velocity_free_rings(struct v pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma); } +static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) +{ + struct mac_regs *regs = vptr->mac_regs; + int avail, dirty, unusable; + + /* + * RD number must be equal to 4X per hardware spec + * (programming guide rev 1.20, p.13) + */ + if (vptr->rd_filled < 4) + return; + + wmb(); + + unusable = vptr->rd_filled | 0x0003; + dirty = vptr->rd_dirty - unusable + 1; + for (avail = vptr->rd_filled & 0xfffc; avail; avail--) { + dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; + velocity_give_rx_desc(vptr->rd_ring + dirty); + } + + writew(vptr->rd_filled & 0xfffc, ®s->RBRDU); + vptr->rd_filled = unusable; +} + +static int velocity_rx_refill(struct velocity_info *vptr) +{ + int dirty = vptr->rd_dirty, done = 0, ret = 0; + + do { + struct rx_desc *rd = vptr->rd_ring + dirty; + + /* Fine for an all zero Rx desc at init time as well */ + if (rd->rdesc0.owner == cpu_to_le32(OWNED_BY_NIC)) + break; + + if (!vptr->rd_info[dirty].skb) { + ret = velocity_alloc_rx_buf(vptr, dirty); + if (ret < 0) + break; + } + done++; + dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; + } while (dirty != vptr->rd_curr); + + if (done) { + vptr->rd_dirty = dirty; + vptr->rd_filled += done; + velocity_give_many_rx_descs(vptr); + } + + return ret; +} + /** * velocity_init_rd_ring - set up receive ring * @vptr: velocity to configure @@ -976,9 +1043,7 @@ static void velocity_free_rings(struct v static int velocity_init_rd_ring(struct velocity_info *vptr) { - int i, ret = -ENOMEM; - struct rx_desc *rd; - struct velocity_rd_info *rd_info; + int ret = -ENOMEM; unsigned int rsize = sizeof(struct velocity_rd_info) * vptr->options.numrx; @@ -987,22 +1052,14 @@ static int velocity_init_rd_ring(struct goto out; memset(vptr->rd_info, 0, rsize); - /* Init the RD ring entries */ - for (i = 0; i < vptr->options.numrx; i++) { - rd = &(vptr->rd_ring[i]); - rd_info = &(vptr->rd_info[i]); + vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0; - ret = velocity_alloc_rx_buf(vptr, i); - if (ret < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR - "%s: failed to allocate RX buffer.\n", - vptr->dev->name); - velocity_free_rd_ring(vptr); - goto out; - } - rd->rdesc0.owner = OWNED_BY_NIC; + ret = velocity_rx_refill(vptr); + if (ret < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: failed to allocate RX buffer.\n", vptr->dev->name); + velocity_free_rd_ring(vptr); } - vptr->rd_used = vptr->rd_curr = 0; out: return ret; } @@ -1025,7 +1082,7 @@ static void velocity_free_rd_ring(struct for (i = 0; i < vptr->options.numrx; i++) { struct velocity_rd_info *rd_info = &(vptr->rd_info[i]); - if (!rd_info->skb_dma) + if (!rd_info->skb) continue; pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1146,22 +1203,14 @@ static void velocity_free_td_ring(struct static int velocity_rx_srv(struct velocity_info *vptr, int status) { - struct rx_desc *rd; struct net_device_stats *stats = &vptr->stats; - struct mac_regs * regs = vptr->mac_regs; int rd_curr = vptr->rd_curr; int works = 0; while (1) { + struct rx_desc *rd = vptr->rd_ring + rd_curr; - rd = &(vptr->rd_ring[rd_curr]); - - if ((vptr->rd_info[rd_curr]).skb == NULL) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) - break; - } - - if (works++ > 15) + if (!vptr->rd_info[rd_curr].skb || (works++ > 15)) break; if (rd->rdesc0.owner == OWNED_BY_NIC) @@ -1169,17 +1218,10 @@ static int velocity_rx_srv(struct veloci /* * Don't drop CE or RL error frame although RXOK is off - * FIXME: need to handle copybreak */ if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { - if (velocity_receive_frame(vptr, rd_curr) == 0) { - if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) { - VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name); - break; - } - } else { + if (velocity_receive_frame(vptr, rd_curr) < 0) stats->rx_dropped++; - } } else { if (rd->rdesc0.RSR & RSR_CRC) stats->rx_crc_errors++; @@ -1191,25 +1233,18 @@ static int velocity_rx_srv(struct veloci rd->inten = 1; - if (++vptr->rd_used >= 4) { - int i, rd_prev = rd_curr; - for (i = 0; i < 4; i++) { - if (--rd_prev < 0) - rd_prev = vptr->options.numrx - 1; - - rd = &(vptr->rd_ring[rd_prev]); - rd->rdesc0.owner = OWNED_BY_NIC; - } - writew(4, &(regs->RBRDU)); - vptr->rd_used -= 4; - } - vptr->dev->last_rx = jiffies; rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; } + + if (velocity_rx_refill(vptr) < 0) { + VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s: rx buf allocation failure\n", vptr->dev->name); + } + vptr->rd_curr = rd_curr; VAR_USED(stats); return works; @@ -1242,6 +1277,65 @@ static inline void velocity_rx_csum(stru } /** + * velocity_rx_copy - in place Rx copy for small packets + * @rx_skb: network layer packet buffer candidate + * @pkt_size: received data size + * @rd: receive packet descriptor + * @dev: network device + * + * Replace the current skb that is scheduled for Rx processing by a + * shorter, immediatly allocated skb, if the received packet is small + * enough. This function returns a negative value if the received + * packet is too big or if memory is exhausted. + */ +static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, + struct velocity_info *vptr) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *new_skb; + + new_skb = dev_alloc_skb(pkt_size + 2); + if (new_skb) { + new_skb->dev = vptr->dev; + new_skb->ip_summed = rx_skb[0]->ip_summed; + + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) + skb_reserve(new_skb, 2); + + memcpy(new_skb->data, rx_skb[0]->tail, pkt_size); + *rx_skb = new_skb; + ret = 0; + } + + } + return ret; +} + +/** + * velocity_iph_realign - IP header alignment + * @vptr: velocity we are handling + * @skb: network layer packet buffer + * @pkt_size: received data size + * + * Align IP header on a 2 bytes boundary. This behavior can be + * configured by the user. + */ +static inline void velocity_iph_realign(struct velocity_info *vptr, + struct sk_buff *skb, int pkt_size) +{ + /* FIXME - memmove ? */ + if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { + int i; + + for (i = pkt_size; i >= 0; i--) + *(skb->data + i + 2) = *(skb->data + i); + skb_reserve(skb, 2); + } +} + +/** * velocity_receive_frame - received packet processor * @vptr: velocity we are handling * @idx: ring index @@ -1252,9 +1346,11 @@ static inline void velocity_rx_csum(stru static int velocity_receive_frame(struct velocity_info *vptr, int idx) { + void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int); struct net_device_stats *stats = &vptr->stats; struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]); struct rx_desc *rd = &(vptr->rd_ring[idx]); + int pkt_len = rd->rdesc0.len; struct sk_buff *skb; if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) { @@ -1269,22 +1365,8 @@ static int velocity_receive_frame(struct skb = rd_info->skb; skb->dev = vptr->dev; - pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, - PCI_DMA_FROMDEVICE); - rd_info->skb_dma = (dma_addr_t) NULL; - rd_info->skb = NULL; - - /* FIXME - memmove ? */ - if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) { - int i; - for (i = rd->rdesc0.len + 4; i >= 0; i--) - *(skb->data + i + 2) = *(skb->data + i); - skb->data += 2; - skb->tail += 2; - } - - skb_put(skb, (rd->rdesc0.len - 4)); - skb->protocol = eth_type_trans(skb, skb->dev); + pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma, + vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Drop frame not meeting IEEE 802.3 @@ -1297,13 +1379,23 @@ static int velocity_receive_frame(struct } } + pci_action = pci_dma_sync_single_for_device; + velocity_rx_csum(rd, skb); - - /* - * FIXME: need rx_copybreak handling - */ - stats->rx_bytes += skb->len; + if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) { + velocity_iph_realign(vptr, skb, pkt_len); + pci_action = pci_unmap_single; + rd_info->skb = NULL; + } + + pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + skb_put(skb, pkt_len - 4); + skb->protocol = eth_type_trans(skb, skb->dev); + + stats->rx_bytes += pkt_len; netif_rx(skb); return 0; @@ -1963,32 +2055,6 @@ static int velocity_intr(int irq, void * /** - * ether_crc - ethernet CRC function - * - * Compute an ethernet CRC hash of the data block provided. This - * is not performance optimised but is not needed in performance - * critical code paths. - * - * FIXME: could we use shared code here ? - */ - -static inline u32 ether_crc(int length, unsigned char *data) -{ - static unsigned const ethernet_polynomial = 0x04c11db7U; - - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) { - crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - } - return crc; -} - -/** * velocity_set_multi - filter list change callback * @dev: network device * @@ -2123,13 +2189,13 @@ static int velocity_ioctl(struct net_dev */ static struct pci_driver velocity_driver = { - name:VELOCITY_NAME, - id_table:velocity_id_table, - probe:velocity_found1, - remove:velocity_remove1, + .name = VELOCITY_NAME, + .id_table = velocity_id_table, + .probe = velocity_found1, + .remove = __devexit_p(velocity_remove1), #ifdef CONFIG_PM - suspend:velocity_suspend, - resume:velocity_resume, + .suspend = velocity_suspend, + .resume = velocity_resume, #endif }; @@ -2147,9 +2213,6 @@ static int __init velocity_init_module(v int ret; ret = pci_module_init(&velocity_driver); -#ifdef CONFIG_PM - register_inetaddr_notifier(&velocity_inetaddr_notifier); -#endif return ret; } @@ -2165,7 +2228,10 @@ static int __init velocity_init_module(v static void __exit velocity_cleanup_module(void) { #ifdef CONFIG_PM - unregister_inetaddr_notifier(&velocity_inetaddr_notifier); + if (velocity_notifier_registered) { + unregister_inetaddr_notifier(&velocity_inetaddr_notifier); + velocity_notifier_registered = 0; + } #endif pci_unregister_driver(&velocity_driver); } @@ -2992,172 +3058,6 @@ static void velocity_restore_context(str } -static int velocity_suspend(struct pci_dev *pdev, u32 state) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - - if(!netif_running(vptr->dev)) - return 0; - - netif_device_detach(vptr->dev); - - spin_lock_irqsave(&vptr->lock, flags); - pci_save_state(pdev, vptr->pci_state); -#ifdef ETHTOOL_GWOL - if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { - velocity_get_ip(vptr); - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - velocity_set_wol(vptr); - pci_enable_wake(pdev, 3, 1); - pci_set_power_state(pdev, 3); - } else { - velocity_save_context(vptr, &vptr->context); - velocity_shutdown(vptr); - pci_disable_device(pdev); - pci_set_power_state(pdev, state); - } -#else - pci_set_power_state(pdev, state); -#endif - spin_unlock_irqrestore(&vptr->lock, flags); - return 0; -} - -static int velocity_resume(struct pci_dev *pdev) -{ - struct velocity_info *vptr = pci_get_drvdata(pdev); - unsigned long flags; - int i; - - if(!netif_running(vptr->dev)) - return 0; - - pci_set_power_state(pdev, 0); - pci_enable_wake(pdev, 0, 0); - pci_restore_state(pdev, vptr->pci_state); - - mac_wol_reset(vptr->mac_regs); - - spin_lock_irqsave(&vptr->lock, flags); - velocity_restore_context(vptr, &vptr->context); - velocity_init_registers(vptr, VELOCITY_INIT_WOL); - mac_disable_int(vptr->mac_regs); - - velocity_tx_srv(vptr, 0); - - for (i = 0; i < vptr->num_txq; i++) { - if (vptr->td_used[i]) { - mac_tx_queue_wake(vptr->mac_regs, i); - } - } - - mac_enable_int(vptr->mac_regs); - spin_unlock_irqrestore(&vptr->lock, flags); - netif_device_attach(vptr->dev); - - return 0; -} - -static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; - struct net_device *dev; - struct velocity_info *vptr; - - if (ifa) { - dev = ifa->ifa_dev->dev; - vptr = dev->priv; - velocity_get_ip(vptr); - } - return NOTIFY_DONE; -} -#endif - -/* - * Purpose: Functions to set WOL. - */ - -const static unsigned short crc16_tab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - - -static u32 mask_pattern[2][4] = { - {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ - {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ -}; - -/** - * ether_crc16 - compute ethernet CRC - * @len: buffer length - * @cp: buffer - * @crc16: initial CRC - * - * Compute a CRC value for a block of data. - * FIXME: can we use generic functions ? - */ - -static u16 ether_crc16(int len, u8 * cp, u16 crc16) -{ - while (len--) - crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff]; - return (crc16); -} - -/** - * bit_reverse - 16bit reverse - * @data: 16bit data t reverse - * - * Reverse the order of a 16bit value and return the reversed bits - */ - -static u16 bit_reverse(u16 data) -{ - u32 new = 0x00000000; - int ii; - - - for (ii = 0; ii < 16; ii++) { - new |= ((u32) (data & 1) << (31 - ii)); - data >>= 1; - } - - return (u16) (new >> 16); -} - /** * wol_calc_crc - WOL CRC * @pattern: data pattern @@ -3166,7 +3066,7 @@ static u16 bit_reverse(u16 data) * Compute the wake on lan crc hashes for the packet header * we are interested in. */ - + u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern) { u16 crc = 0xFFFF; @@ -3186,12 +3086,12 @@ u16 wol_calc_crc(int size, u8 * pattern, continue; } mask >>= 1; - crc = ether_crc16(1, &(pattern[i * 8 + j]), crc); + crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1); } } /* Finally, invert the result once to get the correct data */ crc = ~crc; - return bit_reverse(crc); + return bitreverse(crc) >> 16; } /** @@ -3203,13 +3103,18 @@ u16 wol_calc_crc(int size, u8 * pattern, * * FIXME: check static buffer is safe here */ - + static int velocity_set_wol(struct velocity_info *vptr) { struct mac_regs * regs = vptr->mac_regs; static u8 buf[256]; int i; + static u32 mask_pattern[2][4] = { + {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */ + {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */ + }; + writew(0xFFFF, ®s->WOLCRClr); writeb(WOLCFG_SAB | WOLCFG_SAM, ®s->WOLCFGSet); writew(WOLCR_MAGIC_EN, ®s->WOLCRSet); @@ -3236,7 +3141,8 @@ static int velocity_set_wol(struct veloc memcpy(arp->ar_tip, vptr->ip_addr, 4); - crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]); + crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, + (u8 *) & mask_pattern[0][0]); writew(crc, ®s->PatternCRC[0]); writew(WOLCR_ARP_EN, ®s->WOLCRSet); @@ -3275,3 +3181,85 @@ static int velocity_set_wol(struct veloc return 0; } +static int velocity_suspend(struct pci_dev *pdev, u32 state) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + + if(!netif_running(vptr->dev)) + return 0; + + netif_device_detach(vptr->dev); + + spin_lock_irqsave(&vptr->lock, flags); + pci_save_state(pdev, vptr->pci_state); +#ifdef ETHTOOL_GWOL + if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) { + velocity_get_ip(vptr); + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + velocity_set_wol(vptr); + pci_enable_wake(pdev, 3, 1); + pci_set_power_state(pdev, 3); + } else { + velocity_save_context(vptr, &vptr->context); + velocity_shutdown(vptr); + pci_disable_device(pdev); + pci_set_power_state(pdev, state); + } +#else + pci_set_power_state(pdev, state); +#endif + spin_unlock_irqrestore(&vptr->lock, flags); + return 0; +} + +static int velocity_resume(struct pci_dev *pdev) +{ + struct velocity_info *vptr = pci_get_drvdata(pdev); + unsigned long flags; + int i; + + if(!netif_running(vptr->dev)) + return 0; + + pci_set_power_state(pdev, 0); + pci_enable_wake(pdev, 0, 0); + pci_restore_state(pdev, vptr->pci_state); + + mac_wol_reset(vptr->mac_regs); + + spin_lock_irqsave(&vptr->lock, flags); + velocity_restore_context(vptr, &vptr->context); + velocity_init_registers(vptr, VELOCITY_INIT_WOL); + mac_disable_int(vptr->mac_regs); + + velocity_tx_srv(vptr, 0); + + for (i = 0; i < vptr->num_txq; i++) { + if (vptr->td_used[i]) { + mac_tx_queue_wake(vptr->mac_regs, i); + } + } + + mac_enable_int(vptr->mac_regs); + spin_unlock_irqrestore(&vptr->lock, flags); + netif_device_attach(vptr->dev); + + return 0; +} + +static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *) ptr; + struct net_device *dev; + struct velocity_info *vptr; + + if (ifa) { + dev = ifa->ifa_dev->dev; + vptr = dev->priv; + velocity_get_ip(vptr); + } + return NOTIFY_DONE; +} +#endif --- linux-2.6.8-rc1/drivers/net/via-velocity.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/via-velocity.h 2004-07-13 17:09:23.000000000 -0700 @@ -37,7 +37,6 @@ #define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1} #define REV_ID_VT6110 (0) -#define DEVICE_ID (0x3119) #define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0) #define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0) @@ -1772,7 +1771,8 @@ struct velocity_info { struct velocity_td_info *td_infos[TX_QUEUE_NO]; int rd_curr; - int rd_used; + int rd_dirty; + u32 rd_filled; struct rx_desc *rd_ring; struct velocity_rd_info *rd_info; /* It's an array */ --- linux-2.6.8-rc1/drivers/net/wan/cosa.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wan/cosa.c 2004-07-13 17:09:13.000000000 -0700 @@ -729,7 +729,7 @@ static void cosa_sppp_timeout(struct net cosa_kick(chan->cosa); if (chan->tx_skb) { dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; + chan->tx_skb = NULL; } netif_wake_queue(dev); } @@ -745,11 +745,11 @@ static int cosa_sppp_close(struct net_de spin_lock_irqsave(&chan->cosa->lock, flags); if (chan->rx_skb) { kfree_skb(chan->rx_skb); - chan->rx_skb = 0; + chan->rx_skb = NULL; } if (chan->tx_skb) { kfree_skb(chan->tx_skb); - chan->tx_skb = 0; + chan->tx_skb = NULL; } chan->usage=0; chan->cosa->usage--; @@ -791,7 +791,7 @@ static int sppp_rx_done(struct channel_d chan->stats.rx_packets++; chan->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); - chan->rx_skb = 0; + chan->rx_skb = NULL; chan->pppdev.dev->last_rx = jiffies; return 0; } @@ -807,7 +807,7 @@ static int sppp_tx_done(struct channel_d return 1; } dev_kfree_skb_irq(chan->tx_skb); - chan->tx_skb = 0; + chan->tx_skb = NULL; chan->stats.tx_packets++; chan->stats.tx_bytes += size; netif_wake_queue(chan->pppdev.dev); --- linux-2.6.8-rc1/drivers/net/wan/lmc/lmc_main.c 2004-02-17 20:48:44.000000000 -0800 +++ 25/drivers/net/wan/lmc/lmc_main.c 2004-07-13 17:09:13.000000000 -0700 @@ -1250,7 +1250,7 @@ static int lmc_ifdown (struct net_device for (i = 0; i < LMC_RXDESCS; i++) { struct sk_buff *skb = sc->lmc_rxq[i]; - sc->lmc_rxq[i] = 0; + sc->lmc_rxq[i] = NULL; sc->lmc_rxring[i].status = 0; sc->lmc_rxring[i].length = 0; sc->lmc_rxring[i].buffer1 = 0xDEADBEEF; @@ -1394,7 +1394,7 @@ static irqreturn_t lmc_interrupt (int ir // dev_kfree_skb(sc->lmc_txq[i]); dev_kfree_skb_irq(sc->lmc_txq[i]); - sc->lmc_txq[i] = 0; + sc->lmc_txq[i] = NULL; badtx++; i = badtx % LMC_TXDESCS; @@ -1667,7 +1667,7 @@ static int lmc_rx (struct net_device *de */ give_it_anyways: - sc->lmc_rxq[i] = 0x0; + sc->lmc_rxq[i] = NULL; sc->lmc_rxring[i].buffer1 = 0x0; skb_put (skb, len); @@ -1965,7 +1965,7 @@ static void lmc_softreset (lmc_softc_t * dev_kfree_skb(sc->lmc_txq[i]); /* free it */ sc->stats.tx_dropped++; /* We just dropped a packet */ } - sc->lmc_txq[i] = 0; + sc->lmc_txq[i] = NULL; sc->lmc_txring[i].status = 0x00000000; sc->lmc_txring[i].buffer2 = virt_to_bus (&sc->lmc_txring[i + 1]); } --- linux-2.6.8-rc1/drivers/net/wan/lmc/lmc_proto.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/net/wan/lmc/lmc_proto.c 2004-07-13 17:09:13.000000000 -0700 @@ -112,7 +112,7 @@ void lmc_proto_attach(lmc_softc_t *sc) / * They set a few basics because they don't use sync_ppp */ dev->flags |= IFF_POINTOPOINT; - dev->hard_header = 0; + dev->hard_header = NULL; dev->hard_header_len = 0; dev->addr_len = 0; } --- linux-2.6.8-rc1/drivers/net/wan/pc300_tty.c 2004-03-10 20:41:29.000000000 -0800 +++ 25/drivers/net/wan/pc300_tty.c 2004-07-13 17:09:13.000000000 -0700 @@ -264,7 +264,7 @@ void cpc_tty_init(pc300dev_t *pc300dev) INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work, (void *)cpc_tty); INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work, (void *)port); - cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = 0; + cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; pc300dev->cpc_tty = (void *)cpc_tty; @@ -878,7 +878,7 @@ void cpc_tty_receive(pc300dev_t *pc300de cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); } new->size = rx_len; - new->next = 0; + new->next = NULL; if (cpc_tty->buf_rx.first == 0) { cpc_tty->buf_rx.first = new; cpc_tty->buf_rx.last = new; --- linux-2.6.8-rc1/drivers/net/wan/sbni.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/wan/sbni.c 2004-07-13 17:09:13.000000000 -0700 @@ -349,7 +349,7 @@ sbni_probe1( struct net_device *dev, u if( sbni_card_probe( ioaddr ) ) { release_region( ioaddr, SBNI_IO_EXTENT ); - return 0; + return NULL; } outb( 0, ioaddr + CSR0 ); @@ -368,7 +368,7 @@ sbni_probe1( struct net_device *dev, u printk( KERN_ERR "%s: can't detect device irq!\n", dev->name ); release_region( ioaddr, SBNI_IO_EXTENT ); - return 0; + return NULL; } } else if( irq == 2 ) irq = 9; @@ -381,7 +381,7 @@ sbni_probe1( struct net_device *dev, u if( !nl ) { printk( KERN_ERR "%s: unable to get memory!\n", dev->name ); release_region( ioaddr, SBNI_IO_EXTENT ); - return 0; + return NULL; } dev->priv = nl; --- linux-2.6.8-rc1/drivers/net/wan/syncppp.c 2003-10-17 15:58:03.000000000 -0700 +++ 25/drivers/net/wan/syncppp.c 2004-07-13 17:09:13.000000000 -0700 @@ -643,7 +643,7 @@ badreq: case LCP_TERM_REQ: sppp_clear_timeout (sp); /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); + sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL); /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; @@ -1262,7 +1262,7 @@ static void sppp_ipcp_input (struct sppp } else { /* Send Configure-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, - 0, 0); + 0, NULL); /* Change the state. */ if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) sp->ipcp.state = IPCP_STATE_OPENED; @@ -1297,7 +1297,7 @@ static void sppp_ipcp_input (struct sppp break; case IPCP_TERM_REQ: /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); + sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL); /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; /* Initiate renegotiation. */ @@ -1332,7 +1332,7 @@ static void sppp_lcp_open (struct sppp * static void sppp_ipcp_open (struct sppp *sp) { sp->ipcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL); sppp_set_timeout (sp, 2); } --- linux-2.6.8-rc1/drivers/net/wan/x25_asy.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wan/x25_asy.c 2004-07-13 17:09:13.000000000 -0700 @@ -627,7 +627,7 @@ static void x25_asy_close_tty(struct tty (void) dev_close(sl->dev); } - tty->disc_data = 0; + tty->disc_data = NULL; sl->tty = NULL; x25_asy_free(sl); } --- linux-2.6.8-rc1/drivers/net/wireless/airo.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/airo.c 2004-07-13 17:09:52.000000000 -0700 @@ -101,7 +101,7 @@ static struct pci_driver airo_driver = { infront of the label, that statistic will not be included in the list of statistics in the /proc filesystem */ -#define IGNLABEL(comment) 0 +#define IGNLABEL(comment) NULL static char *statsLabels[] = { "RxOverrun", IGNLABEL("RxPlcpCrcErr"), @@ -1210,6 +1210,7 @@ struct airo_info { APListRid *APList; #define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE u32 pci_state[16]; + char proc_name[IFNAMSIZ]; }; static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, @@ -2346,7 +2347,7 @@ void stop_airo_card( struct net_device * if (ai->wifidev) { unregister_netdev(ai->wifidev); free_netdev(ai->wifidev); - ai->wifidev = 0; + ai->wifidev = NULL; } clear_bit(FLAG_REGISTERED, &ai->flags); } @@ -2358,7 +2359,7 @@ void stop_airo_card( struct net_device * * Clean out tx queue */ if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) { - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; for (;(skb = skb_dequeue(&ai->txq));) dev_kfree_skb(skb); } @@ -2680,7 +2681,8 @@ int reset_card( struct net_device *dev , } struct net_device *_init_airo_card( unsigned short irq, int port, - int is_pcmcia, struct pci_dev *pci ) + int is_pcmcia, struct pci_dev *pci, + struct device *dmdev ) { struct net_device *dev; struct airo_info *ai; @@ -2741,10 +2743,8 @@ struct net_device *_init_airo_card( unsi dev->irq = irq; dev->base_addr = port; - /* what is with PCMCIA ??? */ - if (pci) { - SET_NETDEV_DEV(dev, &pci->dev); - } + SET_NETDEV_DEV(dev, dmdev); + if (test_bit(FLAG_MPI,&ai->flags)) reset_card (dev, 1); @@ -2826,9 +2826,9 @@ err_out_free: return NULL; } -struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) +struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia, struct device *dmdev ) { - return _init_airo_card ( irq, port, is_pcmcia, 0); + return _init_airo_card ( irq, port, is_pcmcia, 0, dmdev); } EXPORT_SYMBOL(init_airo_card); @@ -4369,7 +4369,8 @@ static int setup_proc_entry( struct net_ struct airo_info *apriv ) { struct proc_dir_entry *entry; /* First setup the device directory */ - apriv->proc_entry = create_proc_entry(dev->name, + strcpy(apriv->proc_name,dev->name); + apriv->proc_entry = create_proc_entry(apriv->proc_name, S_IFDIR|airo_perm, airo_entry); apriv->proc_entry->uid = proc_uid; @@ -4470,7 +4471,7 @@ static int takedown_proc_entry( struct n remove_proc_entry("APList",apriv->proc_entry); remove_proc_entry("BSSList",apriv->proc_entry); remove_proc_entry("WepKey",apriv->proc_entry); - remove_proc_entry(dev->name,airo_entry); + remove_proc_entry(apriv->proc_name,airo_entry); return 0; } @@ -5458,9 +5459,9 @@ static int __devinit airo_pci_probe(stru pci_set_master(pdev); if (pdev->device == 0x5000 || pdev->device == 0xa504) - dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev); + dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); else - dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev); + dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); if (!dev) return -ENODEV; @@ -5563,7 +5564,7 @@ static int __init airo_init_module( void printk( KERN_INFO "airo: Trying to configure ISA adapter at irq=%d io=0x%x\n", irq[i], io[i] ); - if (init_airo_card( irq[i], io[i], 0 )) + if (init_airo_card( irq[i], io[i], 0, NULL )) have_isa_dev = 1; } --- linux-2.6.8-rc1/drivers/net/wireless/airo_cs.c 2004-03-10 20:41:29.000000000 -0800 +++ 25/drivers/net/wireless/airo_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -89,7 +89,7 @@ MODULE_PARM(irq_list, "1-4i"); event handler. */ -struct net_device *init_airo_card( int, int, int ); +struct net_device *init_airo_card( int, int, int, struct device * ); void stop_airo_card( struct net_device *, int ); int reset_airo_card( struct net_device * ); @@ -270,7 +270,7 @@ static void airo_detach(dev_link_t *link if ( ((local_info_t*)link->priv)->eth_dev ) { stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); } - ((local_info_t*)link->priv)->eth_dev = 0; + ((local_info_t*)link->priv)->eth_dev = NULL; /* Break the link with Card Services */ if (link->handle) @@ -450,7 +450,7 @@ static void airo_config(dev_link_t *link CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); ((local_info_t*)link->priv)->eth_dev = init_airo_card( link->irq.AssignedIRQ, - link->io.BasePort1, 1 ); + link->io.BasePort1, 1, pcmcia_lookup_device(handle) ); if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; /* --- linux-2.6.8-rc1/drivers/net/wireless/arlan.h 2004-02-17 20:48:44.000000000 -0800 +++ 25/drivers/net/wireless/arlan.h 2004-07-13 17:09:53.000000000 -0700 @@ -52,7 +52,6 @@ extern int arlan_debug; extern int arlan_entry_debug; extern int arlan_exit_debug; extern int testMemory; -extern const char* arlan_version; extern int arlan_command(struct net_device * dev, int command); #define SIDUNKNOWN -1 --- linux-2.6.8-rc1/drivers/net/wireless/atmel.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/atmel.c 2004-07-13 17:09:13.000000000 -0700 @@ -1599,7 +1599,7 @@ struct net_device *init_atmel_card( unsi netif_carrier_off(dev); - create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv); + create_proc_read_entry ("driver/atmel", 0, NULL, atmel_read_proc, priv); printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n", dev->name, DRIVER_MAJOR, DRIVER_MINOR); --- linux-2.6.8-rc1/drivers/net/wireless/atmel_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/atmel_cs.c 2004-07-13 17:09:13.000000000 -0700 @@ -612,7 +612,7 @@ static void atmel_release(dev_link_t *li if (dev) stop_atmel_card(dev, 0); - ((local_info_t*)link->priv)->eth_dev = 0; + ((local_info_t*)link->priv)->eth_dev = NULL; /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); --- linux-2.6.8-rc1/drivers/net/wireless/netwave_cs.c 2004-03-10 20:41:29.000000000 -0800 +++ 25/drivers/net/wireless/netwave_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -1075,6 +1075,8 @@ static void netwave_pcmcia_config(dev_li dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); + if (register_netdev(dev) != 0) { printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); goto failed; --- linux-2.6.8-rc1/drivers/net/wireless/orinoco_cs.c 2004-02-03 20:42:36.000000000 -0800 +++ 25/drivers/net/wireless/orinoco_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -461,6 +461,7 @@ orinoco_cs_config(dev_link_t *link) /* register_netdev will give us an ethX name */ dev->name[0] = '\0'; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); --- linux-2.6.8-rc1/drivers/net/wireless/orinoco_plx.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_plx.c 2004-07-13 17:09:13.000000000 -0700 @@ -324,8 +324,6 @@ static struct pci_driver orinoco_plx_dri .id_table = orinoco_plx_pci_id_table, .probe = orinoco_plx_init_one, .remove = __devexit_p(orinoco_plx_remove_one), - .suspend = 0, - .resume = 0, }; static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow , David Gibson )"; --- linux-2.6.8-rc1/drivers/net/wireless/orinoco_tmd.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/orinoco_tmd.c 2004-07-13 17:09:13.000000000 -0700 @@ -202,8 +202,6 @@ static struct pci_driver orinoco_tmd_dri .id_table = orinoco_tmd_pci_id_table, .probe = orinoco_tmd_init_one, .remove = __devexit_p(orinoco_tmd_remove_one), - .suspend = 0, - .resume = 0, }; static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain )"; --- linux-2.6.8-rc1/drivers/net/wireless/prism54/oid_mgt.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/prism54/oid_mgt.c 2004-07-13 17:09:23.000000000 -0700 @@ -28,10 +28,6 @@ const int frequency_list_bg[] = { 2412, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; -const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230, - 5240, 5260, 5280, 5300, 5320 -}; - int channel_of_freq(int f) { @@ -41,10 +37,8 @@ channel_of_freq(int f) while ((c < 14) && (f != frequency_list_bg[c])) c++; return (c >= 14) ? 0 : ++c; - } else if ((f >= (int) 5170) && (f <= (int) 5320)) { - while ((c < 12) && (f != frequency_list_a[c])) - c++; - return (c >= 12) ? 0 : (c + 37); + } else if ((f >= (int) 5000) && (f <= (int) 6000)) { + return ( (f - 5000) / 5 ); } else return 0; } --- linux-2.6.8-rc1/drivers/net/wireless/ray_cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/ray_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -570,6 +570,7 @@ static void ray_config(dev_link_t *link) return; } + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); i = register_netdev(dev); if (i != 0) { printk("ray_config register_netdev() failed\n"); @@ -2914,7 +2915,7 @@ static int __init init_ray_cs(void) DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc); #ifdef CONFIG_PROC_FS - proc_mkdir("driver/ray_cs", 0); + proc_mkdir("driver/ray_cs", NULL); create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_read); raycs_write("driver/ray_cs/essid", write_essid, NULL); --- linux-2.6.8-rc1/drivers/net/wireless/strip.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/net/wireless/strip.c 2004-07-13 17:09:13.000000000 -0700 @@ -2707,7 +2707,7 @@ static void strip_close(struct tty_struc unregister_netdev(strip_info->dev); - tty->disc_data = 0; + tty->disc_data = NULL; strip_info->tty = NULL; printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->dev->name); --- linux-2.6.8-rc1/drivers/net/wireless/wavelan_cs.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/wireless/wavelan_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -4112,6 +4112,7 @@ wv_pcmcia_config(dev_link_t * link) (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr); #endif + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); i = register_netdev(dev); if(i != 0) { --- linux-2.6.8-rc1/drivers/net/wireless/wl3501_cs.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/net/wireless/wl3501_cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -2146,6 +2146,7 @@ static void wl3501_config(dev_link_t *li dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; + SET_NETDEV_DEV(dev, pcmcia_lookup_device(handle)); if (register_netdev(dev)) { printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); goto failed; --- linux-2.6.8-rc1/drivers/pci/hotplug/acpiphp_glue.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/pci/hotplug/acpiphp_glue.c 2004-07-13 17:09:13.000000000 -0700 @@ -1227,7 +1227,7 @@ struct acpiphp_slot *get_slot_from_id(in /* should never happen! */ err("%s: no object for id %d\n", __FUNCTION__, id); WARN_ON(1); - return 0; + return NULL; } --- linux-2.6.8-rc1/drivers/pci/hotplug/cpci_hotplug_core.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/pci/hotplug/cpci_hotplug_core.c 2004-07-13 17:09:13.000000000 -0700 @@ -614,9 +614,9 @@ cpci_start_thread(void) thread_finished = 0; if(controller->irq) { - pid = kernel_thread(event_thread, 0, 0); + pid = kernel_thread(event_thread, NULL, 0); } else { - pid = kernel_thread(poll_thread, 0, 0); + pid = kernel_thread(poll_thread, NULL, 0); } if(pid < 0) { err("Can't start up our thread"); --- linux-2.6.8-rc1/drivers/pci/hotplug/cpqphp_ctrl.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/pci/hotplug/cpqphp_ctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -1829,7 +1829,7 @@ int cpqhp_event_start_thread(void) init_MUTEX_LOCKED(&event_exit); event_finished=0; - pid = kernel_thread(event_thread, 0, 0); + pid = kernel_thread(event_thread, NULL, 0); if (pid < 0) { err ("Can't start up our event thread\n"); return -1; --- linux-2.6.8-rc1/drivers/pci/hotplug/ibmphp_hpc.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/pci/hotplug/ibmphp_hpc.c 2004-07-13 17:09:13.000000000 -0700 @@ -1081,7 +1081,7 @@ int __init ibmphp_hpc_start_poll_thread debug ("%s - Entry\n", __FUNCTION__); - tid_poll = kernel_thread (hpc_poll_thread, 0, 0); + tid_poll = kernel_thread (hpc_poll_thread, NULL, 0); if (tid_poll < 0) { err ("%s - Error, thread not started\n", __FUNCTION__); rc = -1; --- linux-2.6.8-rc1/drivers/pci/hotplug/pciehp_ctrl.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pci/hotplug/pciehp_ctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -1454,7 +1454,7 @@ int pciehp_event_start_thread(void) event_finished=0; init_MUTEX_LOCKED(&event_semaphore); - pid = kernel_thread(event_thread, 0, 0); + pid = kernel_thread(event_thread, NULL, 0); if (pid < 0) { err ("Can't start up our event thread\n"); --- linux-2.6.8-rc1/drivers/pci/hotplug/pciehp_hpc.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pci/hotplug/pciehp_hpc.c 2004-07-13 17:09:13.000000000 -0700 @@ -237,8 +237,8 @@ struct php_ctlr_state_s { static spinlock_t hpc_event_lock; DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */ -static int ctlr_seq_num = 0; /* Controller sequence # */ +static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ +static int ctlr_seq_num; /* Controller sequence # */ static spinlock_t list_lock; static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs); @@ -744,7 +744,7 @@ static void hpc_release_ctlr(struct cont } } if (php_ctlr->pci_dev) - php_ctlr->pci_dev = 0; + php_ctlr->pci_dev = NULL; spin_lock(&list_lock); p = php_ctlr_list_head; @@ -1467,7 +1467,7 @@ int pcie_init(struct controller * ctrl, if (php_ctlr_list_head == 0) { php_ctlr_list_head = php_ctlr; p = php_ctlr_list_head; - p->pnext = 0; + p->pnext = NULL; } else { p = php_ctlr_list_head; --- linux-2.6.8-rc1/drivers/pci/hotplug/rpaphp_vio.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pci/hotplug/rpaphp_vio.c 2004-07-13 17:09:21.000000000 -0700 @@ -86,7 +86,14 @@ int register_vio_slot(struct device_node } slot->dev_type = VIO_DEV; slot->dev.vio_dev = vio_find_node(dn); - if (!slot->dev.vio_dev) + if (slot->dev.vio_dev) { + /* + * rpaphp is the only owner of vio devices and + * does not need extra reference taken by + * vio_find_node + */ + put_device(&slot->dev.vio_dev->dev); + } else slot->dev.vio_dev = vio_register_device_node(dn); if (slot->dev.vio_dev) slot->state = CONFIGURED; --- linux-2.6.8-rc1/drivers/pci/hotplug/shpchp_ctrl.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pci/hotplug/shpchp_ctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -1890,7 +1890,7 @@ int shpchp_event_start_thread (void) event_finished=0; init_MUTEX_LOCKED(&event_semaphore); - pid = kernel_thread(event_thread, 0, 0); + pid = kernel_thread(event_thread, NULL, 0); if (pid < 0) { err ("Can't start up our event thread\n"); --- linux-2.6.8-rc1/drivers/pci/hotplug/shpchp_hpc.c 2004-05-09 21:07:24.000000000 -0700 +++ 25/drivers/pci/hotplug/shpchp_hpc.c 2004-07-13 17:09:13.000000000 -0700 @@ -228,7 +228,7 @@ static spinlock_t hpc_event_lock; DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */ +static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequenc # */ static spinlock_t list_lock; @@ -799,7 +799,7 @@ static void hpc_release_ctlr(struct cont iounmap(php_ctlr->creg); release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); - php_ctlr->pci_dev = 0; + php_ctlr->pci_dev = NULL; } spin_lock(&list_lock); @@ -1572,7 +1572,7 @@ int shpc_init(struct controller * ctrl, if (php_ctlr_list_head == 0) { php_ctlr_list_head = php_ctlr; p = php_ctlr_list_head; - p->pnext = 0; + p->pnext = NULL; } else { p = php_ctlr_list_head; --- linux-2.6.8-rc1/drivers/pci/quirks.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pci/quirks.c 2004-07-13 17:09:22.788808448 -0700 @@ -817,6 +817,7 @@ static void __init quirk_alder_ioapic(st static void __init quirk_intel_ide_combined(struct pci_dev *pdev) { u8 prog, comb, tmp; + int ich = 0; /* * Narrow down to Intel SATA PCI devices. @@ -827,8 +828,12 @@ static void __init quirk_intel_ide_combi case 0x24df: case 0x25a3: case 0x25b0: + ich = 5; + break; case 0x2651: case 0x2652: + case 0x2653: + ich = 6; break; default: /* we do not handle this PCI device */ @@ -839,13 +844,25 @@ static void __init quirk_intel_ide_combi * Read combined mode register. */ pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */ - tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */ - if (tmp == 0x4) /* bits 10x */ - comb = (1 << 0); /* SATA port 0, PATA port 1 */ - else if (tmp == 0x6) /* bits 11x */ - comb = (1 << 2); /* PATA port 0, SATA port 1 */ - else - return; /* not in combined mode */ + + if (ich == 5) { + tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */ + if (tmp == 0x4) /* bits 10x */ + comb = (1 << 0); /* SATA port 0, PATA port 1 */ + else if (tmp == 0x6) /* bits 11x */ + comb = (1 << 2); /* PATA port 0, SATA port 1 */ + else + return; /* not in combined mode */ + } else { + WARN_ON(ich != 6); + tmp &= 0x3; /* interesting bits 1:0 */ + if (tmp & (1 << 0)) + comb = (1 << 2); /* PATA port 0, SATA port 1 */ + else if (tmp & (1 << 1)) + comb = (1 << 0); /* SATA port 0, PATA port 1 */ + else + return; /* not in combined mode */ + } /* * Read programming interface register. --- linux-2.6.8-rc1/drivers/pcmcia/cardbus.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/pcmcia/cardbus.c 2004-07-13 17:09:13.000000000 -0700 @@ -118,7 +118,7 @@ static void cb_release_cis_mem(struct pc cs_dbg(s, 1, "cb_release_cis_mem()\n"); iounmap(s->cb_cis_virt); s->cb_cis_virt = NULL; - s->cb_cis_res = 0; + s->cb_cis_res = NULL; } } --- linux-2.6.8-rc1/drivers/pcmcia/cs.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pcmcia/cs.c 2004-07-13 17:09:39.000000000 -0700 @@ -1160,6 +1160,22 @@ EXPORT_SYMBOL(pcmcia_lookup_bus); #endif +/*===================================================================== + + Return the driver model device associated with a card.. + +======================================================================*/ + +struct device *pcmcia_lookup_device(client_handle_t handle) +{ + if (CHECK_HANDLE(handle)) + return NULL; + + return handle->device; +} + +EXPORT_SYMBOL(pcmcia_lookup_device); + /*====================================================================== Get the current socket state bits. We don't support the latched @@ -2154,6 +2170,7 @@ EXPORT_SYMBOL(pcmcia_set_event_mask); EXPORT_SYMBOL(pcmcia_suspend_card); EXPORT_SYMBOL(pcmcia_validate_cis); EXPORT_SYMBOL(pcmcia_write_memory); +EXPORT_SYMBOL(read_tuple); EXPORT_SYMBOL(dead_socket); EXPORT_SYMBOL(MTDHelperEntry); --- linux-2.6.8-rc1/drivers/pcmcia/cs_internal.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pcmcia/cs_internal.h 2004-07-13 17:09:39.000000000 -0700 @@ -33,6 +33,7 @@ typedef struct eraseq_t { typedef struct client_t { u_short client_magic; struct pcmcia_socket *Socket; + struct device *device; u_char Function; dev_info_t dev_info; u_int Attributes; --- linux-2.6.8-rc1/drivers/pcmcia/ds.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pcmcia/ds.c 2004-07-13 17:09:53.000000000 -0700 @@ -108,6 +108,9 @@ typedef struct user_info_t { struct pcmcia_bus_socket *socket; } user_info_t; +static LIST_HEAD(pcmcia_sockets); +static DECLARE_MUTEX(pcmcia_socket_mutex); + /* Socket state information */ struct pcmcia_bus_socket { atomic_t refcount; @@ -119,6 +122,9 @@ struct pcmcia_bus_socket { struct work_struct removal; socket_bind_t *bind; struct pcmcia_socket *parent; + struct list_head devices; + struct semaphore device_mutex; + struct list_head socket_list; }; #define DS_SOCKET_PRESENT 0x01 @@ -133,7 +139,9 @@ static dev_info_t dev_info = "Driver Ser static int major_dev = -1; -extern struct proc_dir_entry *proc_pccard; +static struct proc_dir_entry *proc_pccard; + +static int resources_ready; /*====================================================================*/ @@ -164,6 +172,7 @@ static int pcmcia_bind_device(bind_req_t client->client_magic = CLIENT_MAGIC; strlcpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN); client->Socket = s; + client->device = &req->device->dev; client->Function = req->Function; client->state = CLIENT_UNBOUND; client->erase_busy.next = &client->erase_busy; @@ -354,6 +363,8 @@ EXPORT_SYMBOL(cs_error); /*======================================================================*/ +static struct pcmcia_device * get_pcmcia_device (struct pcmcia_bus_socket *s, int function); +static void put_pcmcia_device(struct pcmcia_device *dev); static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr); @@ -430,6 +441,218 @@ static int proc_read_drivers(char *buf, /*====================================================================== + sysfs support + +======================================================================*/ + +static ssize_t +pcmcia_show_product_string(struct pcmcia_device *dev, char *buf, int index) +{ + char *str = buf; + + if (dev->id_mask & DEVICE_HAS_VERSION_INFO && index < dev->vers_1.ns) + str += sprintf(str,"%s\n", + dev->vers_1.str+dev->vers_1.ofs[index]); + else + str += sprintf(str,"\n"); + return (str - buf); +} + +#define pcmcia_prod_str_attr(field, index) \ +static ssize_t \ +show_##field (struct device *dmdev, char *buf) \ +{ \ + struct pcmcia_device *dev; \ + \ + dev = to_pcmcia_device (dmdev); \ + return pcmcia_show_product_string(dev,buf,index); \ +} \ +static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +pcmcia_prod_str_attr(prod_str0,0); +pcmcia_prod_str_attr(prod_str1,1); +pcmcia_prod_str_attr(prod_str2,2); +pcmcia_prod_str_attr(prod_str3,3); + +static ssize_t +pcmcia_show_manfid(struct device *dmdev, char *buf) +{ + struct pcmcia_device *dev = to_pcmcia_device(dmdev); + char *str = buf; + + if (dev->id_mask & DEVICE_HAS_MANF_INFO) + str += sprintf(str,"0x%04x, 0x%04x\n", + dev->manfid.manf, + dev->manfid.card); + else + str += sprintf(str,"\n"); + return (str - buf); +} + +static DEVICE_ATTR(manfid,S_IRUGO,pcmcia_show_manfid,NULL); + +static void pcmcia_sysfs_attach(struct pcmcia_device *dev) +{ + device_create_file (&dev->dev, &dev_attr_prod_str0); + device_create_file (&dev->dev, &dev_attr_prod_str1); + device_create_file (&dev->dev, &dev_attr_prod_str2); + device_create_file (&dev->dev, &dev_attr_prod_str3); + device_create_file (&dev->dev, &dev_attr_manfid); +} + +/*====================================================================== + + device addition, removal, and hotplug functions for the driver model + +======================================================================*/ + +static void pcmcia_bus_release_device(struct device *pdev) +{ + struct pcmcia_device *dev = to_pcmcia_device(pdev); + kfree(dev); +} + +static int pcmcia_bus_insert_card(struct pcmcia_bus_socket *s) +{ + struct pcmcia_device *dev; + int i, ret, function_count = 0, has_cis = 0; + cisinfo_t cisinfo; + + if (!(s->state & DS_SOCKET_PRESENT)) + return CS_NO_CARD; + + if (!resources_ready && !(s->parent->features & SS_CAP_STATIC_MAP)) + return CS_NO_CARD; + + down(&s->device_mutex); + if (!list_empty(&s->devices)) { + ret = -EBUSY; + goto out; + } + + ret = pcmcia_validate_cis(s->handle, &cisinfo); + if (ret) + goto out; + + if (cisinfo.Chains) { + cistpl_longlink_mfc_t mfc; + + has_cis = 1; + if (!read_tuple(s->handle, CISTPL_LONGLINK_MFC, &mfc)) + function_count = mfc.nfn; + } + + for (i=0; i<=function_count; i++) { + dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); + if (!dev) + continue; + + memset(dev, 0, sizeof(struct pcmcia_device)); + dev->socket = s; + dev->dev.parent = s->parent->dev.dev; + dev->dev.bus = &pcmcia_bus_type; + dev->dev.release = &pcmcia_bus_release_device; + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%u:%u", s->parent->sock, i); + + dev->function = i; + if (has_cis) { + if (!read_tuple(s->handle, CISTPL_VERS_1, &dev->vers_1)) + dev->id_mask |= DEVICE_HAS_VERSION_INFO; + if (!read_tuple(s->handle, CISTPL_MANFID, &dev->manfid)) + dev->id_mask |= DEVICE_HAS_MANF_INFO; + } + + ret = device_register(&dev->dev); + if (!ret) { + list_add_tail(&dev->device_list, &s->devices); + pcmcia_sysfs_attach(dev); + } else + kfree(dev); + } + +out: + up(&s->device_mutex); + return ret; +} + +static void pcmcia_bus_remove_card(struct pcmcia_bus_socket *s) +{ + struct pcmcia_device *dev, *tmp; + down(&s->device_mutex); + list_for_each_entry_safe(dev, tmp, &s->devices, device_list) { + list_del(&dev->device_list); + device_unregister(&dev->dev); + } + up(&s->device_mutex); +} + +#ifdef CONFIG_HOTPLUG + +int pcmcia_bus_hotplug(struct device *pdev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct pcmcia_device *dev; + char *scratch; + int i = 0; + int length = 0; + + if (!pdev) + return -ENODEV; + + dev = to_pcmcia_device(pdev); + + scratch = buffer; + + /* stuff we want to pass to /sbin/hotplug */ + envp[i++] = scratch; + length += snprintf (scratch, buffer_size - length, "PRODUCT="); + for (i = 0; i < dev->vers_1.ns; i++) { + length += snprintf(scratch,buffer_size - length, "%s\"%s\"", (i>0) ? "," : "", + dev->vers_1.str+dev->vers_1.ofs[i]); + } + + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + envp [i++] = scratch; + length += snprintf (scratch, buffer_size - length, "MANFID=0x%04x,0x%04x", + dev->manfid.manf, dev->manfid.card); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + envp[i] = 0; + + return 0; +} + +#else /* CONFIG_HOTPLUG */ + +int pcmcia_bus_hotplug(struct device *pdev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + return -ENODEV; +} + +#endif /* CONFIG_HOTPLUG */ + +static void pcmcia_rescan_sockets(void) +{ + struct pcmcia_bus_socket *s; + + down(&pcmcia_socket_mutex); + + list_for_each_entry(s, &pcmcia_sockets, socket_list) + pcmcia_bus_insert_card(s); + + up(&pcmcia_socket_mutex); +} + +/*====================================================================== + These manage a ring buffer of events pending for one user process ======================================================================*/ @@ -501,6 +724,7 @@ static int ds_event(event_t event, int p case CS_EVENT_CARD_REMOVAL: s->state &= ~DS_SOCKET_PRESENT; + pcmcia_bus_remove_card(s); if (!(s->state & DS_SOCKET_REMOVAL_PENDING)) { s->state |= DS_SOCKET_REMOVAL_PENDING; schedule_delayed_work(&s->removal, HZ/10); @@ -509,6 +733,7 @@ static int ds_event(event_t event, int p case CS_EVENT_CARD_INSERTION: s->state |= DS_SOCKET_PRESENT; + pcmcia_bus_insert_card(s); handle_event(s, event); break; @@ -562,6 +787,7 @@ static int bind_mtd(struct pcmcia_bus_so static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { struct pcmcia_driver *driver; + struct pcmcia_device *device; socket_bind_t *b; bind_req_t bind_req; int ret; @@ -587,7 +813,12 @@ static int bind_request(struct pcmcia_bu if (!try_module_get(driver->owner)) return -EINVAL; + device = get_pcmcia_device(s, bind_info->function); + if (!device) + return -EINVAL; + bind_req.Socket = s->parent; + bind_req.device = device; bind_req.Function = bind_info->function; bind_req.dev_info = (dev_info_t *) driver->drv.name; ret = pcmcia_bind_device(&bind_req); @@ -614,16 +845,25 @@ static int bind_request(struct pcmcia_bu b->next = s->bind; s->bind = b; + down_write(&device->dev.bus->subsys.rwsem); + device->dev.driver = &driver->drv; + if (driver->attach) { b->instance = driver->attach(); if (b->instance == NULL) { printk(KERN_NOTICE "ds: unable to create instance " "of '%s'!\n", (char *)bind_info->dev_info); module_put(driver->owner); + device->dev.driver = NULL; + up_write(&device->dev.bus->subsys.rwsem); return -ENODEV; } } + device_bind_driver(&device->dev); + up_write(&device->dev.bus->subsys.rwsem); + put_pcmcia_device(device); + return 0; } /* bind_request */ @@ -699,6 +939,7 @@ static int get_device_info(struct pcmcia static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { socket_bind_t **b, *c; + struct pcmcia_device *device; ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock, (char *)bind_info->dev_info); @@ -710,6 +951,14 @@ static int unbind_request(struct pcmcia_ if (*b == NULL) return -ENODEV; + device = get_pcmcia_device(s, bind_info->function); + if (device) { + down_write(&device->dev.bus->subsys.rwsem); + device_release_driver(&device->dev); + up_write(&device->dev.bus->subsys.rwsem); + put_pcmcia_device(device); + } + c = *b; c->driver->use_count--; if (c->driver->detach) { @@ -933,6 +1182,12 @@ static int ds_ioctl(struct inode * inode switch (cmd) { case DS_ADJUST_RESOURCE_INFO: ret = pcmcia_adjust_resource_info(s->handle, &buf.adjust); + /* + * We can't read CIS information until user space has given us the + * memory resource locations. Therefore, we wait until now. + */ + if ((ret == CS_SUCCESS) && (buf.adjust.Resource == RES_MEMORY_RANGE)) + resources_ready = 1; break; case DS_GET_CARD_SERVICES_INFO: ret = pcmcia_get_card_services_info(&buf.servinfo); @@ -1005,6 +1260,7 @@ static int ds_ioctl(struct inode * inode break; case DS_BIND_REQUEST: if (!capable(CAP_SYS_ADMIN)) return -EPERM; + pcmcia_rescan_sockets(); err = bind_request(s, &buf.bind_info); break; case DS_GET_DEVICE_INFO: @@ -1075,7 +1331,11 @@ static int __devinit pcmcia_bus_add_sock return -ENOMEM; memset(s, 0, sizeof(struct pcmcia_bus_socket)); atomic_set(&s->refcount, 1); - + + down(&pcmcia_socket_mutex); + list_add_tail(&s->socket_list, &pcmcia_sockets); + up(&pcmcia_socket_mutex); + /* * Ugly. But we want to wait for the socket threads to have started up. * We really should let the drivers themselves drive some of this.. @@ -1087,6 +1347,8 @@ static int __devinit pcmcia_bus_add_sock init_waitqueue_head(&s->request); /* initialize data */ + INIT_LIST_HEAD(&s->devices); + init_MUTEX(&s->device_mutex); INIT_WORK(&s->removal, handle_removal, s); s->parent = socket; @@ -1135,6 +1397,11 @@ static void pcmcia_bus_remove_socket(str pcmcia_deregister_client(socket->pcmcia->handle); + down(&pcmcia_socket_mutex); + pcmcia_bus_remove_card(socket->pcmcia); + list_del(&socket->pcmcia->socket_list); + up(&pcmcia_socket_mutex); + socket->pcmcia->state |= DS_SOCKET_DEAD; pcmcia_put_bus_socket(socket->pcmcia); socket->pcmcia = NULL; @@ -1153,7 +1420,9 @@ static struct class_interface pcmcia_bus struct bus_type pcmcia_bus_type = { .name = "pcmcia", + .hotplug = pcmcia_bus_hotplug, }; + EXPORT_SYMBOL(pcmcia_bus_type); @@ -1180,13 +1449,12 @@ static int __init init_pcmcia_bus(void) return 0; } -fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that +fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that * pcmcia_socket_class is already registered */ static void __exit exit_pcmcia_bus(void) { - class_interface_unregister(&pcmcia_bus_interface); #ifdef CONFIG_PROC_FS if (proc_pccard) { @@ -1197,6 +1465,7 @@ static void __exit exit_pcmcia_bus(void) if (major_dev != -1) unregister_chrdev(major_dev, "pcmcia"); + class_interface_unregister(&pcmcia_bus_interface); bus_unregister(&pcmcia_bus_type); } module_exit(exit_pcmcia_bus); @@ -1238,9 +1507,30 @@ static struct pcmcia_driver * get_pcmcia struct cmp_data cmp = { .dev_info = dev_info, }; - + ret = bus_for_each_drv(&pcmcia_bus_type, NULL, &cmp, cmp_drv_callback); if (ret) return cmp.drv; return NULL; } + +static struct pcmcia_device * get_pcmcia_device (struct pcmcia_bus_socket *s, int function) +{ + struct pcmcia_device *dev, *tmp; + down(&s->device_mutex); + list_for_each_entry_safe(dev, tmp, &s->devices, device_list) { + if (dev->function == function) { + if (!get_device(&dev->dev)) + break; + up(&s->device_mutex); + return dev; + } + } + up(&s->device_mutex); + return NULL; +} + +static void put_pcmcia_device(struct pcmcia_device *dev) +{ + put_device(&dev->dev); +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/cpumask.h 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,25 @@ +/* $Id: cpumask.h,v 1.7 2004/05/12 19:59:01 mikpe Exp $ + * Performance-monitoring counters driver. + * Partial simulation of cpumask_t on non-cpumask_t kernels. + * Extension to allow inspecting a cpumask_t as array of ulong. + * Appropriate definition of perfctr_cpus_forbidden_mask. + * + * Copyright (C) 2003-2004 Mikael Pettersson + */ + +#ifdef CPU_ARRAY_SIZE +#define PERFCTR_CPUMASK_NRLONGS CPU_ARRAY_SIZE +#else +#define PERFCTR_CPUMASK_NRLONGS 1 +#endif + +/* CPUs in `perfctr_cpus_forbidden_mask' must not use the + performance-monitoring counters. TSC use is unrestricted. + This is needed to prevent resource conflicts on hyper-threaded P4s. */ +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK +extern cpumask_t perfctr_cpus_forbidden_mask; +#define perfctr_cpu_is_forbidden(cpu) cpu_isset((cpu), perfctr_cpus_forbidden_mask) +#else +#define perfctr_cpus_forbidden_mask CPU_MASK_NONE +#define perfctr_cpu_is_forbidden(cpu) 0 /* cpu_isset() needs an lvalue :-( */ +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/init.c 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,95 @@ +/* $Id: init.c,v 1.76 2004/05/31 18:18:55 mikpe Exp $ + * Performance-monitoring counters driver. + * Top-level initialisation code. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#include +#include +#include +#include +#include + +#include + +#include "cpumask.h" +#include "virtual.h" +#include "version.h" + +struct perfctr_info perfctr_info = { + .abi_version = PERFCTR_ABI_VERSION, + .driver_version = VERSION, +}; + +char *perfctr_cpu_name __initdata; + +static int cpus_copy_to_user(struct perfctr_cpu_mask __user *argp, const cpumask_t *cpus) +{ + const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int)); + unsigned int u_nrwords; + unsigned int ui, ki, j; + + if (get_user(u_nrwords, &argp->nrwords)) + return -EFAULT; + if (put_user(k_nrwords, &argp->nrwords)) + return -EFAULT; + if (u_nrwords < k_nrwords) + return -EOVERFLOW; + for(ui = 0, ki = 0; ki < PERFCTR_CPUMASK_NRLONGS; ++ki) { + unsigned long mask = cpus_addr(*cpus)[ki]; + for(j = 0; j < sizeof(long)/sizeof(int); ++j) { + if (put_user((unsigned int)mask, &argp->mask[ui])) + return -EFAULT; + ++ui; + mask = (mask >> (8*sizeof(int)-1)) >> 1; + } + } + return 0; +} + +asmlinkage long sys_perfctr_info(struct perfctr_info __user *infop, + struct perfctr_cpu_mask __user *cpusp, + struct perfctr_cpu_mask __user *forbiddenp) +{ + if (infop && copy_to_user(infop, &perfctr_info, sizeof perfctr_info)) + return -EFAULT; + if (cpusp) { + int err = cpus_copy_to_user(cpusp, &cpu_online_map); + if (err) + return err; + } + if (forbiddenp) { + int err = cpus_copy_to_user(forbiddenp, &perfctr_cpus_forbidden_mask); + if (err) + return err; + } + return 0; +} + +static int __init perfctr_init(void) +{ + int err; + + err = perfctr_cpu_init(); + if (err) { + printk(KERN_INFO "perfctr: not supported by this processor\n"); + return err; + } + err = vperfctr_init(); + if (err) + return err; + printk(KERN_INFO "perfctr: driver %s, cpu type %s at %u kHz\n", + perfctr_info.driver_version, + perfctr_cpu_name, + perfctr_info.cpu_khz); + return 0; +} + +static void __exit perfctr_exit(void) +{ + vperfctr_exit(); + perfctr_cpu_exit(); +} + +module_init(perfctr_init) +module_exit(perfctr_exit) --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/Kconfig 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,62 @@ +# $Id: Kconfig,v 1.10 2004/05/24 11:00:55 mikpe Exp $ +# Performance-monitoring counters driver configuration +# + +menu "Performance-monitoring counters support" + +config PERFCTR + bool "Performance monitoring counters support" + help + This driver provides access to the performance-monitoring counter + registers available in some (but not all) modern processors. + These special-purpose registers can be programmed to count low-level + performance-related events which occur during program execution, + such as cache misses, pipeline stalls, etc. + + You can safely say Y here, even if you intend to run the kernel + on a processor without performance-monitoring counters. + + At you can find + the corresponding user-space components, as well as other + versions of this package. A mailing list is also available, at + . + +config PERFCTR_INIT_TESTS + bool "Init-time hardware tests" + depends on PERFCTR + default n + help + This option makes the driver perform additional hardware tests + during initialisation, and log their results in the kernel's + message buffer. For most supported processors, these tests simply + measure the runtime overheads of performance counter operations. + + If you have a less well-known processor (one not listed in the + etc/costs/ directory in the user-space package), you should enable + this option and email the results to the perfctr developers. + + If unsure, say N. + +config PERFCTR_VIRTUAL + bool "Virtual performance counters support" + depends on PERFCTR + help + The processor's performance-monitoring counters are special-purpose + global registers. This option adds support for virtual per-process + performance-monitoring counters which only run when the process + to which they belong is executing. This improves the accuracy of + performance measurements by reducing "noise" from other processes. + + Say Y. + +config PERFCTR_INTERRUPT_SUPPORT + bool + depends on PERFCTR + default y if X86_LOCAL_APIC + +config PERFCTR_CPUS_FORBIDDEN_MASK + bool + depends on PERFCTR + default y if X86 && SMP + +endmenu --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/Makefile 2004-07-13 17:09:33.000000000 -0700 @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.26 2004/05/30 23:02:14 mikpe Exp $ +# Makefile for the Performance-monitoring counters driver. + +# This also covers x86_64. +perfctr-objs-$(CONFIG_X86) := x86.o +tests-objs-$(CONFIG_X86) := x86_tests.o + +perfctr-objs-$(CONFIG_PPC32) := ppc.o +tests-objs-$(CONFIG_PPC32) := ppc_tests.o + +perfctr-objs-y += init.o +perfctr-objs-$(CONFIG_PERFCTR_INIT_TESTS) += $(tests-objs-y) +perfctr-objs-$(CONFIG_PERFCTR_VIRTUAL) += virtual.o + +perfctr-objs := $(perfctr-objs-y) +obj-$(CONFIG_PERFCTR) := perfctr.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/ppc.c 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,926 @@ +/* $Id: ppc.c,v 1.12 2004/05/31 18:13:42 mikpe Exp $ + * PPC32 performance-monitoring counters driver. + * + * Copyright (C) 2004 Mikael Pettersson + */ +#include +#include +#include +#include +#include +#include +#include /* tb_ticks_per_jiffy, get_tbl() */ + +#include "ppc_tests.h" + +/* Support for lazy evntsel and perfctr SPR updates. */ +struct per_cpu_cache { /* roughly a subset of perfctr_cpu_state */ + union { + unsigned int id; /* cache owner id */ + } k1; + /* Physically indexed cache of the MMCRs. */ + unsigned int ppc_mmcr[3]; +} ____cacheline_aligned; +static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache); +#define get_cpu_cache() (&__get_cpu_var(per_cpu_cache)) + +/* Structure for counter snapshots, as 32-bit values. */ +struct perfctr_low_ctrs { + unsigned int tsc; + unsigned int pmc[6]; +}; + +enum pm_type { + PM_NONE, + PM_604, + PM_604e, + PM_750, /* XXX: Minor event set diffs between IBM and Moto. */ + PM_7400, + PM_7450, +}; +static enum pm_type pm_type; + +/* Bits users shouldn't set in control.ppc.mmcr0: + * - PMXE because we don't yet support overflow interrupts + * - PMC1SEL/PMC2SEL because event selectors are in control.evntsel[] + */ +#define MMCR0_RESERVED (MMCR0_PMXE | MMCR0_PMC1SEL | MMCR0_PMC2SEL) + +static unsigned int new_id(void) +{ + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + static unsigned int counter; + int id; + + spin_lock(&lock); + id = ++counter; + spin_unlock(&lock); + return id; +} + +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT +static void perfctr_default_ihandler(unsigned long pc) +{ +} + +static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler; + +void do_perfctr_interrupt(struct pt_regs *regs) +{ + preempt_disable(); + (*perfctr_ihandler)(regs->nip); + preempt_enable_no_resched(); +} + +void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler) +{ + perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler; +} + +#else +#define perfctr_cstatus_has_ictrs(cstatus) 0 +#endif + +#if defined(CONFIG_SMP) && defined(CONFIG_PERFCTR_INTERRUPT_SUPPORT) + +static inline void +set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) +{ + state->k1.isuspend_cpu = cpu; +} + +static inline int +is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) +{ + return state->k1.isuspend_cpu == cpu; +} + +static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) +{ + state->k1.isuspend_cpu = NR_CPUS; +} + +#else +static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { } +static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; } +static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { } +#endif + +/**************************************************************** + * * + * Driver procedures. * + * * + ****************************************************************/ + +/* + * The PowerPC 604/750/74xx family. + * + * Common features + * --------------- + * - Per counter event selection data in subfields of control registers. + * MMCR0 contains both global control and PMC1/PMC2 event selectors. + * - Overflow interrupt support is present in all processors, but an + * erratum makes it difficult to use in 750/7400/7410 processors. + * - There is no concept of per-counter qualifiers: + * - User-mode/supervisor-mode restrictions are global. + * - Two groups of counters, PMC1 and PMC2-PMC. Each group + * has a single overflow interrupt/event enable/disable flag. + * - The instructions used to read (mfspr) and write (mtspr) the control + * and counter registers (SPRs) only support hardcoded register numbers. + * There is no support for accessing an SPR via a runtime value. + * - Each counter supports its own unique set of events. However, events + * 0-1 are common for PMC1-PMC4, and events 2-4 are common for PMC1-PMC4. + * - There is no separate high-resolution core clock counter. + * The time-base counter is available, but it typically runs an order of + * magnitude slower than the core clock. + * Any performance counter can be programmed to count core clocks, but + * doing this (a) reserves one PMC, and (b) needs indirect accesses + * since the SPR number in general isn't known at compile-time. + * + * Driver notes + * ------------ + * - The driver currently does not support performance monitor interrupts, + * mostly because of the 750/7400/7410 erratum. Working around it would + * require disabling the decrementer interrupt, reserving a performance + * counter and setting it up for TBL bit-flip events, and having the PMI + * handler invoke the decrementer handler. + * + * 604 + * --- + * 604 has MMCR0, PMC1, PMC2, SIA, and SDA. + * + * MMCR0[THRESHOLD] is not automatically multiplied. + * + * On the 604, software must always reset MMCR0[ENINT] after + * taking a PMI. This is not the case for the 604e. + * + * 604e + * ---- + * 604e adds MMCR1, PMC3, and PMC4. + * Bus-to-core multiplier is available via HID1[PLL_CFG]. + * + * MMCR0[THRESHOLD] is automatically multiplied by 4. + * + * When the 604e vectors to the PMI handler, it automatically + * clears any pending PMIs. Unlike the 604, the 604e does not + * require MMCR0[ENINT] to be cleared (and possibly reset) + * before external interrupts can be re-enabled. + * + * 750 + * --- + * 750 adds user-readable MMCRn/PMCn/SIA registers, and removes SDA. + * + * MMCR0[THRESHOLD] is not automatically multiplied. + * + * Motorola MPC750UM.pdf, page C-78, states: "The performance monitor + * of the MPC755 functions the same as that of the MPC750, (...), except + * that for both the MPC750 and MPC755, no combination of the thermal + * assist unit, the decrementer register, and the performance monitor + * can be used at any one time. If exceptions for any two of these + * functional blocks are enabled together, multiple exceptions caused + * by any of these three blocks cause unpredictable results." + * + * IBM 750CXe_Err_DD2X.pdf, Erratum #13, states that a PMI which + * occurs immediately after a delayed decrementer exception can + * corrupt SRR0, causing the processor to hang. It also states that + * PMIs via TB bit transitions can be used to simulate the decrementer. + * + * 750FX adds dual-PLL support and programmable core frequency switching. + * + * 74xx + * ---- + * 7400 adds MMCR2 and BAMR. + * + * MMCR0[THRESHOLD] is multiplied by 2 or 32, as specified + * by MMCR2[THRESHMULT]. + * + * 74xx changes the semantics of several MMCR0 control bits, + * compared to 604/750. + * + * PPC7410 Erratum No. 10: Like the MPC750 TAU/DECR/PMI erratum. + * Erratum No. 14 marks TAU as unsupported in 7410, but this leaves + * perfmon and decrementer interrupts as being mutually exclusive. + * Affects PPC7410 1.0-1.2 (PVR 0x800C1100-0x800C1102). 1.3 and up + * (PVR 0x800C1103 up) are Ok. + * + * 7450 adds PMC5 and PMC6. + * + * 7455/7445 V3.3 (PVR 80010303) and later use the 7457 PLL table, + * earlier revisions use the 7450 PLL table + */ + +static inline unsigned int read_pmc(unsigned int pmc) +{ + switch (pmc) { + default: /* impossible, but silences gcc warning */ + case 0: + return mfspr(SPRN_PMC1); + case 1: + return mfspr(SPRN_PMC2); + case 2: + return mfspr(SPRN_PMC3); + case 3: + return mfspr(SPRN_PMC4); + case 4: + return mfspr(SPRN_PMC5); + case 5: + return mfspr(SPRN_PMC6); + } +} + +static void ppc_read_counters(/*const*/ struct perfctr_cpu_state *state, + struct perfctr_low_ctrs *ctrs) +{ + unsigned int cstatus, nrctrs, i; + + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + ctrs->tsc = get_tbl(); + nrctrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nrctrs; ++i) { + unsigned int pmc = state->pmc[i].map; + ctrs->pmc[i] = read_pmc(pmc); + } + /* handle MMCR0 changes due to FCECE or TRIGGER on 74xx */ + if (state->cstatus & (1<<30)) { + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + state->ppc_mmcr[0] = mmcr0; + get_cpu_cache()->ppc_mmcr[0] = mmcr0; + } +} + +static unsigned int pmc_max_event(unsigned int pmc) +{ + switch (pmc) { + default: /* impossible, but silences gcc warning */ + case 0: + return 127; + case 1: + return 63; + case 2: + return 31; + case 3: + return 31; + case 4: + return 31; + case 5: + return 63; + } +} + +static unsigned int get_nr_pmcs(void) +{ + switch (pm_type) { + case PM_7450: + return 6; + case PM_7400: + case PM_750: + case PM_604e: + return 4; + case PM_604: + return 2; + default: /* PM_NONE, but silences gcc warning */ + return 0; + } +} + +static int ppc_check_control(struct perfctr_cpu_state *state) +{ + unsigned int i, nrctrs, pmc_mask, pmc; + unsigned int nr_pmcs, evntsel[6]; + + nr_pmcs = get_nr_pmcs(); + nrctrs = state->control.nractrs; + if (state->control.nrictrs || nrctrs > nr_pmcs) + return -EINVAL; + + pmc_mask = 0; + memset(evntsel, 0, sizeof evntsel); + for(i = 0; i < nrctrs; ++i) { + pmc = state->control.pmc_map[i]; + state->pmc[i].map = pmc; + if (pmc >= nr_pmcs || (pmc_mask & (1<control.evntsel[i]; + if (evntsel[pmc] > pmc_max_event(pmc)) + return -EINVAL; + } + + switch (pm_type) { + case PM_7450: + case PM_7400: + if (state->control.ppc.mmcr2 & MMCR2_RESERVED) + return -EINVAL; + state->ppc_mmcr[2] = state->control.ppc.mmcr2; + break; + default: + if (state->control.ppc.mmcr2) + return -EINVAL; + state->ppc_mmcr[2] = 0; + } + + if (state->control.ppc.mmcr0 & MMCR0_RESERVED) + return -EINVAL; + state->ppc_mmcr[0] = (state->control.ppc.mmcr0 + | (evntsel[0] << (31-25)) + | (evntsel[1] << (31-31))); + + state->ppc_mmcr[1] = (( evntsel[2] << (31-4)) + | (evntsel[3] << (31-9)) + | (evntsel[4] << (31-14)) + | (evntsel[5] << (31-20))); + + state->k1.id = new_id(); + + /* + * MMCR0[FC] and MMCR0[TRIGGER] may change on 74xx if FCECE or + * TRIGGER is set. To avoid undoing those changes, we must read + * MMCR0 back into state->ppc_mmcr[0] and the cache at suspends. + */ + switch (pm_type) { + case PM_7450: + case PM_7400: + if (state->ppc_mmcr[0] & (MMCR0_FCECE | MMCR0_TRIGGER)) + state->cstatus |= (1<<30); + default: + ; + } + + return 0; +} + +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT +static void ppc_isuspend(struct perfctr_cpu_state *state) +{ + // XXX +} + +static void ppc_iresume(const struct perfctr_cpu_state *state) +{ + // XXX +} +#endif + +static void ppc_write_control(const struct perfctr_cpu_state *state) +{ + struct per_cpu_cache *cache; + unsigned int value; + + cache = get_cpu_cache(); + if (cache->k1.id == state->k1.id) + return; + /* + * Order matters here: update threshmult and event + * selectors before updating global control, which + * potentially enables PMIs. + * + * Since mtspr doesn't accept a runtime value for the + * SPR number, unroll the loop so each mtspr targets + * a constant SPR. + * + * For processors without MMCR2, we ensure that the + * cache and the state indicate the same value for it, + * preventing any actual mtspr to it. Ditto for MMCR1. + */ + value = state->ppc_mmcr[2]; + if (value != cache->ppc_mmcr[2]) { + cache->ppc_mmcr[2] = value; + mtspr(SPRN_MMCR2, value); + } + value = state->ppc_mmcr[1]; + if (value != cache->ppc_mmcr[1]) { + cache->ppc_mmcr[1] = value; + mtspr(SPRN_MMCR1, value); + } + value = state->ppc_mmcr[0]; + if (value != cache->ppc_mmcr[0]) { + cache->ppc_mmcr[0] = value; + mtspr(SPRN_MMCR0, value); + } + cache->k1.id = state->k1.id; +} + +static void ppc_clear_counters(void) +{ + switch (pm_type) { + case PM_7450: + case PM_7400: + mtspr(SPRN_MMCR2, 0); + mtspr(SPRN_BAMR, 0); + case PM_750: + case PM_604e: + mtspr(SPRN_MMCR1, 0); + case PM_604: + mtspr(SPRN_MMCR0, 0); + case PM_NONE: + ; + } + switch (pm_type) { + case PM_7450: + mtspr(SPRN_PMC6, 0); + mtspr(SPRN_PMC5, 0); + case PM_7400: + case PM_750: + case PM_604e: + mtspr(SPRN_PMC4, 0); + mtspr(SPRN_PMC3, 0); + case PM_604: + mtspr(SPRN_PMC2, 0); + mtspr(SPRN_PMC1, 0); + case PM_NONE: + ; + } +} + +/* + * Driver methods, internal and exported. + */ + +static void perfctr_cpu_write_control(const struct perfctr_cpu_state *state) +{ + return ppc_write_control(state); +} + +static void perfctr_cpu_read_counters(/*const*/ struct perfctr_cpu_state *state, + struct perfctr_low_ctrs *ctrs) +{ + return ppc_read_counters(state, ctrs); +} + +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT +static void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) +{ + return ppc_isuspend(state); +} + +static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) +{ + return ppc_iresume(state); +} + +/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to + bypass internal caching and force a reload if the I-mode PMCs. */ +void perfctr_cpu_ireload(struct perfctr_cpu_state *state) +{ +#ifdef CONFIG_SMP + clear_isuspend_cpu(state); +#else + get_cpu_cache()->k1.id = 0; +#endif +} + +/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */ +unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state) +{ + unsigned int cstatus, nrctrs, pmc, pmc_mask; + + cstatus = state->cstatus; + pmc = perfctr_cstatus_nractrs(cstatus); + nrctrs = perfctr_cstatus_nrctrs(cstatus); + + for(pmc_mask = 0; pmc < nrctrs; ++pmc) { + if ((int)state->pmc[pmc].start < 0) { /* PPC-specific */ + /* XXX: "+=" to correct for overshots */ + state->pmc[pmc].start = state->control.ireset[pmc]; + pmc_mask |= (1 << pmc); + } + } + /* XXX: if pmc_mask == 0, then it must have been a TBL bit flip */ + /* XXX: HW cleared MMCR0[ENINT]. We presumably cleared the entire + MMCR0, so the re-enable occurs automatically later, no? */ + return pmc_mask; +} + +static inline int check_ireset(const struct perfctr_cpu_state *state) +{ + unsigned int nrctrs, i; + + i = state->control.nractrs; + nrctrs = i + state->control.nrictrs; + for(; i < nrctrs; ++i) + if (state->control.ireset[i] < 0) /* PPC-specific */ + return -EINVAL; + return 0; +} + +static inline void setup_imode_start_values(struct perfctr_cpu_state *state) +{ + unsigned int cstatus, nrctrs, i; + + cstatus = state->cstatus; + nrctrs = perfctr_cstatus_nrctrs(cstatus); + for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) + state->pmc[i].start = state->control.ireset[i]; +} + +#else /* CONFIG_PERFCTR_INTERRUPT_SUPPORT */ +static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { } +static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { } +static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; } +static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { } +#endif /* CONFIG_PERFCTR_INTERRUPT_SUPPORT */ + +static int check_control(struct perfctr_cpu_state *state) +{ + return ppc_check_control(state); +} + +int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global) +{ + int err; + + clear_isuspend_cpu(state); + state->cstatus = 0; + + /* disallow i-mode counters if we cannot catch the interrupts */ + if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) + && state->control.nrictrs) + return -EPERM; + + err = check_ireset(state); + if (err < 0) + return err; + err = check_control(state); /* may initialise state->cstatus */ + if (err < 0) + return err; + state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on, + state->control.nractrs, + state->control.nrictrs); + setup_imode_start_values(state); + return 0; +} + +void perfctr_cpu_suspend(struct perfctr_cpu_state *state) +{ + unsigned int i, cstatus, nractrs; + struct perfctr_low_ctrs now; + + if (perfctr_cstatus_has_ictrs(state->cstatus)) + perfctr_cpu_isuspend(state); + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + state->tsc_sum += now.tsc - state->tsc_start; + nractrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nractrs; ++i) + state->pmc[i].sum += now.pmc[i] - state->pmc[i].start; +} + +void perfctr_cpu_resume(struct perfctr_cpu_state *state) +{ + if (perfctr_cstatus_has_ictrs(state->cstatus)) + perfctr_cpu_iresume(state); + perfctr_cpu_write_control(state); + //perfctr_cpu_read_counters(state, &state->start); + { + struct perfctr_low_ctrs now; + unsigned int i, cstatus, nrctrs; + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + state->tsc_start = now.tsc; + nrctrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nrctrs; ++i) + state->pmc[i].start = now.pmc[i]; + } + /* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */ +} + +void perfctr_cpu_sample(struct perfctr_cpu_state *state) +{ + unsigned int i, cstatus, nractrs; + struct perfctr_low_ctrs now; + + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) { + state->tsc_sum += now.tsc - state->tsc_start; + state->tsc_start = now.tsc; + } + nractrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nractrs; ++i) { + state->pmc[i].sum += now.pmc[i] - state->pmc[i].start; + state->pmc[i].start = now.pmc[i]; + } +} + +static void perfctr_cpu_clear_counters(void) +{ + struct per_cpu_cache *cache; + + cache = get_cpu_cache(); + memset(cache, 0, sizeof *cache); + cache->k1.id = -1; + + ppc_clear_counters(); +} + +/**************************************************************** + * * + * Processor detection and initialisation procedures. * + * * + ****************************************************************/ + +/* Derive CPU core frequency from TB frequency and PLL_CFG. */ + +enum pll_type { + PLL_NONE, /* for e.g. 604 which has no HID1[PLL_CFG] */ + PLL_604e, + PLL_750, + PLL_750FX, + PLL_7400, + PLL_7450, + PLL_7457, +}; + +/* These are the known bus-to-core ratios, indexed by PLL_CFG. + Multiplied by 2 since half-multiplier steps are present. */ + +static unsigned char cfg_ratio_604e[16] __initdata = { // *2 + 2, 2, 14, 2, 4, 13, 5, 9, + 6, 11, 8, 10, 3, 12, 7, 0 +}; + +static unsigned char cfg_ratio_750[16] __initdata = { // *2 + 5, 15, 14, 2, 4, 13, 20, 9, // 0b0110 is 18 if L1_TSTCLK=0, but that is abnormal + 6, 11, 8, 10, 16, 12, 7, 0 +}; + +static unsigned char cfg_ratio_750FX[32] __initdata = { // *2 + 0, 0, 2, 2, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 22, 24, 26, + 28, 30, 32, 34, 36, 38, 40, 0 +}; + +static unsigned char cfg_ratio_7400[16] __initdata = { // *2 + 18, 15, 14, 2, 4, 13, 5, 9, + 6, 11, 8, 10, 16, 12, 7, 0 +}; + +static unsigned char cfg_ratio_7450[32] __initdata = { // *2 + 1, 0, 15, 30, 14, 0, 2, 0, + 4, 0, 13, 26, 5, 0, 9, 18, + 6, 0, 11, 22, 8, 20, 10, 24, + 16, 28, 12, 32, 7, 0, 0, 0 +}; + +static unsigned char cfg_ratio_7457[32] __initdata = { // *2 + 23, 34, 15, 30, 14, 36, 2, 40, + 4, 42, 13, 26, 17, 48, 19, 18, + 6, 21, 11, 22, 8, 20, 10, 24, + 16, 28, 12, 32, 27, 56, 0, 25 +}; + +static unsigned int __init tb_to_core_ratio(enum pll_type pll_type) +{ + unsigned char *cfg_ratio; + unsigned int shift = 28, mask = 0xF, hid1, pll_cfg, ratio; + + switch (pll_type) { + case PLL_604e: + cfg_ratio = cfg_ratio_604e; + break; + case PLL_750: + cfg_ratio = cfg_ratio_750; + break; + case PLL_750FX: + cfg_ratio = cfg_ratio_750FX; + hid1 = mfspr(SPRN_HID1); + switch ((hid1 >> 16) & 0x3) { /* HID1[PI0,PS] */ + case 0: /* PLL0 with external config */ + shift = 31-4; /* access HID1[PCE] */ + break; + case 2: /* PLL0 with internal config */ + shift = 31-20; /* access HID1[PC0] */ + break; + case 1: case 3: /* PLL1 */ + shift = 31-28; /* access HID1[PC1] */ + break; + } + mask = 0x1F; + break; + case PLL_7400: + cfg_ratio = cfg_ratio_7400; + break; + case PLL_7450: + cfg_ratio = cfg_ratio_7450; + shift = 12; + mask = 0x1F; + break; + case PLL_7457: + cfg_ratio = cfg_ratio_7457; + shift = 12; + mask = 0x1F; + break; + default: + return 0; + } + hid1 = mfspr(SPRN_HID1); + pll_cfg = (hid1 >> shift) & mask; + ratio = cfg_ratio[pll_cfg]; + if (!ratio) + printk(KERN_WARNING "perfctr: unknown PLL_CFG 0x%x\n", pll_cfg); + return (4/2) * ratio; +} + +static unsigned int __init pll_to_core_khz(enum pll_type pll_type) +{ + unsigned int tb_to_core = tb_to_core_ratio(pll_type); + perfctr_info.tsc_to_cpu_mult = tb_to_core; + return tb_ticks_per_jiffy * tb_to_core * (HZ/10) / (1000/10); +} + +/* Extract core and timebase frequencies from Open Firmware. */ + +static unsigned int __init of_to_core_khz(void) +{ + struct device_node *cpu; + unsigned int *fp, core, tb; + + cpu = find_type_devices("cpu"); + if (!cpu) + return 0; + fp = (unsigned int*)get_property(cpu, "clock-frequency", NULL); + if (!fp || !(core = *fp)) + return 0; + fp = (unsigned int*)get_property(cpu, "timebase-frequency", NULL); + if (!fp || !(tb = *fp)) + return 0; + perfctr_info.tsc_to_cpu_mult = core / tb; + return core / 1000; +} + +static unsigned int __init detect_cpu_khz(enum pll_type pll_type) +{ + unsigned int khz; + + khz = pll_to_core_khz(pll_type); + if (khz) + return khz; + + khz = of_to_core_khz(); + if (khz) + return khz; + + printk(KERN_WARNING "perfctr: unable to determine CPU speed\n"); + return 0; +} + +static int __init known_init(void) +{ + static char known_name[] __initdata = "PowerPC 60x/7xx/74xx"; + unsigned int features; + enum pll_type pll_type; + unsigned int pvr; + int have_mmcr1; + + features = PERFCTR_FEATURE_RDTSC | PERFCTR_FEATURE_RDPMC; + have_mmcr1 = 1; + pvr = mfspr(SPRN_PVR); + switch (PVR_VER(pvr)) { + case 0x0004: /* 604 */ + pm_type = PM_604; + pll_type = PLL_NONE; + features = PERFCTR_FEATURE_RDTSC; + have_mmcr1 = 0; + break; + case 0x0009: /* 604e; */ + case 0x000A: /* 604ev */ + pm_type = PM_604e; + pll_type = PLL_604e; + features = PERFCTR_FEATURE_RDTSC; + break; + case 0x0008: /* 750/740 */ + pm_type = PM_750; + pll_type = PLL_750; + break; + case 0x7000: case 0x7001: /* IBM750FX */ + case 0x7002: /* IBM750GX */ + pm_type = PM_750; + pll_type = PLL_750FX; + break; + case 0x000C: /* 7400 */ + pm_type = PM_7400; + pll_type = PLL_7400; + break; + case 0x800C: /* 7410 */ + pm_type = PM_7400; + pll_type = PLL_7400; + break; + case 0x8000: /* 7451/7441 */ + pm_type = PM_7450; + pll_type = PLL_7450; + break; + case 0x8001: /* 7455/7445 */ + pm_type = PM_7450; + pll_type = ((pvr & 0xFFFF) < 0x0303) ? PLL_7450 : PLL_7457; + break; + case 0x8002: /* 7457/7447 */ + pm_type = PM_7450; + pll_type = PLL_7457; + break; + default: + return -ENODEV; + } + perfctr_info.cpu_features = features; + perfctr_info.cpu_type = 0; /* user-space should inspect PVR */ + perfctr_cpu_name = known_name; + perfctr_info.cpu_khz = detect_cpu_khz(pll_type); + perfctr_ppc_init_tests(have_mmcr1); + return 0; +} + +static int __init unknown_init(void) +{ + static char unknown_name[] __initdata = "Generic PowerPC with TB"; + unsigned int khz; + + khz = detect_cpu_khz(PLL_NONE); + if (!khz) + return -ENODEV; + perfctr_info.cpu_features = PERFCTR_FEATURE_RDTSC; + perfctr_info.cpu_type = 0; + perfctr_cpu_name = unknown_name; + perfctr_info.cpu_khz = khz; + pm_type = PM_NONE; + return 0; +} + +static void perfctr_cpu_clear_one(void *ignore) +{ + /* PREEMPT note: when called via on_each_cpu(), + this is in IRQ context with preemption disabled. */ + perfctr_cpu_clear_counters(); +} + +static void perfctr_cpu_reset(void) +{ + on_each_cpu(perfctr_cpu_clear_one, NULL, 1, 1); + perfctr_cpu_set_ihandler(NULL); +} + +static int init_done; + +int __init perfctr_cpu_init(void) +{ + int err; + + perfctr_info.cpu_features = 0; + + err = known_init(); + if (err) { + err = unknown_init(); + if (err) + goto out; + } + + perfctr_cpu_reset(); + init_done = 1; + out: + return err; +} + +void __exit perfctr_cpu_exit(void) +{ + perfctr_cpu_reset(); +} + +/**************************************************************** + * * + * Hardware reservation. * + * * + ****************************************************************/ + +static DECLARE_MUTEX(mutex); +static const char *current_service = 0; + +const char *perfctr_cpu_reserve(const char *service) +{ + const char *ret; + + if (!init_done) + return "unsupported hardware"; + down(&mutex); + ret = current_service; + if (!ret) + current_service = service; + up(&mutex); + return ret; +} + +void perfctr_cpu_release(const char *service) +{ + down(&mutex); + if (service != current_service) { + printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n", + __FUNCTION__, service, current_service); + } else { + /* power down the counters */ + perfctr_cpu_reset(); + current_service = 0; + } + up(&mutex); +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/ppc_tests.c 2004-07-13 17:09:34.000000000 -0700 @@ -0,0 +1,288 @@ +/* $Id: ppc_tests.c,v 1.4 2004/05/21 16:57:53 mikpe Exp $ + * Performance-monitoring counters driver. + * Optional PPC32-specific init-time tests. + * + * Copyright (C) 2004 Mikael Pettersson + */ +#include +#include +#include +#include +#include +#include +#include /* for tb_ticks_per_jiffy */ +#include "ppc_tests.h" + +#define NITER 256 +#define X2(S) S"; "S +#define X8(S) X2(X2(X2(S))) + +static void __init do_read_tbl(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mftbl %0") : "=r"(dummy)); +} + +static void __init do_read_pmc1(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC1)) : "=r"(dummy)); +} + +static void __init do_read_pmc2(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC2)) : "=r"(dummy)); +} + +static void __init do_read_pmc3(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC3)) : "=r"(dummy)); +} + +static void __init do_read_pmc4(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC4)) : "=r"(dummy)); +} + +static void __init do_read_mmcr0(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR0)) : "=r"(dummy)); +} + +static void __init do_read_mmcr1(unsigned int unused) +{ + unsigned int i, dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR1)) : "=r"(dummy)); +} + +static void __init do_write_pmc2(unsigned int arg) +{ + unsigned int i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC2) ",%0") : : "r"(arg)); +} + +static void __init do_write_pmc3(unsigned int arg) +{ + unsigned int i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC3) ",%0") : : "r"(arg)); +} + +static void __init do_write_pmc4(unsigned int arg) +{ + unsigned int i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC4) ",%0") : : "r"(arg)); +} + +static void __init do_write_mmcr1(unsigned int arg) +{ + unsigned int i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR1) ",%0") : : "r"(arg)); +} + +static void __init do_write_mmcr0(unsigned int arg) +{ + unsigned int i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR0) ",%0") : : "r"(arg)); +} + +static void __init do_empty_loop(unsigned int unused) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__("" : : ); +} + +static unsigned __init run(void (*doit)(unsigned int), unsigned int arg) +{ + unsigned int start, stop; + start = mfspr(SPRN_PMC1); + (*doit)(arg); /* should take < 2^32 cycles to complete */ + stop = mfspr(SPRN_PMC1); + return stop - start; +} + +static void __init init_tests_message(void) +{ + unsigned int pvr = mfspr(SPRN_PVR); + printk(KERN_INFO "Please email the following PERFCTR INIT lines " + "to mikpe@csd.uu.se\n" + KERN_INFO "To remove this message, rebuild the driver " + "with CONFIG_PERFCTR_INIT_TESTS=n\n"); + printk(KERN_INFO "PERFCTR INIT: PVR 0x%08x, CPU clock %u kHz, TB clock %u kHz\n", + pvr, + perfctr_info.cpu_khz, + tb_ticks_per_jiffy*(HZ/10)/(1000/10)); +} + +static void __init clear(int have_mmcr1) +{ + mtspr(SPRN_MMCR0, 0); + mtspr(SPRN_PMC1, 0); + mtspr(SPRN_PMC2, 0); + if (have_mmcr1) { + mtspr(SPRN_MMCR1, 0); + mtspr(SPRN_PMC3, 0); + mtspr(SPRN_PMC4, 0); + } +} + +static void __init check_fcece(unsigned int pmc1ce) +{ + unsigned int mmcr0; + + /* + * This test checks if MMCR0[FC] is set after PMC1 overflows + * when MMCR0[FCECE] is set. + * 74xx documentation states this behaviour, while documentation + * for 604/750 processors doesn't mention this at all. + * + * Also output the value of PMC1 shortly after the overflow. + * This tells us if PMC1 really was frozen. On 604/750, it may not + * freeze since we don't enable PMIs. [No freeze confirmed on 750.] + * + * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether + * this masks all PMC1 overflow events or just PMC1 PMIs. + * + * PMC1 counts processor cycles, with 100 to go before overflowing. + * FCECE is set. + * PMC1CE is clear if !pmc1ce, otherwise set. + */ + mtspr(SPRN_PMC1, 0x80000000-100); + mmcr0 = (1<<(31-6)) | (0x01 << 6); + if (pmc1ce) + mmcr0 |= (1<<(31-16)); + mtspr(SPRN_MMCR0, mmcr0); + do { + do_empty_loop(0); + } while (!(mfspr(SPRN_PMC1) & 0x80000000)); + do_empty_loop(0); + printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[FC] is %u, PMC1 is %#x\n", + __FUNCTION__, pmc1ce, + !!(mfspr(SPRN_MMCR0) & (1<<(31-0))), mfspr(SPRN_PMC1)); + mtspr(SPRN_MMCR0, 0); + mtspr(SPRN_PMC1, 0); +} + +static void __init check_trigger(unsigned int pmc1ce) +{ + unsigned int mmcr0; + + /* + * This test checks if MMCR0[TRIGGER] is reset after PMC1 overflows. + * 74xx documentation states this behaviour, while documentation + * for 604/750 processors doesn't mention this at all. + * [No reset confirmed on 750.] + * + * Also output the values of PMC1 and PMC2 shortly after the overflow. + * PMC2 should be equal to PMC1-0x80000000. + * + * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether + * this masks all PMC1 overflow events or just PMC1 PMIs. + * + * PMC1 counts processor cycles, with 100 to go before overflowing. + * PMC2 counts processor cycles, starting from 0. + * TRIGGER is set, so PMC2 doesn't start until PMC1 overflows. + * PMC1CE is clear if !pmc1ce, otherwise set. + */ + mtspr(SPRN_PMC2, 0); + mtspr(SPRN_PMC1, 0x80000000-100); + mmcr0 = (1<<(31-18)) | (0x01 << 6) | (0x01 << 0); + if (pmc1ce) + mmcr0 |= (1<<(31-16)); + mtspr(SPRN_MMCR0, mmcr0); + do { + do_empty_loop(0); + } while (!(mfspr(SPRN_PMC1) & 0x80000000)); + do_empty_loop(0); + printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[TRIGGER] is %u, PMC1 is %#x, PMC2 is %#x\n", + __FUNCTION__, pmc1ce, + !!(mfspr(SPRN_MMCR0) & (1<<(31-18))), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2)); + mtspr(SPRN_MMCR0, 0); + mtspr(SPRN_PMC1, 0); + mtspr(SPRN_PMC2, 0); +} + +static void __init +measure_overheads(int have_mmcr1) +{ + int i; + unsigned int mmcr0, loop, ticks[12]; + const char *name[12]; + + clear(have_mmcr1); + + /* PMC1 = "processor cycles", + PMC2 = "completed instructions", + not disabled in any mode, + no interrupts */ + mmcr0 = (0x01 << 6) | (0x02 << 0); + mtspr(SPRN_MMCR0, mmcr0); + + name[0] = "mftbl"; + ticks[0] = run(do_read_tbl, 0); + name[1] = "mfspr (pmc1)"; + ticks[1] = run(do_read_pmc1, 0); + name[2] = "mfspr (pmc2)"; + ticks[2] = run(do_read_pmc2, 0); + name[3] = "mfspr (pmc3)"; + ticks[3] = have_mmcr1 ? run(do_read_pmc3, 0) : 0; + name[4] = "mfspr (pmc4)"; + ticks[4] = have_mmcr1 ? run(do_read_pmc4, 0) : 0; + name[5] = "mfspr (mmcr0)"; + ticks[5] = run(do_read_mmcr0, 0); + name[6] = "mfspr (mmcr1)"; + ticks[6] = have_mmcr1 ? run(do_read_mmcr1, 0) : 0; + name[7] = "mtspr (pmc2)"; + ticks[7] = run(do_write_pmc2, 0); + name[8] = "mtspr (pmc3)"; + ticks[8] = have_mmcr1 ? run(do_write_pmc3, 0) : 0; + name[9] = "mtspr (pmc4)"; + ticks[9] = have_mmcr1 ? run(do_write_pmc4, 0) : 0; + name[10] = "mtspr (mmcr1)"; + ticks[10] = have_mmcr1 ? run(do_write_mmcr1, 0) : 0; + name[11] = "mtspr (mmcr0)"; + ticks[11] = run(do_write_mmcr0, mmcr0); + + loop = run(do_empty_loop, 0); + + clear(have_mmcr1); + + init_tests_message(); + printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER); + printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop); + for(i = 0; i < ARRAY_SIZE(ticks); ++i) { + unsigned int x; + if (!ticks[i]) + continue; + x = ((ticks[i] - loop) * 10) / NITER; + printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n", + name[i], x/10, x%10, ticks[i]); + } + check_fcece(0); + check_fcece(1); + check_trigger(0); + check_trigger(1); +} + +void __init perfctr_ppc_init_tests(int have_mmcr1) +{ + preempt_disable(); + measure_overheads(have_mmcr1); + preempt_enable(); +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/ppc_tests.h 2004-07-13 17:09:34.000000000 -0700 @@ -0,0 +1,12 @@ +/* $Id: ppc_tests.h,v 1.1 2004/01/12 01:59:11 mikpe Exp $ + * Performance-monitoring counters driver. + * Optional PPC32-specific init-time tests. + * + * Copyright (C) 2004 Mikael Pettersson + */ + +#ifdef CONFIG_PERFCTR_INIT_TESTS +extern void perfctr_ppc_init_tests(int have_mmcr1); +#else +static inline void perfctr_ppc_init_tests(int have_mmcr1) { } +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/version.h 2004-07-13 17:09:33.000000000 -0700 @@ -0,0 +1 @@ +#define VERSION "2.7.3" --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/virtual.c 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,970 @@ +/* $Id: virtual.c,v 1.95 2004/05/31 20:36:37 mikpe Exp $ + * Virtual per-process performance counters. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#include +#include +#include /* for unlikely() in 2.4.18 and older */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "cpumask.h" +#include "virtual.h" + +/**************************************************************** + * * + * Data types and macros. * + * * + ****************************************************************/ + +struct vperfctr { +/* User-visible fields: (must be first for mmap()) */ + struct perfctr_cpu_state cpu_state; +/* Kernel-private fields: */ + int si_signo; + atomic_t count; + spinlock_t owner_lock; + struct task_struct *owner; + /* sampling_timer and bad_cpus_allowed are frequently + accessed, so they get to share a cache line */ + unsigned int sampling_timer ____cacheline_aligned; +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK + atomic_t bad_cpus_allowed; +#endif +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT + unsigned int iresume_cstatus; +#endif +}; +#define IS_RUNNING(perfctr) perfctr_cstatus_enabled((perfctr)->cpu_state.cstatus) + +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT + +static void vperfctr_ihandler(unsigned long pc); + +static inline void vperfctr_set_ihandler(void) +{ + perfctr_cpu_set_ihandler(vperfctr_ihandler); +} + +static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr) +{ + perfctr->iresume_cstatus = 0; +} + +#else +static inline void vperfctr_set_ihandler(void) { } +static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr) { } +#endif + +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK + +static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr) +{ + atomic_set(&perfctr->bad_cpus_allowed, 0); +} + +/* Concurrent set_cpus_allowed() is possible. The only lock it + can take is the task lock, so we have to take it as well. + task_lock/unlock also disables/enables preemption. */ + +static inline void vperfctr_task_lock(struct task_struct *p) +{ + task_lock(p); +} + +static inline void vperfctr_task_unlock(struct task_struct *p) +{ + task_unlock(p); +} + +#else /* !CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK */ + +static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr) { } + +/* Concurrent set_cpus_allowed() is impossible or irrelevant. + Disabling and enabling preemption suffices for an atomic region. */ + +static inline void vperfctr_task_lock(struct task_struct *p) +{ + preempt_disable(); +} + +static inline void vperfctr_task_unlock(struct task_struct *p) +{ + preempt_enable(); +} + +#endif /* !CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK */ + +/**************************************************************** + * * + * Resource management. * + * * + ****************************************************************/ + +/* XXX: perhaps relax this to number of _live_ perfctrs */ +static spinlock_t nrctrs_lock = SPIN_LOCK_UNLOCKED; +static int nrctrs; +static const char this_service[] = __FILE__; + +static int inc_nrctrs(void) +{ + const char *other; + + other = NULL; + spin_lock(&nrctrs_lock); + if (++nrctrs == 1) { + other = perfctr_cpu_reserve(this_service); + if (other) + nrctrs = 0; + } + spin_unlock(&nrctrs_lock); + if (other) { + printk(KERN_ERR __FILE__ + ": cannot operate, perfctr hardware taken by '%s'\n", + other); + return -EBUSY; + } + vperfctr_set_ihandler(); + return 0; +} + +static void dec_nrctrs(void) +{ + spin_lock(&nrctrs_lock); + if (--nrctrs == 0) + perfctr_cpu_release(this_service); + spin_unlock(&nrctrs_lock); +} + +/* Allocate a `struct vperfctr'. Claim and reserve + an entire page so that it can be mmap():ed. */ +static struct vperfctr *vperfctr_alloc(void) +{ + unsigned long page; + + if (inc_nrctrs() != 0) + return ERR_PTR(-EBUSY); + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + dec_nrctrs(); + return ERR_PTR(-ENOMEM); + } + SetPageReserved(virt_to_page(page)); + return (struct vperfctr*) page; +} + +static void vperfctr_free(struct vperfctr *perfctr) +{ + ClearPageReserved(virt_to_page(perfctr)); + free_page((unsigned long)perfctr); + dec_nrctrs(); +} + +static struct vperfctr *get_empty_vperfctr(void) +{ + struct vperfctr *perfctr = vperfctr_alloc(); + if (!IS_ERR(perfctr)) { + atomic_set(&perfctr->count, 1); + vperfctr_init_bad_cpus_allowed(perfctr); + spin_lock_init(&perfctr->owner_lock); + } + return perfctr; +} + +static void put_vperfctr(struct vperfctr *perfctr) +{ + if (atomic_dec_and_test(&perfctr->count)) + vperfctr_free(perfctr); +} + +/**************************************************************** + * * + * Basic counter operations. * + * These must all be called by the owner process only. * + * These must all be called with preemption disabled. * + * * + ****************************************************************/ + +/* PRE: IS_RUNNING(perfctr) + * Suspend the counters. + * XXX: When called from switch_to(), perfctr belongs to 'prev' + * but current is 'next'. + */ +static inline void vperfctr_suspend(struct vperfctr *perfctr) +{ + perfctr_cpu_suspend(&perfctr->cpu_state); +} + +static inline void vperfctr_reset_sampling_timer(struct vperfctr *perfctr) +{ + /* XXX: base the value on perfctr_info.cpu_khz instead! */ + perfctr->sampling_timer = HZ/2; +} + +/* PRE: perfctr == current->thread.perfctr && IS_RUNNING(perfctr) + * Restart the counters. + */ +static inline void vperfctr_resume(struct vperfctr *perfctr) +{ + perfctr_cpu_resume(&perfctr->cpu_state); + vperfctr_reset_sampling_timer(perfctr); +} + +/* Sample the counters but do not suspend them. */ +static void vperfctr_sample(struct vperfctr *perfctr) +{ + if (IS_RUNNING(perfctr)) { + perfctr_cpu_sample(&perfctr->cpu_state); + vperfctr_reset_sampling_timer(perfctr); + } +} + +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT +/* vperfctr interrupt handler (XXX: add buffering support) */ +/* PREEMPT note: called in IRQ context with preemption disabled. */ +static void vperfctr_ihandler(unsigned long pc) +{ + struct task_struct *tsk = current; + struct vperfctr *perfctr; + unsigned int pmc_mask; + siginfo_t si; + + perfctr = tsk->thread.perfctr; + if (!perfctr) { + printk(KERN_ERR "%s: BUG! pid %d has no vperfctr\n", + __FUNCTION__, tsk->pid); + return; + } + if (!perfctr_cstatus_has_ictrs(perfctr->cpu_state.cstatus)) { + printk(KERN_ERR "%s: BUG! vperfctr has cstatus %#x (pid %d, comm %s)\n", + __FUNCTION__, perfctr->cpu_state.cstatus, tsk->pid, tsk->comm); + return; + } + vperfctr_suspend(perfctr); + pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state); + if (!pmc_mask) { + printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n", + __FUNCTION__, tsk->pid); + return; + } + /* suspend a-mode and i-mode PMCs, leaving only TSC on */ + /* XXX: some people also want to suspend the TSC */ + perfctr->iresume_cstatus = perfctr->cpu_state.cstatus; + if (perfctr_cstatus_has_tsc(perfctr->iresume_cstatus)) { + perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0); + vperfctr_resume(perfctr); + } else + perfctr->cpu_state.cstatus = 0; + si.si_signo = perfctr->si_signo; + si.si_errno = 0; + si.si_code = SI_PMC_OVF; + si.si_pmc_ovf_mask = pmc_mask; + if (!send_sig_info(si.si_signo, &si, tsk)) + send_sig(si.si_signo, tsk, 1); +} +#endif + +/**************************************************************** + * * + * Process management operations. * + * These must all, with the exception of vperfctr_unlink() * + * and __vperfctr_set_cpus_allowed(), be called by the owner * + * process only. * + * * + ****************************************************************/ + +/* Called from exit_thread() or do_vperfctr_unlink(). + * If the counters are running, stop them and sample their final values. + * Detach the vperfctr object from its owner task. + * PREEMPT note: exit_thread() does not run with preemption disabled. + */ +static void vperfctr_unlink(struct task_struct *owner, struct vperfctr *perfctr) +{ + /* this synchronises with sys_vperfctr() */ + spin_lock(&perfctr->owner_lock); + perfctr->owner = NULL; + spin_unlock(&perfctr->owner_lock); + + /* perfctr suspend+detach must be atomic wrt process suspend */ + /* this also synchronises with perfctr_set_cpus_allowed() */ + vperfctr_task_lock(owner); + if (IS_RUNNING(perfctr) && owner == current) + vperfctr_suspend(perfctr); + owner->thread.perfctr = NULL; + vperfctr_task_unlock(owner); + + perfctr->cpu_state.cstatus = 0; + vperfctr_clear_iresume_cstatus(perfctr); + put_vperfctr(perfctr); +} + +void __vperfctr_exit(struct vperfctr *perfctr) +{ + vperfctr_unlink(current, perfctr); +} + +/* schedule() --> switch_to() --> .. --> __vperfctr_suspend(). + * If the counters are running, suspend them. + * PREEMPT note: switch_to() runs with preemption disabled. + */ +void __vperfctr_suspend(struct vperfctr *perfctr) +{ + if (IS_RUNNING(perfctr)) + vperfctr_suspend(perfctr); +} + +/* schedule() --> switch_to() --> .. --> __vperfctr_resume(). + * PRE: perfctr == current->thread.perfctr + * If the counters are runnable, resume them. + * PREEMPT note: switch_to() runs with preemption disabled. + */ +void __vperfctr_resume(struct vperfctr *perfctr) +{ + if (IS_RUNNING(perfctr)) { +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK + if (unlikely(atomic_read(&perfctr->bad_cpus_allowed)) && + perfctr_cstatus_nrctrs(perfctr->cpu_state.cstatus)) { + perfctr->cpu_state.cstatus = 0; + vperfctr_clear_iresume_cstatus(perfctr); + BUG_ON(current->state != TASK_RUNNING); + send_sig(SIGILL, current, 1); + return; + } +#endif + vperfctr_resume(perfctr); + } +} + +/* Called from update_one_process() [triggered by timer interrupt]. + * PRE: perfctr == current->thread.perfctr. + * Sample the counters but do not suspend them. + * Needed to avoid precision loss due to multiple counter + * wraparounds between resume/suspend for CPU-bound processes. + * PREEMPT note: called in IRQ context with preemption disabled. + */ +void __vperfctr_sample(struct vperfctr *perfctr) +{ + if (--perfctr->sampling_timer == 0) + vperfctr_sample(perfctr); +} + +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK +/* Called from set_cpus_allowed(). + * PRE: current holds task_lock(owner) + * PRE: owner->thread.perfctr == perfctr + */ +void __vperfctr_set_cpus_allowed(struct task_struct *owner, + struct vperfctr *perfctr, + cpumask_t new_mask) +{ + if (cpus_intersects(new_mask, perfctr_cpus_forbidden_mask)) { + atomic_set(&perfctr->bad_cpus_allowed, 1); + if (printk_ratelimit()) + printk(KERN_WARNING "perfctr: process %d (comm %s) issued unsafe" + " set_cpus_allowed() on process %d (comm %s)\n", + current->pid, current->comm, owner->pid, owner->comm); + } else + atomic_set(&perfctr->bad_cpus_allowed, 0); +} +#endif + +/**************************************************************** + * * + * Virtual perfctr system calls implementation. * + * These can be called by the owner process (tsk == current), * + * a monitor process which has the owner under ptrace ATTACH * + * control (tsk && tsk != current), or anyone with a handle to * + * an unlinked perfctr (!tsk). * + * * + ****************************************************************/ + +static int do_vperfctr_control(struct vperfctr *perfctr, + const struct vperfctr_control __user *argp, + struct task_struct *tsk) +{ + struct vperfctr_control *control; + int err; + unsigned int next_cstatus; + unsigned int nrctrs, i; + + if (!tsk) + return -ESRCH; /* attempt to update unlinked perfctr */ + + /* The control object can be large (over 300 bytes on i386), + so kmalloc() it instead of storing it on the stack. + We must use task-private storage to prevent racing with a + monitor process attaching to us before the non-preemptible + perfctr update step. Therefore we cannot store the copy + in the perfctr object itself. */ + control = kmalloc(sizeof(*control), GFP_USER); + if (!control) + return -ENOMEM; + + err = -EFAULT; + if (copy_from_user(control, argp, sizeof *control)) + goto out_kfree; + + if (control->cpu_control.nractrs || control->cpu_control.nrictrs) { + cpumask_t old_mask, new_mask; + + old_mask = tsk->cpus_allowed; + cpus_andnot(new_mask, old_mask, perfctr_cpus_forbidden_mask); + + err = -EINVAL; + if (cpus_empty(new_mask)) + goto out_kfree; + if (!cpus_equal(new_mask, old_mask)) + set_cpus_allowed(tsk, new_mask); + } + + /* PREEMPT note: preemption is disabled over the entire + region since we're updating an active perfctr. */ + preempt_disable(); + if (IS_RUNNING(perfctr)) { + if (tsk == current) + vperfctr_suspend(perfctr); + perfctr->cpu_state.cstatus = 0; + vperfctr_clear_iresume_cstatus(perfctr); + } + perfctr->cpu_state.control = control->cpu_control; + /* remote access note: perfctr_cpu_update_control() is ok */ + err = perfctr_cpu_update_control(&perfctr->cpu_state, 0); + if (err < 0) + goto out; + next_cstatus = perfctr->cpu_state.cstatus; + if (!perfctr_cstatus_enabled(next_cstatus)) + goto out; + + /* XXX: validate si_signo? */ + perfctr->si_signo = control->si_signo; + + if (!perfctr_cstatus_has_tsc(next_cstatus)) + perfctr->cpu_state.tsc_sum = 0; + + nrctrs = perfctr_cstatus_nrctrs(next_cstatus); + for(i = 0; i < nrctrs; ++i) + if (!(control->preserve & (1<cpu_state.pmc[i].sum = 0; + + if (tsk == current) + vperfctr_resume(perfctr); + + out: + preempt_enable(); + out_kfree: + kfree(control); + return err; +} + +static int do_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk) +{ +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT + unsigned int iresume_cstatus; + + if (!tsk) + return -ESRCH; /* attempt to update unlinked perfctr */ + + iresume_cstatus = perfctr->iresume_cstatus; + if (!perfctr_cstatus_has_ictrs(iresume_cstatus)) + return -EPERM; + + /* PREEMPT note: preemption is disabled over the entire + region because we're updating an active perfctr. */ + preempt_disable(); + + if (IS_RUNNING(perfctr) && tsk == current) + vperfctr_suspend(perfctr); + + perfctr->cpu_state.cstatus = iresume_cstatus; + perfctr->iresume_cstatus = 0; + + /* remote access note: perfctr_cpu_ireload() is ok */ + perfctr_cpu_ireload(&perfctr->cpu_state); + + if (tsk == current) + vperfctr_resume(perfctr); + + preempt_enable(); + + return 0; +#else + return -ENOSYS; +#endif +} + +static int do_vperfctr_unlink(struct vperfctr *perfctr, struct task_struct *tsk) +{ + if (tsk) + vperfctr_unlink(tsk, perfctr); + return 0; +} + +static int do_vperfctr_read(struct vperfctr *perfctr, + struct perfctr_sum_ctrs __user *sump, + struct vperfctr_control __user *controlp, + const struct task_struct *tsk) +{ + struct { + struct perfctr_sum_ctrs sum; + struct vperfctr_control control; + } *tmp; + int ret; + + /* The state snapshot can be large (almost 500 bytes on i386), + so kmalloc() it instead of storing it on the stack. + We must use task-private storage to prevent racing with a + monitor process attaching to us during the preemptible + copy_to_user() step. Therefore we cannot store the snapshot + in the perfctr object itself. */ + tmp = kmalloc(sizeof(*tmp), GFP_USER); + if (!tmp) + return -ENOMEM; + + /* PREEMPT note: While we're reading our own control, another + process may ptrace ATTACH to us and update our control. + Disable preemption to ensure we get a consistent copy. + Not needed for other cases since the perfctr is either + unlinked or its owner is ptrace ATTACH suspended by us. */ + if (tsk == current) { + preempt_disable(); + if (sump) + vperfctr_sample(perfctr); + } + if (sump) { //sum = perfctr->cpu_state.sum; + int j; + tmp->sum.tsc = perfctr->cpu_state.tsc_sum; + for(j = 0; j < ARRAY_SIZE(tmp->sum.pmc); ++j) + tmp->sum.pmc[j] = perfctr->cpu_state.pmc[j].sum; + } + if (controlp) { + tmp->control.si_signo = perfctr->si_signo; + tmp->control.cpu_control = perfctr->cpu_state.control; + tmp->control.preserve = 0; + } + if (tsk == current) + preempt_enable(); + ret = -EFAULT; + if (sump && copy_to_user(sump, &tmp->sum, sizeof tmp->sum)) + goto out; + if (controlp && copy_to_user(controlp, &tmp->control, sizeof tmp->control)) + goto out; + ret = 0; + out: + kfree(tmp); + return ret; +} + +/**************************************************************** + * * + * Virtual perfctr file operations. * + * * + ****************************************************************/ + +static int vperfctr_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct vperfctr *perfctr; + + /* Only allow read-only mapping of first page. */ + if ((vma->vm_end - vma->vm_start) != PAGE_SIZE || + vma->vm_pgoff != 0 || + (pgprot_val(vma->vm_page_prot) & _PAGE_RW) || + (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))) + return -EPERM; + perfctr = filp->private_data; + if (!perfctr) + return -EPERM; + return remap_page_range(vma, vma->vm_start, virt_to_phys(perfctr), + PAGE_SIZE, vma->vm_page_prot); +} + +static int vperfctr_release(struct inode *inode, struct file *filp) +{ + struct vperfctr *perfctr = filp->private_data; + filp->private_data = NULL; + if (perfctr) + put_vperfctr(perfctr); + return 0; +} + +static struct file_operations vperfctr_file_ops = { + .mmap = vperfctr_mmap, + .release = vperfctr_release, +}; + +/**************************************************************** + * * + * File system for virtual perfctrs. Based on pipefs. * + * * + ****************************************************************/ + +#define VPERFCTRFS_MAGIC (('V'<<24)|('P'<<16)|('M'<<8)|('C')) + +/* The code to set up a `struct file_system_type' for a pseudo fs + is unfortunately not the same in 2.4 and 2.6. */ +#include /* needed for 2.6, included by fs.h in 2.4 */ + +static struct super_block * +vperfctrfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "vperfctr:", NULL, VPERFCTRFS_MAGIC); +} + +static struct file_system_type vperfctrfs_type = { + .name = "vperfctrfs", + .get_sb = vperfctrfs_get_sb, + .kill_sb = kill_anon_super, +}; + +/* XXX: check if s/vperfctr_mnt/vperfctrfs_type.kern_mnt/ would work */ +static struct vfsmount *vperfctr_mnt; +#define vperfctr_fs_init_done() (vperfctr_mnt != NULL) + +static int __init vperfctrfs_init(void) +{ + int err = register_filesystem(&vperfctrfs_type); + if (!err) { + vperfctr_mnt = kern_mount(&vperfctrfs_type); + if (!IS_ERR(vperfctr_mnt)) + return 0; + err = PTR_ERR(vperfctr_mnt); + unregister_filesystem(&vperfctrfs_type); + vperfctr_mnt = NULL; + } + return err; +} + +static void __exit vperfctrfs_exit(void) +{ + unregister_filesystem(&vperfctrfs_type); + mntput(vperfctr_mnt); +} + +static struct inode *vperfctr_get_inode(void) +{ + struct inode *inode; + + inode = new_inode(vperfctr_mnt->mnt_sb); + if (!inode) + return NULL; + inode->i_fop = &vperfctr_file_ops; + inode->i_state = I_DIRTY; + inode->i_mode = S_IFCHR | S_IRUSR | S_IWUSR; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_blksize = 0; + return inode; +} + +static int vperfctrfs_delete_dentry(struct dentry *dentry) +{ + return 1; +} + +static struct dentry_operations vperfctrfs_dentry_operations = { + .d_delete = vperfctrfs_delete_dentry, +}; + +static struct dentry *vperfctr_d_alloc_root(struct inode *inode) +{ + struct qstr this; + char name[32]; + struct dentry *dentry; + + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; /* will go */ + dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this); + if (dentry) { + dentry->d_op = &vperfctrfs_dentry_operations; + d_add(dentry, inode); + } + return dentry; +} + +static struct file *vperfctr_get_filp(void) +{ + struct file *filp; + struct inode *inode; + struct dentry *dentry; + + filp = get_empty_filp(); + if (!filp) + goto out; + inode = vperfctr_get_inode(); + if (!inode) + goto out_filp; + dentry = vperfctr_d_alloc_root(inode); + if (!dentry) + goto out_inode; + + filp->f_vfsmnt = mntget(vperfctr_mnt); + filp->f_dentry = dentry; + filp->f_mapping = dentry->d_inode->i_mapping; + + filp->f_pos = 0; + filp->f_flags = 0; + filp->f_op = &vperfctr_file_ops; /* fops_get() if MODULE */ + filp->f_mode = FMODE_READ; + filp->f_version = 0; + + return filp; + + out_inode: + iput(inode); + out_filp: + put_filp(filp); /* doesn't run ->release() like fput() does */ + out: + return NULL; +} + +/**************************************************************** + * * + * Virtual perfctr actual system calls. * + * * + ****************************************************************/ + +/* tid is the actual task/thread id (née pid, stored as ->pid), + pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */ +asmlinkage long sys_vperfctr_open(int tid, int creat) +{ + struct file *filp; + struct task_struct *tsk; + struct vperfctr *perfctr; + int err; + int fd; + + if (!vperfctr_fs_init_done()) + return -ENODEV; + filp = vperfctr_get_filp(); + if (!filp) + return -ENOMEM; + err = fd = get_unused_fd(); + if (err < 0) + goto err_filp; + perfctr = NULL; + if (creat) { + perfctr = get_empty_vperfctr(); /* may sleep */ + if (IS_ERR(perfctr)) { + err = PTR_ERR(perfctr); + goto err_fd; + } + } + tsk = current; + if (tid != 0 && tid != tsk->pid) { /* remote? */ + read_lock(&tasklist_lock); + tsk = find_task_by_pid(tid); + if (tsk) + get_task_struct(tsk); + read_unlock(&tasklist_lock); + err = -ESRCH; + if (!tsk) + goto err_perfctr; + err = ptrace_check_attach(tsk, 0); + if (err < 0) + goto err_tsk; + } + if (creat) { + /* check+install must be atomic to prevent remote-control races */ + vperfctr_task_lock(tsk); + if (!tsk->thread.perfctr) { + perfctr->owner = tsk; + tsk->thread.perfctr = perfctr; + err = 0; + } else + err = -EEXIST; + vperfctr_task_unlock(tsk); + if (err) + goto err_tsk; + } else { + perfctr = tsk->thread.perfctr; + /* XXX: Old API needed to allow NULL perfctr here. + Do we want to keep or change that rule? */ + } + filp->private_data = perfctr; + if (perfctr) + atomic_inc(&perfctr->count); + if (tsk != current) + put_task_struct(tsk); + fd_install(fd, filp); + return fd; + err_tsk: + if (tsk != current) + put_task_struct(tsk); + err_perfctr: + if (perfctr) /* can only occur if creat != 0 */ + put_vperfctr(perfctr); + err_fd: + put_unused_fd(fd); + err_filp: + fput(filp); + return err; +} + +static struct vperfctr *fd_get_vperfctr(int fd) +{ + struct vperfctr *perfctr; + struct file *filp; + int err; + + err = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + err = -EINVAL; + if (filp->f_op != &vperfctr_file_ops) + goto out_filp; + perfctr = filp->private_data; + if (!perfctr) + goto out_filp; + atomic_inc(&perfctr->count); + fput(filp); + return perfctr; + out_filp: + fput(filp); + out: + return ERR_PTR(err); +} + +static struct task_struct *vperfctr_get_tsk(struct vperfctr *perfctr) +{ + struct task_struct *tsk; + + tsk = current; + if (perfctr != current->thread.perfctr) { + /* this synchronises with vperfctr_unlink() and itself */ + spin_lock(&perfctr->owner_lock); + tsk = perfctr->owner; + if (tsk) + get_task_struct(tsk); + spin_unlock(&perfctr->owner_lock); + if (tsk) { + int ret = ptrace_check_attach(tsk, 0); + if (ret < 0) { + put_task_struct(tsk); + return ERR_PTR(ret); + } + } + } + return tsk; +} + +static void vperfctr_put_tsk(struct task_struct *tsk) +{ + if (tsk && tsk != current) + put_task_struct(tsk); +} + +asmlinkage long sys_vperfctr_control(int fd, + const struct vperfctr_control __user *control) +{ + struct vperfctr *perfctr; + struct task_struct *tsk; + int ret; + + perfctr = fd_get_vperfctr(fd); + if (IS_ERR(perfctr)) + return PTR_ERR(perfctr); + tsk = vperfctr_get_tsk(perfctr); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); + goto out; + } + ret = do_vperfctr_control(perfctr, control, tsk); + vperfctr_put_tsk(tsk); + out: + put_vperfctr(perfctr); + return ret; +} + +asmlinkage long sys_vperfctr_unlink(int fd) +{ + struct vperfctr *perfctr; + struct task_struct *tsk; + int ret; + + perfctr = fd_get_vperfctr(fd); + if (IS_ERR(perfctr)) + return PTR_ERR(perfctr); + tsk = vperfctr_get_tsk(perfctr); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); + goto out; + } + ret = do_vperfctr_unlink(perfctr, tsk); + vperfctr_put_tsk(tsk); + out: + put_vperfctr(perfctr); + return ret; +} + +asmlinkage long sys_vperfctr_iresume(int fd) +{ + struct vperfctr *perfctr; + struct task_struct *tsk; + int ret; + + perfctr = fd_get_vperfctr(fd); + if (IS_ERR(perfctr)) + return PTR_ERR(perfctr); + tsk = vperfctr_get_tsk(perfctr); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); + goto out; + } + ret = do_vperfctr_iresume(perfctr, tsk); + vperfctr_put_tsk(tsk); + out: + put_vperfctr(perfctr); + return ret; +} + +asmlinkage long sys_vperfctr_read(int fd, + struct perfctr_sum_ctrs __user *sum, + struct vperfctr_control __user *control) +{ + struct vperfctr *perfctr; + struct task_struct *tsk; + int ret; + + perfctr = fd_get_vperfctr(fd); + if (IS_ERR(perfctr)) + return PTR_ERR(perfctr); + tsk = vperfctr_get_tsk(perfctr); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); + goto out; + } + ret = do_vperfctr_read(perfctr, sum, control, tsk); + vperfctr_put_tsk(tsk); + out: + put_vperfctr(perfctr); + return ret; +} + +/**************************************************************** + * * + * module_init/exit * + * * + ****************************************************************/ + +int __init vperfctr_init(void) +{ + return vperfctrfs_init(); +} + +void __exit vperfctr_exit(void) +{ + vperfctrfs_exit(); +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/virtual.h 2004-07-13 17:09:34.000000000 -0700 @@ -0,0 +1,13 @@ +/* $Id: virtual.h,v 1.13 2004/05/31 18:18:55 mikpe Exp $ + * Virtual per-process performance counters. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ + +#ifdef CONFIG_PERFCTR_VIRTUAL +extern int vperfctr_init(void); +extern void vperfctr_exit(void); +#else +static inline int vperfctr_init(void) { return 0; } +static inline void vperfctr_exit(void) { } +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/x86.c 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,1628 @@ +/* $Id: x86.c,v 1.141 2004/05/31 18:13:42 mikpe Exp $ + * x86/x86_64 performance-monitoring counters driver. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#include +#include +#include +#include +#include + +#include +#undef MSR_P6_PERFCTR0 +#undef MSR_IA32_MISC_ENABLE +#include +#include +struct hw_interrupt_type; +#include +#include /* cpu_khz */ + +#include "cpumask.h" +#include "x86_tests.h" + +/* Support for lazy evntsel and perfctr MSR updates. */ +struct per_cpu_cache { /* roughly a subset of perfctr_cpu_state */ + union { + unsigned int p5_cesr; + unsigned int id; /* cache owner id */ + } k1; + struct { + /* NOTE: these caches have physical indices, not virtual */ + unsigned int evntsel[18]; + unsigned int escr[0x3E2-0x3A0]; + unsigned int pebs_enable; + unsigned int pebs_matrix_vert; + } control; +} ____cacheline_aligned; +static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache); + +/* Structure for counter snapshots, as 32-bit values. */ +struct perfctr_low_ctrs { + unsigned int tsc; + unsigned int pmc[18]; +}; + +/* Intel P5, Cyrix 6x86MX/MII/III, Centaur WinChip C6/2/3 */ +#define MSR_P5_CESR 0x11 +#define MSR_P5_CTR0 0x12 /* .. 0x13 */ +#define P5_CESR_CPL 0x00C0 +#define P5_CESR_RESERVED (~0x01FF) +#define MII_CESR_RESERVED (~0x05FF) +#define C6_CESR_RESERVED (~0x00FF) + +/* Intel P6, VIA C3 */ +#define MSR_P6_PERFCTR0 0xC1 /* .. 0xC2 */ +#define MSR_P6_EVNTSEL0 0x186 /* .. 0x187 */ +#define P6_EVNTSEL_ENABLE 0x00400000 +#define P6_EVNTSEL_INT 0x00100000 +#define P6_EVNTSEL_CPL 0x00030000 +#define P6_EVNTSEL_RESERVED 0x00280000 +#define VC3_EVNTSEL1_RESERVED (~0x1FF) + +/* AMD K7 */ +#define MSR_K7_EVNTSEL0 0xC0010000 /* .. 0xC0010003 */ +#define MSR_K7_PERFCTR0 0xC0010004 /* .. 0xC0010007 */ + +/* Intel P4, Intel Pentium M */ +#define MSR_IA32_MISC_ENABLE 0x1A0 +#define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7) /* read-only status bit */ +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1<<12) /* read-only status bit */ + +/* Intel P4 */ +#define MSR_P4_PERFCTR0 0x300 /* .. 0x311 */ +#define MSR_P4_CCCR0 0x360 /* .. 0x371 */ +#define MSR_P4_ESCR0 0x3A0 /* .. 0x3E1, with some gaps */ + +#define MSR_P4_PEBS_ENABLE 0x3F1 +#define P4_PE_REPLAY_TAG_BITS 0x00000607 +#define P4_PE_UOP_TAG 0x01000000 +#define P4_PE_RESERVED 0xFEFFF9F8 /* only allow ReplayTagging */ + +#define MSR_P4_PEBS_MATRIX_VERT 0x3F2 +#define P4_PMV_REPLAY_TAG_BITS 0x00000003 +#define P4_PMV_RESERVED 0xFFFFFFFC + +#define P4_CCCR_OVF 0x80000000 +#define P4_CCCR_CASCADE 0x40000000 +#define P4_CCCR_OVF_PMI_T1 0x08000000 +#define P4_CCCR_OVF_PMI_T0 0x04000000 +#define P4_CCCR_FORCE_OVF 0x02000000 +#define P4_CCCR_ACTIVE_THREAD 0x00030000 +#define P4_CCCR_ENABLE 0x00001000 +#define P4_CCCR_ESCR_SELECT(X) (((X) >> 13) & 0x7) +#define P4_CCCR_EXTENDED_CASCADE 0x00000800 +#define P4_CCCR_RESERVED (0x300007FF|P4_CCCR_OVF|P4_CCCR_OVF_PMI_T1) + +#define P4_ESCR_CPL_T1 0x00000003 +#define P4_ESCR_CPL_T0 0x0000000C +#define P4_ESCR_TAG_ENABLE 0x00000010 +#define P4_ESCR_RESERVED (0x80000000) + +#define P4_FAST_RDPMC 0x80000000 +#define P4_MASK_FAST_RDPMC 0x0000001F /* we only need low 5 bits */ + +/* missing from */ +#define cpu_has_msr boot_cpu_has(X86_FEATURE_MSR) + +#define rdmsr_low(msr,low) \ + __asm__ __volatile__("rdmsr" : "=a"(low) : "c"(msr) : "edx") +#define rdpmc_low(ctr,low) \ + __asm__ __volatile__("rdpmc" : "=a"(low) : "c"(ctr) : "edx") + +static void clear_msr_range(unsigned int base, unsigned int n) +{ + unsigned int i; + + for(i = 0; i < n; ++i) + wrmsr(base+i, 0, 0); +} + +static inline void set_in_cr4_local(unsigned int mask) +{ + write_cr4(read_cr4() | mask); +} + +static inline void clear_in_cr4_local(unsigned int mask) +{ + write_cr4(read_cr4() & ~mask); +} + +static unsigned int new_id(void) +{ + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + static unsigned int counter; + int id; + + spin_lock(&lock); + id = ++counter; + spin_unlock(&lock); + return id; +} + +#ifdef CONFIG_X86_LOCAL_APIC +static void perfctr_default_ihandler(unsigned long pc) +{ +} + +static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler; + +asmlinkage void smp_perfctr_interrupt(struct pt_regs *regs) +{ + /* PREEMPT note: invoked via an interrupt gate, which + masks interrupts. We're still on the originating CPU. */ + /* XXX: recursive interrupts? delay the ACK, mask LVTPC, or queue? */ + ack_APIC_irq(); + irq_enter(); + (*perfctr_ihandler)(instruction_pointer(regs)); + irq_exit(); +} + +void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler) +{ + perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler; +} + +#else +#define perfctr_cstatus_has_ictrs(cstatus) 0 +#undef cpu_has_apic +#define cpu_has_apic 0 +#undef apic_write +#define apic_write(reg,vector) do{}while(0) +#endif + +#if defined(CONFIG_SMP) + +static inline void +set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) +{ + state->k1.isuspend_cpu = cpu; +} + +static inline int +is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) +{ + return state->k1.isuspend_cpu == cpu; +} + +static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) +{ + state->k1.isuspend_cpu = NR_CPUS; +} + +#else +static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { } +static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; } +static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { } +#endif + +/**************************************************************** + * * + * Driver procedures. * + * * + ****************************************************************/ + +/* + * Intel P5 family (Pentium, family code 5). + * - One TSC and two 40-bit PMCs. + * - A single 32-bit CESR (MSR 0x11) controls both PMCs. + * CESR has two halves, each controlling one PMC. + * To keep the API reasonably clean, the user puts 16 bits of + * control data in each counter's evntsel; the driver combines + * these to a single 32-bit CESR value. + * - Overflow interrupts are not available. + * - Pentium MMX added the RDPMC instruction. RDPMC has lower + * overhead than RDMSR and it can be used in user-mode code. + * - The MMX events are not symmetric: some events are only available + * for some PMC, and some event codes denote different events + * depending on which PMCs they control. + */ + +/* shared with MII and C6 */ +static int p5_like_check_control(struct perfctr_cpu_state *state, + unsigned int reserved_bits, int is_c6) +{ + unsigned short cesr_half[2]; + unsigned int pmc, evntsel, i; + + if (state->control.nrictrs != 0 || state->control.nractrs > 2) + return -EINVAL; + cesr_half[0] = 0; + cesr_half[1] = 0; + for(i = 0; i < state->control.nractrs; ++i) { + pmc = state->control.pmc_map[i]; + state->pmc[i].map = pmc; + if (pmc > 1 || cesr_half[pmc] != 0) + return -EINVAL; + evntsel = state->control.evntsel[i]; + /* protect reserved bits */ + if ((evntsel & reserved_bits) != 0) + return -EPERM; + /* the CPL field (if defined) must be non-zero */ + if (!is_c6 && !(evntsel & P5_CESR_CPL)) + return -EINVAL; + cesr_half[pmc] = evntsel; + } + state->k1.id = (cesr_half[1] << 16) | cesr_half[0]; + return 0; +} + +static int p5_check_control(struct perfctr_cpu_state *state, int is_global) +{ + return p5_like_check_control(state, P5_CESR_RESERVED, 0); +} + +/* shared with MII but not C6 */ +static void p5_write_control(const struct perfctr_cpu_state *state) +{ + struct per_cpu_cache *cache; + unsigned int cesr; + + cesr = state->k1.id; + if (!cesr) /* no PMC is on (this test doesn't work on C6) */ + return; + cache = &__get_cpu_var(per_cpu_cache); + if (cache->k1.p5_cesr != cesr) { + cache->k1.p5_cesr = cesr; + wrmsr(MSR_P5_CESR, cesr, 0); + } +} + +static void p5_read_counters(const struct perfctr_cpu_state *state, + struct perfctr_low_ctrs *ctrs) +{ + unsigned int cstatus, nrctrs, i; + + /* The P5 doesn't allocate a cache line on a write miss, so do + a dummy read to avoid a write miss here _and_ a read miss + later in our caller. */ + asm("" : : "r"(ctrs->tsc)); + + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + rdtscl(ctrs->tsc); + nrctrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nrctrs; ++i) { + unsigned int pmc = state->pmc[i].map; + rdmsr_low(MSR_P5_CTR0+pmc, ctrs->pmc[i]); + } +} + +/* used by all except pre-MMX P5 */ +static void rdpmc_read_counters(const struct perfctr_cpu_state *state, + struct perfctr_low_ctrs *ctrs) +{ + unsigned int cstatus, nrctrs, i; + + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + rdtscl(ctrs->tsc); + nrctrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nrctrs; ++i) { + unsigned int pmc = state->pmc[i].map; + rdpmc_low(pmc, ctrs->pmc[i]); + } +} + +/* shared with MII and C6 */ +static void p5_clear_counters(void) +{ + clear_msr_range(MSR_P5_CESR, 1+2); +} + +/* + * Cyrix 6x86/MII/III. + * - Same MSR assignments as P5 MMX. Has RDPMC and two 48-bit PMCs. + * - Event codes and CESR formatting as in the plain P5 subset. + * - Many but not all P5 MMX event codes are implemented. + * - Cyrix adds a few more event codes. The event code is widened + * to 7 bits, and Cyrix puts the high bit in CESR bit 10 + * (and CESR bit 26 for PMC1). + */ + +static int mii_check_control(struct perfctr_cpu_state *state, int is_global) +{ + return p5_like_check_control(state, MII_CESR_RESERVED, 0); +} + +/* + * Centaur WinChip C6/2/3. + * - Same MSR assignments as P5 MMX. Has RDPMC and two 40-bit PMCs. + * - CESR is formatted with two halves, like P5. However, there + * are no defined control fields for e.g. CPL selection, and + * there is no defined method for stopping the counters. + * - Only a few event codes are defined. + * - The 64-bit TSC is synthesised from the low 32 bits of the + * two PMCs, and CESR has to be set up appropriately. + * Reprogramming CESR causes RDTSC to yield invalid results. + * (The C6 may also hang in this case, due to C6 erratum I-13.) + * Therefore, using the PMCs on any of these processors requires + * that the TSC is not accessed at all: + * 1. The kernel must be configured or a TSC-less processor, i.e. + * generic 586 or less. + * 2. The "notsc" boot parameter must be passed to the kernel. + * 3. User-space libraries and code must also be configured and + * compiled for a generic 586 or less. + */ + +#if !defined(CONFIG_X86_TSC) +static int c6_check_control(struct perfctr_cpu_state *state, int is_global) +{ + if (state->control.tsc_on) + return -EINVAL; + return p5_like_check_control(state, C6_CESR_RESERVED, 1); +} + +static void c6_write_control(const struct perfctr_cpu_state *state) +{ + struct per_cpu_cache *cache; + unsigned int cesr; + + if (perfctr_cstatus_nractrs(state->cstatus) == 0) /* no PMC is on */ + return; + cache = &__get_cpu_var(per_cpu_cache); + cesr = state->k1.id; + if (cache->k1.p5_cesr != cesr) { + cache->k1.p5_cesr = cesr; + wrmsr(MSR_P5_CESR, cesr, 0); + } +} +#endif + +/* + * Intel P6 family (Pentium Pro, Pentium II, and Pentium III cores, + * and Xeon and Celeron versions of Pentium II and III cores). + * - One TSC and two 40-bit PMCs. + * - One 32-bit EVNTSEL MSR for each PMC. + * - EVNTSEL0 contains a global enable/disable bit. + * That bit is reserved in EVNTSEL1. + * - Each EVNTSEL contains a CPL field. + * - Overflow interrupts are possible, but requires that the + * local APIC is available. Some Mobile P6s have no local APIC. + * - The PMCs cannot be initialised with arbitrary values, since + * wrmsr fills the high bits by sign-extending from bit 31. + * - Most events are symmetric, but a few are not. + */ + +/* shared with K7 */ +static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7) +{ + unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc; + + nractrs = state->control.nractrs; + nrctrs = nractrs + state->control.nrictrs; + if (nrctrs < nractrs || nrctrs > (is_k7 ? 4 : 2)) + return -EINVAL; + + pmc_mask = 0; + for(i = 0; i < nrctrs; ++i) { + pmc = state->control.pmc_map[i]; + state->pmc[i].map = pmc; + if (pmc >= (is_k7 ? 4 : 2) || (pmc_mask & (1<control.evntsel[i]; + /* protect reserved bits */ + if (evntsel & P6_EVNTSEL_RESERVED) + return -EPERM; + /* check ENable bit */ + if (is_k7) { + /* ENable bit must be set in each evntsel */ + if (!(evntsel & P6_EVNTSEL_ENABLE)) + return -EINVAL; + } else { + /* only evntsel[0] has the ENable bit */ + if (evntsel & P6_EVNTSEL_ENABLE) { + if (pmc > 0) + return -EPERM; + } else { + if (pmc == 0) + return -EINVAL; + } + } + /* the CPL field must be non-zero */ + if (!(evntsel & P6_EVNTSEL_CPL)) + return -EINVAL; + /* INT bit must be off for a-mode and on for i-mode counters */ + if (evntsel & P6_EVNTSEL_INT) { + if (i < nractrs) + return -EINVAL; + } else { + if (i >= nractrs) + return -EINVAL; + } + } + state->k1.id = new_id(); + return 0; +} + +static int p6_check_control(struct perfctr_cpu_state *state, int is_global) +{ + return p6_like_check_control(state, 0); +} + +#ifdef CONFIG_X86_LOCAL_APIC +/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */ +/* shared with K7 and P4 */ +static void p6_like_isuspend(struct perfctr_cpu_state *state, + unsigned int msr_evntsel0) +{ + struct per_cpu_cache *cache; + unsigned int cstatus, nrctrs, i; + int cpu; + + cpu = smp_processor_id(); + set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */ + cache = &per_cpu(per_cpu_cache, cpu); + cstatus = state->cstatus; + nrctrs = perfctr_cstatus_nrctrs(cstatus); + for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) { + unsigned int pmc_raw, pmc_idx, now; + pmc_raw = state->pmc[i].map; + /* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7. + We don't need to make it into a parameter. */ + pmc_idx = pmc_raw & P4_MASK_FAST_RDPMC; + cache->control.evntsel[pmc_idx] = 0; + /* On P4 this intensionally also clears the CCCR.OVF flag. */ + wrmsr(msr_evntsel0+pmc_idx, 0, 0); + /* P4 erratum N17 does not apply since we read only low 32 bits. */ + rdpmc_low(pmc_raw, now); + state->pmc[i].sum += now - state->pmc[i].start; + state->pmc[i].start = now; + } + /* cache->k1.id is still == state->k1.id */ +} + +/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */ +/* shared with K7 and P4 */ +static void p6_like_iresume(const struct perfctr_cpu_state *state, + unsigned int msr_evntsel0, + unsigned int msr_perfctr0) +{ + struct per_cpu_cache *cache; + unsigned int cstatus, nrctrs, i; + int cpu; + + cpu = smp_processor_id(); + cache = &per_cpu(per_cpu_cache, cpu); + if (cache->k1.id == state->k1.id) { + cache->k1.id = 0; /* force reload of cleared EVNTSELs */ + if (is_isuspend_cpu(state, cpu)) + return; /* skip reload of PERFCTRs */ + } + cstatus = state->cstatus; + nrctrs = perfctr_cstatus_nrctrs(cstatus); + for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) { + /* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7. + We don't need to make it into a parameter. */ + unsigned int pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC; + /* If the control wasn't ours we must disable the evntsels + before reinitialising the counters, to prevent unexpected + counter increments and missed overflow interrupts. */ + if (cache->control.evntsel[pmc]) { + cache->control.evntsel[pmc] = 0; + wrmsr(msr_evntsel0+pmc, 0, 0); + } + /* P4 erratum N15 does not apply since the CCCR is disabled. */ + wrmsr(msr_perfctr0+pmc, state->pmc[i].start, -1); + } + /* cache->k1.id remains != state->k1.id */ +} + +static void p6_isuspend(struct perfctr_cpu_state *state) +{ + p6_like_isuspend(state, MSR_P6_EVNTSEL0); +} + +static void p6_iresume(const struct perfctr_cpu_state *state) +{ + p6_like_iresume(state, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0); +} +#endif /* CONFIG_X86_LOCAL_APIC */ + +/* shared with K7 and VC3 */ +static void p6_like_write_control(const struct perfctr_cpu_state *state, + unsigned int msr_evntsel0) +{ + struct per_cpu_cache *cache; + unsigned int nrctrs, i; + + cache = &__get_cpu_var(per_cpu_cache); + if (cache->k1.id == state->k1.id) + return; + nrctrs = perfctr_cstatus_nrctrs(state->cstatus); + for(i = 0; i < nrctrs; ++i) { + unsigned int evntsel = state->control.evntsel[i]; + unsigned int pmc = state->pmc[i].map; + if (evntsel != cache->control.evntsel[pmc]) { + cache->control.evntsel[pmc] = evntsel; + wrmsr(msr_evntsel0+pmc, evntsel, 0); + } + } + cache->k1.id = state->k1.id; +} + +/* shared with VC3, Generic*/ +static void p6_write_control(const struct perfctr_cpu_state *state) +{ + p6_like_write_control(state, MSR_P6_EVNTSEL0); +} + +static void p6_clear_counters(void) +{ + clear_msr_range(MSR_P6_EVNTSEL0, 2); + clear_msr_range(MSR_P6_PERFCTR0, 2); +} + +/* + * AMD K7 family (Athlon, Duron). + * - Somewhat similar to the Intel P6 family. + * - Four 48-bit PMCs. + * - Four 32-bit EVNTSEL MSRs with similar layout as in P6. + * - Completely different MSR assignments :-( + * - Fewer countable events defined :-( + * - The events appear to be completely symmetric. + * - The EVNTSEL MSRs are symmetric since each has its own enable bit. + * - Publicly available documentation is incomplete. + * - K7 model 1 does not have a local APIC. AMD Document #22007 + * Revision J hints that it may use debug interrupts instead. + * + * The K8 has the same hardware layout as the K7. It also has + * better documentation and a different set of available events. + */ + +static int k7_check_control(struct perfctr_cpu_state *state, int is_global) +{ + return p6_like_check_control(state, 1); +} + +#ifdef CONFIG_X86_LOCAL_APIC +static void k7_isuspend(struct perfctr_cpu_state *state) +{ + p6_like_isuspend(state, MSR_K7_EVNTSEL0); +} + +static void k7_iresume(const struct perfctr_cpu_state *state) +{ + p6_like_iresume(state, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0); +} +#endif /* CONFIG_X86_LOCAL_APIC */ + +static void k7_write_control(const struct perfctr_cpu_state *state) +{ + p6_like_write_control(state, MSR_K7_EVNTSEL0); +} + +static void k7_clear_counters(void) +{ + clear_msr_range(MSR_K7_EVNTSEL0, 4+4); +} + +/* + * VIA C3 family. + * - A Centaur design somewhat similar to the P6/Celeron. + * - PERFCTR0 is an alias for the TSC, and EVNTSEL0 is read-only. + * - PERFCTR1 is 32 bits wide. + * - EVNTSEL1 has no defined control fields, and there is no + * defined method for stopping the counter. + * - According to testing, the reserved fields in EVNTSEL1 have + * no function. We always fill them with zeroes. + * - Only a few event codes are defined. + * - No local APIC or interrupt-mode support. + * - pmc_map[0] must be 1, if nractrs == 1. + */ +static int vc3_check_control(struct perfctr_cpu_state *state, int is_global) +{ + if (state->control.nrictrs || state->control.nractrs > 1) + return -EINVAL; + if (state->control.nractrs == 1) { + if (state->control.pmc_map[0] != 1) + return -EINVAL; + state->pmc[0].map = 1; + if (state->control.evntsel[0] & VC3_EVNTSEL1_RESERVED) + return -EPERM; + state->k1.id = state->control.evntsel[0]; + } else + state->k1.id = 0; + return 0; +} + +static void vc3_clear_counters(void) +{ + /* Not documented, but seems to be default after boot. */ + wrmsr(MSR_P6_EVNTSEL0+1, 0x00070079, 0); +} + +/* + * Intel Pentium 4. + * Current implementation restrictions: + * - No DS/PEBS support. + * + * Known quirks: + * - OVF_PMI+FORCE_OVF counters must have an ireset value of -1. + * This allows the regular overflow check to also handle FORCE_OVF + * counters. Not having this restriction would lead to MAJOR + * complications in the driver's "detect overflow counters" code. + * There is no loss of functionality since the ireset value doesn't + * affect the counter's PMI rate for FORCE_OVF counters. + * - In experiments with FORCE_OVF counters, and regular OVF_PMI + * counters with small ireset values between -8 and -1, it appears + * that the faulting instruction is subjected to a new PMI before + * it can complete, ad infinitum. This occurs even though the driver + * clears the CCCR (and in testing also the ESCR) and invokes a + * user-space signal handler before restoring the CCCR and resuming + * the instruction. + */ + +/* + * Table 15-4 in the IA32 Volume 3 manual contains a 18x8 entry mapping + * from counter/CCCR number (0-17) and ESCR SELECT value (0-7) to the + * actual ESCR MSR number. This mapping contains some repeated patterns, + * so we can compact it to a 4x8 table of MSR offsets: + * + * 1. CCCRs 16 and 17 are mapped just like CCCRs 13 and 14, respectively. + * Thus, we only consider the 16 CCCRs 0-15. + * 2. The CCCRs are organised in pairs, and both CCCRs in a pair use the + * same mapping. Thus, we only consider the 8 pairs 0-7. + * 3. In each pair of pairs, the second odd-numbered pair has the same domain + * as the first even-numbered pair, and the range is 1+ the range of the + * the first even-numbered pair. For example, CCCR(0) and (1) map ESCR + * SELECT(7) to 0x3A0, and CCCR(2) and (3) map it to 0x3A1. + * The only exception is that pair (7) [CCCRs 14 and 15] does not have + * ESCR SELECT(3) in its domain, like pair (6) [CCCRs 12 and 13] has. + * NOTE: Revisions of IA32 Volume 3 older than #245472-007 had an error + * in this table: CCCRs 12, 13, and 16 had their mappings for ESCR SELECT + * values 2 and 3 swapped. + * 4. All MSR numbers are on the form 0x3??. Instead of storing these as + * 16-bit numbers, the table only stores the 8-bit offsets from 0x300. + */ + +static const unsigned char p4_cccr_escr_map[4][8] = { + /* 0x00 and 0x01 as is, 0x02 and 0x03 are +1 */ + [0x00/4] { [7] 0xA0, + [6] 0xA2, + [2] 0xAA, + [4] 0xAC, + [0] 0xB2, + [1] 0xB4, + [3] 0xB6, + [5] 0xC8, }, + /* 0x04 and 0x05 as is, 0x06 and 0x07 are +1 */ + [0x04/4] { [0] 0xC0, + [2] 0xC2, + [1] 0xC4, }, + /* 0x08 and 0x09 as is, 0x0A and 0x0B are +1 */ + [0x08/4] { [1] 0xA4, + [0] 0xA6, + [5] 0xA8, + [2] 0xAE, + [3] 0xB0, }, + /* 0x0C, 0x0D, and 0x10 as is, + 0x0E, 0x0F, and 0x11 are +1 except [3] is not in the domain */ + [0x0C/4] { [4] 0xB8, + [5] 0xCC, + [6] 0xE0, + [0] 0xBA, + [2] 0xBC, + [3] 0xBE, + [1] 0xCA, }, +}; + +static unsigned int p4_escr_addr(unsigned int pmc, unsigned int cccr_val) +{ + unsigned int escr_select, pair, escr_offset; + + escr_select = P4_CCCR_ESCR_SELECT(cccr_val); + if (pmc > 0x11) + return 0; /* pmc range error */ + if (pmc > 0x0F) + pmc -= 3; /* 0 <= pmc <= 0x0F */ + pair = pmc / 2; /* 0 <= pair <= 7 */ + escr_offset = p4_cccr_escr_map[pair / 2][escr_select]; + if (!escr_offset || (pair == 7 && escr_select == 3)) + return 0; /* ESCR SELECT range error */ + return escr_offset + (pair & 1) + 0x300; +}; + +static int p4_IQ_ESCR_ok; /* only models <= 2 can use IQ_ESCR{0,1} */ +static int p4_is_ht; /* affects several CCCR & ESCR fields */ +static int p4_extended_cascade_ok; /* only models >= 2 can use extended cascading */ + +static int p4_check_control(struct perfctr_cpu_state *state, int is_global) +{ + unsigned int i, nractrs, nrctrs, pmc_mask; + + nractrs = state->control.nractrs; + nrctrs = nractrs + state->control.nrictrs; + if (nrctrs < nractrs || nrctrs > 18) + return -EINVAL; + + pmc_mask = 0; + for(i = 0; i < nrctrs; ++i) { + unsigned int pmc, cccr_val, escr_val, escr_addr; + /* check that pmc_map[] is well-defined; + pmc_map[i] is what we pass to RDPMC, the PMC itself + is extracted by masking off the FAST_RDPMC flag */ + pmc = state->control.pmc_map[i] & ~P4_FAST_RDPMC; + state->pmc[i].map = state->control.pmc_map[i]; + if (pmc >= 18 || (pmc_mask & (1<control.evntsel[i]; + if (cccr_val & P4_CCCR_RESERVED) + return -EPERM; + if (cccr_val & P4_CCCR_EXTENDED_CASCADE) { + if (!p4_extended_cascade_ok) + return -EPERM; + if (!(pmc == 12 || pmc >= 15)) + return -EPERM; + } + if ((cccr_val & P4_CCCR_ACTIVE_THREAD) != P4_CCCR_ACTIVE_THREAD && !p4_is_ht) + return -EINVAL; + if (!(cccr_val & (P4_CCCR_ENABLE | P4_CCCR_CASCADE | P4_CCCR_EXTENDED_CASCADE))) + return -EINVAL; + if (cccr_val & P4_CCCR_OVF_PMI_T0) { + if (i < nractrs) + return -EINVAL; + if ((cccr_val & P4_CCCR_FORCE_OVF) && + state->control.ireset[i] != -1) + return -EINVAL; + } else { + if (i >= nractrs) + return -EINVAL; + } + /* check ESCR contents */ + escr_val = state->control.p4.escr[i]; + if (escr_val & P4_ESCR_RESERVED) + return -EPERM; + if ((escr_val & P4_ESCR_CPL_T1) && (!p4_is_ht || !is_global)) + return -EINVAL; + /* compute and cache ESCR address */ + escr_addr = p4_escr_addr(pmc, cccr_val); + if (!escr_addr) + return -EINVAL; /* ESCR SELECT range error */ + /* IQ_ESCR0 and IQ_ESCR1 only exist in models <= 2 */ + if ((escr_addr & ~0x001) == 0x3BA && !p4_IQ_ESCR_ok) + return -EINVAL; + /* XXX: Two counters could map to the same ESCR. Should we + check that they use the same ESCR value? */ + state->p4_escr_map[i] = escr_addr - MSR_P4_ESCR0; + } + /* check ReplayTagging control (PEBS_ENABLE and PEBS_MATRIX_VERT) */ + if (state->control.p4.pebs_enable) { + if (!nrctrs) + return -EPERM; + if (state->control.p4.pebs_enable & P4_PE_RESERVED) + return -EPERM; + if (!(state->control.p4.pebs_enable & P4_PE_UOP_TAG)) + return -EINVAL; + if (!(state->control.p4.pebs_enable & P4_PE_REPLAY_TAG_BITS)) + return -EINVAL; + if (state->control.p4.pebs_matrix_vert & P4_PMV_RESERVED) + return -EPERM; + if (!(state->control.p4.pebs_matrix_vert & P4_PMV_REPLAY_TAG_BITS)) + return -EINVAL; + } else if (state->control.p4.pebs_matrix_vert) + return -EPERM; + state->k1.id = new_id(); + return 0; +} + +#ifdef CONFIG_X86_LOCAL_APIC +static void p4_isuspend(struct perfctr_cpu_state *state) +{ + return p6_like_isuspend(state, MSR_P4_CCCR0); +} + +static void p4_iresume(const struct perfctr_cpu_state *state) +{ + return p6_like_iresume(state, MSR_P4_CCCR0, MSR_P4_PERFCTR0); +} +#endif /* CONFIG_X86_LOCAL_APIC */ + +static void p4_write_control(const struct perfctr_cpu_state *state) +{ + struct per_cpu_cache *cache; + unsigned int nrctrs, i; + + cache = &__get_cpu_var(per_cpu_cache); + if (cache->k1.id == state->k1.id) + return; + nrctrs = perfctr_cstatus_nrctrs(state->cstatus); + for(i = 0; i < nrctrs; ++i) { + unsigned int escr_val, escr_off, cccr_val, pmc; + escr_val = state->control.p4.escr[i]; + escr_off = state->p4_escr_map[i]; + if (escr_val != cache->control.escr[escr_off]) { + cache->control.escr[escr_off] = escr_val; + wrmsr(MSR_P4_ESCR0+escr_off, escr_val, 0); + } + cccr_val = state->control.evntsel[i]; + pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC; + if (cccr_val != cache->control.evntsel[pmc]) { + cache->control.evntsel[pmc] = cccr_val; + wrmsr(MSR_P4_CCCR0+pmc, cccr_val, 0); + } + } + if (state->control.p4.pebs_enable != cache->control.pebs_enable) { + cache->control.pebs_enable = state->control.p4.pebs_enable; + wrmsr(MSR_P4_PEBS_ENABLE, state->control.p4.pebs_enable, 0); + } + if (state->control.p4.pebs_matrix_vert != cache->control.pebs_matrix_vert) { + cache->control.pebs_matrix_vert = state->control.p4.pebs_matrix_vert; + wrmsr(MSR_P4_PEBS_MATRIX_VERT, state->control.p4.pebs_matrix_vert, 0); + } + cache->k1.id = state->k1.id; +} + +static void p4_clear_counters(void) +{ + /* MSR 0x3F0 seems to have a default value of 0xFC00, but current + docs doesn't fully define it, so leave it alone for now. */ + /* clear PEBS_ENABLE and PEBS_MATRIX_VERT; they handle both PEBS + and ReplayTagging, and should exist even if PEBS is disabled */ + clear_msr_range(0x3F1, 2); + clear_msr_range(0x3A0, 31); + clear_msr_range(0x3C0, 6); + clear_msr_range(0x3C8, 6); + clear_msr_range(0x3E0, 2); + clear_msr_range(MSR_P4_CCCR0, 18); + clear_msr_range(MSR_P4_PERFCTR0, 18); +} + +/* + * Generic driver for any x86 with a working TSC. + */ + +static int generic_check_control(struct perfctr_cpu_state *state, int is_global) +{ + if (state->control.nractrs || state->control.nrictrs) + return -EINVAL; + return 0; +} + +static void generic_clear_counters(void) +{ +} + +/* + * Driver methods, internal and exported. + * + * Frequently called functions (write_control, read_counters, + * isuspend and iresume) are back-patched to invoke the correct + * processor-specific methods directly, thereby saving the + * overheads of indirect function calls. + * + * Backpatchable call sites must have been "finalised" after + * initialisation. The reason for this is that unsynchronised code + * modification doesn't work in multiprocessor systems, due to + * Intel P6 errata. Consequently, all backpatchable call sites + * must be known and local to this file. + * + * Backpatchable calls must initially be to 'noinline' stubs. + * Otherwise the compiler may inline the stubs, which breaks + * redirect_call() and finalise_backpatching(). + */ + +static int redirect_call_disable; + +static noinline void redirect_call(void *ra, void *to) +{ + /* XXX: make this function __init later */ + if (redirect_call_disable) + printk(KERN_ERR __FILE__ ":%s: unresolved call to %p at %p\n", + __FUNCTION__, to, ra); + /* we can only redirect `call near relative' instructions */ + if (*((unsigned char*)ra - 5) != 0xE8) { + printk(KERN_WARNING __FILE__ ":%s: unable to redirect caller %p to %p\n", + __FUNCTION__, ra, to); + return; + } + *(int*)((char*)ra - 4) = (char*)to - (char*)ra; +} + +static void (*write_control)(const struct perfctr_cpu_state*); +static noinline void perfctr_cpu_write_control(const struct perfctr_cpu_state *state) +{ + redirect_call(__builtin_return_address(0), write_control); + return write_control(state); +} + +static void (*read_counters)(const struct perfctr_cpu_state*, + struct perfctr_low_ctrs*); +static noinline void perfctr_cpu_read_counters(const struct perfctr_cpu_state *state, + struct perfctr_low_ctrs *ctrs) +{ + redirect_call(__builtin_return_address(0), read_counters); + return read_counters(state, ctrs); +} + +#ifdef CONFIG_X86_LOCAL_APIC +static void (*cpu_isuspend)(struct perfctr_cpu_state*); +static noinline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) +{ + redirect_call(__builtin_return_address(0), cpu_isuspend); + return cpu_isuspend(state); +} + +static void (*cpu_iresume)(const struct perfctr_cpu_state*); +static noinline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) +{ + redirect_call(__builtin_return_address(0), cpu_iresume); + return cpu_iresume(state); +} + +/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to + bypass internal caching and force a reload if the I-mode PMCs. */ +void perfctr_cpu_ireload(struct perfctr_cpu_state *state) +{ +#ifdef CONFIG_SMP + clear_isuspend_cpu(state); +#else + __get_cpu_var(per_cpu_cache).k1.id = 0; +#endif +} + +/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */ +static int lvtpc_reinit_needed; +unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state) +{ + unsigned int cstatus, nrctrs, pmc, pmc_mask; + + cstatus = state->cstatus; + pmc = perfctr_cstatus_nractrs(cstatus); + nrctrs = perfctr_cstatus_nrctrs(cstatus); + + for(pmc_mask = 0; pmc < nrctrs; ++pmc) { + if ((int)state->pmc[pmc].start >= 0) { /* XXX: ">" ? */ + /* XXX: "+=" to correct for overshots */ + state->pmc[pmc].start = state->control.ireset[pmc]; + pmc_mask |= (1 << pmc); + /* On a P4 we should now clear the OVF flag in the + counter's CCCR. However, p4_isuspend() already + did that as a side-effect of clearing the CCCR + in order to stop the i-mode counters. */ + } + } + if (lvtpc_reinit_needed) + apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR); + return pmc_mask; +} + +static inline int check_ireset(const struct perfctr_cpu_state *state) +{ + unsigned int nrctrs, i; + + i = state->control.nractrs; + nrctrs = i + state->control.nrictrs; + for(; i < nrctrs; ++i) + if (state->control.ireset[i] >= 0) + return -EINVAL; + return 0; +} + +static inline void setup_imode_start_values(struct perfctr_cpu_state *state) +{ + unsigned int cstatus, nrctrs, i; + + cstatus = state->cstatus; + nrctrs = perfctr_cstatus_nrctrs(cstatus); + for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) + state->pmc[i].start = state->control.ireset[i]; +} + +#else /* CONFIG_X86_LOCAL_APIC */ +static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { } +static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { } +static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; } +static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { } +#endif /* CONFIG_X86_LOCAL_APIC */ + +static int (*check_control)(struct perfctr_cpu_state*, int); +int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global) +{ + int err; + + clear_isuspend_cpu(state); + state->cstatus = 0; + + /* disallow i-mode counters if we cannot catch the interrupts */ + if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) + && state->control.nrictrs) + return -EPERM; + + err = check_control(state, is_global); + if (err < 0) + return err; + err = check_ireset(state); + if (err < 0) + return err; + state->cstatus = perfctr_mk_cstatus(state->control.tsc_on, + state->control.nractrs, + state->control.nrictrs); + setup_imode_start_values(state); + return 0; +} + +void perfctr_cpu_suspend(struct perfctr_cpu_state *state) +{ + unsigned int i, cstatus, nractrs; + struct perfctr_low_ctrs now; + + if (perfctr_cstatus_has_ictrs(state->cstatus)) + perfctr_cpu_isuspend(state); + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + state->tsc_sum += now.tsc - state->tsc_start; + nractrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nractrs; ++i) + state->pmc[i].sum += now.pmc[i] - state->pmc[i].start; + /* perfctr_cpu_disable_rdpmc(); */ /* not for x86 */ +} + +void perfctr_cpu_resume(struct perfctr_cpu_state *state) +{ + if (perfctr_cstatus_has_ictrs(state->cstatus)) + perfctr_cpu_iresume(state); + /* perfctr_cpu_enable_rdpmc(); */ /* not for x86 or global-mode */ + perfctr_cpu_write_control(state); + //perfctr_cpu_read_counters(state, &state->start); + { + struct perfctr_low_ctrs now; + unsigned int i, cstatus, nrctrs; + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) + state->tsc_start = now.tsc; + nrctrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nrctrs; ++i) + state->pmc[i].start = now.pmc[i]; + } + /* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */ +} + +void perfctr_cpu_sample(struct perfctr_cpu_state *state) +{ + unsigned int i, cstatus, nractrs; + struct perfctr_low_ctrs now; + + perfctr_cpu_read_counters(state, &now); + cstatus = state->cstatus; + if (perfctr_cstatus_has_tsc(cstatus)) { + state->tsc_sum += now.tsc - state->tsc_start; + state->tsc_start = now.tsc; + } + nractrs = perfctr_cstatus_nractrs(cstatus); + for(i = 0; i < nractrs; ++i) { + state->pmc[i].sum += now.pmc[i] - state->pmc[i].start; + state->pmc[i].start = now.pmc[i]; + } +} + +static void (*clear_counters)(void); +static void perfctr_cpu_clear_counters(void) +{ + return clear_counters(); +} + +/**************************************************************** + * * + * Processor detection and initialisation procedures. * + * * + ****************************************************************/ + +static inline void clear_perfctr_cpus_forbidden_mask(void) +{ +#if !defined(perfctr_cpus_forbidden_mask) + cpus_clear(perfctr_cpus_forbidden_mask); +#endif +} + +static inline void set_perfctr_cpus_forbidden_mask(cpumask_t mask) +{ +#if !defined(perfctr_cpus_forbidden_mask) + perfctr_cpus_forbidden_mask = mask; +#endif +} + +/* see comment above at redirect_call() */ +static void __init finalise_backpatching(void) +{ + struct per_cpu_cache *cache; + struct perfctr_cpu_state state; + cpumask_t old_mask; + + old_mask = perfctr_cpus_forbidden_mask; + clear_perfctr_cpus_forbidden_mask(); + + cache = &__get_cpu_var(per_cpu_cache); + memset(cache, 0, sizeof *cache); + memset(&state, 0, sizeof state); + state.cstatus = + (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) + ? perfctr_mk_cstatus(0, 0, 1) + : 0; + perfctr_cpu_sample(&state); + perfctr_cpu_resume(&state); + perfctr_cpu_suspend(&state); + + set_perfctr_cpus_forbidden_mask(old_mask); + + redirect_call_disable = 1; +} + +#ifdef CONFIG_SMP + +cpumask_t perfctr_cpus_forbidden_mask; + +static void __init p4_ht_mask_setup_cpu(void *forbidden) +{ + unsigned int local_apic_physical_id = cpuid_ebx(1) >> 24; + unsigned int logical_processor_id = local_apic_physical_id & 1; + if (logical_processor_id != 0) + /* We rely on cpu_set() being atomic! */ + cpu_set(smp_processor_id(), *(cpumask_t*)forbidden); +} + +static int __init p4_ht_smp_init(void) +{ + cpumask_t forbidden; + unsigned int cpu; + + cpus_clear(forbidden); + smp_call_function(p4_ht_mask_setup_cpu, &forbidden, 1, 1); + p4_ht_mask_setup_cpu(&forbidden); + if (cpus_empty(forbidden)) + return 0; + perfctr_cpus_forbidden_mask = forbidden; + printk(KERN_INFO "perfctr/x86.c: hyper-threaded P4s detected:" + " restricting access for CPUs"); + for(cpu = 0; cpu < NR_CPUS; ++cpu) + if (cpu_isset(cpu, forbidden)) + printk(" %u", cpu); + printk("\n"); + return 0; +} +#else /* SMP */ +#define p4_ht_smp_init() (0) +#endif /* SMP */ + +static int __init p4_ht_init(void) +{ + unsigned int nr_siblings; + + if (!cpu_has_ht) + return 0; + nr_siblings = (cpuid_ebx(1) >> 16) & 0xFF; + if (nr_siblings > 2) { + printk(KERN_WARNING "perfctr/x86.c: hyper-threaded P4s detected:" + " unsupported number of siblings: %u -- bailing out\n", + nr_siblings); + return -ENODEV; + } + if (nr_siblings < 2) + return 0; + p4_is_ht = 1; /* needed even in a UP kernel */ + return p4_ht_smp_init(); +} + +static int __init intel_init(void) +{ + static char p5_name[] __initdata = "Intel P5"; + static char p6_name[] __initdata = "Intel P6"; + static char p4_name[] __initdata = "Intel P4"; + unsigned int misc_enable; + + if (!cpu_has_tsc) + return -ENODEV; + switch (current_cpu_data.x86) { + case 5: + if (cpu_has_mmx) { + read_counters = rdpmc_read_counters; + + /* Avoid Pentium Erratum 74. */ + if (current_cpu_data.x86_model == 4 && + (current_cpu_data.x86_mask == 4 || + (current_cpu_data.x86_mask == 3 && + ((cpuid_eax(1) >> 12) & 0x3) == 1))) + perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC; + } else { + perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC; + read_counters = p5_read_counters; + } + perfctr_set_tests_type(PTT_P5); + perfctr_cpu_name = p5_name; + write_control = p5_write_control; + check_control = p5_check_control; + clear_counters = p5_clear_counters; + return 0; + case 6: + if (current_cpu_data.x86_model == 9 || + current_cpu_data.x86_model == 13) { /* Pentium M */ + /* Pentium M added the MISC_ENABLE MSR from P4. */ + rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable); + if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL)) + break; + /* Erratum Y3 probably does not apply since we + read only the low 32 bits. */ + } else if (current_cpu_data.x86_model < 3) { /* Pentium Pro */ + /* Avoid Pentium Pro Erratum 26. */ + if (current_cpu_data.x86_mask < 9) + perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC; + } + perfctr_set_tests_type(PTT_P6); + perfctr_cpu_name = p6_name; + read_counters = rdpmc_read_counters; + write_control = p6_write_control; + check_control = p6_check_control; + clear_counters = p6_clear_counters; +#ifdef CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT; + cpu_isuspend = p6_isuspend; + cpu_iresume = p6_iresume; + /* P-M apparently inherited P4's LVTPC auto-masking :-( */ + if (current_cpu_data.x86_model == 9 || + current_cpu_data.x86_model == 13) + lvtpc_reinit_needed = 1; + } +#endif + return 0; + case 15: /* Pentium 4 */ + rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable); + if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL)) + break; + if (p4_ht_init() != 0) + break; + if (current_cpu_data.x86_model <= 2) + p4_IQ_ESCR_ok = 1; + if (current_cpu_data.x86_model >= 2) + p4_extended_cascade_ok = 1; + perfctr_set_tests_type(PTT_P4); + perfctr_cpu_name = p4_name; + read_counters = rdpmc_read_counters; + write_control = p4_write_control; + check_control = p4_check_control; + clear_counters = p4_clear_counters; +#ifdef CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT; + cpu_isuspend = p4_isuspend; + cpu_iresume = p4_iresume; + lvtpc_reinit_needed = 1; + } +#endif + return 0; + } + return -ENODEV; +} + +static int __init amd_init(void) +{ + static char amd_name[] __initdata = "AMD K7/K8"; + + if (!cpu_has_tsc) + return -ENODEV; + switch (current_cpu_data.x86) { + case 6: /* K7 */ + case 15: /* K8. Like a K7 with a different event set. */ + break; + default: + return -ENODEV; + } + perfctr_set_tests_type(PTT_AMD); + perfctr_cpu_name = amd_name; + read_counters = rdpmc_read_counters; + write_control = k7_write_control; + check_control = k7_check_control; + clear_counters = k7_clear_counters; +#ifdef CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT; + cpu_isuspend = k7_isuspend; + cpu_iresume = k7_iresume; + } +#endif + return 0; +} + +static int __init cyrix_init(void) +{ + static char mii_name[] __initdata = "Cyrix 6x86MX/MII/III"; + if (!cpu_has_tsc) + return -ENODEV; + switch (current_cpu_data.x86) { + case 6: /* 6x86MX, MII, or III */ + perfctr_set_tests_type(PTT_P5); + perfctr_cpu_name = mii_name; + read_counters = rdpmc_read_counters; + write_control = p5_write_control; + check_control = mii_check_control; + clear_counters = p5_clear_counters; + return 0; + } + return -ENODEV; +} + +static int __init centaur_init(void) +{ +#if !defined(CONFIG_X86_TSC) + static char winchip_name[] __initdata = "WinChip C6/2/3"; +#endif + static char vc3_name[] __initdata = "VIA C3"; + switch (current_cpu_data.x86) { +#if !defined(CONFIG_X86_TSC) + case 5: + switch (current_cpu_data.x86_model) { + case 4: /* WinChip C6 */ + case 8: /* WinChip 2, 2A, or 2B */ + case 9: /* WinChip 3, a 2A with larger cache and lower voltage */ + break; + default: + return -ENODEV; + } + perfctr_set_tests_type(PTT_WINCHIP); + perfctr_cpu_name = winchip_name; + /* + * TSC must be inaccessible for perfctrs to work. + */ + if (!(read_cr4() & X86_CR4_TSD) || cpu_has_tsc) + return -ENODEV; + perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDTSC; + read_counters = rdpmc_read_counters; + write_control = c6_write_control; + check_control = c6_check_control; + clear_counters = p5_clear_counters; + return 0; +#endif + case 6: /* VIA C3 */ + if (!cpu_has_tsc) + return -ENODEV; + switch (current_cpu_data.x86_model) { + case 6: /* Cyrix III */ + case 7: /* Samuel 2, Ezra (steppings >= 8) */ + case 8: /* Ezra-T */ + case 9: /* Antaur/Nehemiah */ + break; + default: + return -ENODEV; + } + perfctr_set_tests_type(PTT_VC3); + perfctr_cpu_name = vc3_name; + read_counters = rdpmc_read_counters; + write_control = p6_write_control; + check_control = vc3_check_control; + clear_counters = vc3_clear_counters; + return 0; + } + return -ENODEV; +} + +static int __init generic_init(void) +{ + static char generic_name[] __initdata = "Generic x86 with TSC"; + if (!cpu_has_tsc) + return -ENODEV; + perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC; + perfctr_set_tests_type(PTT_GENERIC); + perfctr_cpu_name = generic_name; + check_control = generic_check_control; + write_control = p6_write_control; + read_counters = rdpmc_read_counters; + clear_counters = generic_clear_counters; + return 0; +} + +static void perfctr_cpu_invalidate_cache(void) +{ + /* + * per_cpu_cache[] is initialised to contain "impossible" + * evntsel values guaranteed to differ from anything accepted + * by perfctr_cpu_update_control(). + * All-bits-one works for all currently supported processors. + * The memset also sets the ids to -1, which is intentional. + */ + memset(&__get_cpu_var(per_cpu_cache), ~0, + sizeof(struct per_cpu_cache)); +} + +static void perfctr_cpu_init_one(void *ignore) +{ + /* PREEMPT note: when called via smp_call_function(), + this is in IRQ context with preemption disabled. */ + perfctr_cpu_clear_counters(); + perfctr_cpu_invalidate_cache(); + if (cpu_has_apic) + apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR); + if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC) + set_in_cr4_local(X86_CR4_PCE); +} + +static void perfctr_cpu_exit_one(void *ignore) +{ + /* PREEMPT note: when called via smp_call_function(), + this is in IRQ context with preemption disabled. */ + perfctr_cpu_clear_counters(); + perfctr_cpu_invalidate_cache(); + if (cpu_has_apic) + apic_write(APIC_LVTPC, APIC_DM_NMI | APIC_LVT_MASKED); + if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC) + clear_in_cr4_local(X86_CR4_PCE); +} + +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) + +static void perfctr_pm_suspend(void) +{ + /* XXX: clear control registers */ + printk("perfctr/x86: PM suspend\n"); +} + +static void perfctr_pm_resume(void) +{ + /* XXX: reload control registers */ + printk("perfctr/x86: PM resume\n"); +} + +#include + +static int perfctr_device_suspend(struct sys_device *dev, u32 state) +{ + perfctr_pm_suspend(); + return 0; +} + +static int perfctr_device_resume(struct sys_device *dev) +{ + perfctr_pm_resume(); + return 0; +} + +static struct sysdev_class perfctr_sysclass = { + set_kset_name("perfctr"), + .resume = perfctr_device_resume, + .suspend = perfctr_device_suspend, +}; + +static struct sys_device device_perfctr = { + .id = 0, + .cls = &perfctr_sysclass, +}; + +static void x86_pm_init(void) +{ + if (sysdev_class_register(&perfctr_sysclass) == 0) + sysdev_register(&device_perfctr); +} + +static void x86_pm_exit(void) +{ + sysdev_unregister(&device_perfctr); + sysdev_class_unregister(&perfctr_sysclass); +} + +#else + +static inline void x86_pm_init(void) { } +static inline void x86_pm_exit(void) { } + +#endif /* CONFIG_X86_LOCAL_APIC && CONFIG_PM */ + +#if !defined(CONFIG_X86_LOCAL_APIC) +static inline int reserve_lapic_nmi(void) { return 0; } +static inline void release_lapic_nmi(void) { } +#endif + +static void do_init_tests(void) +{ +#ifdef CONFIG_PERFCTR_INIT_TESTS + if (reserve_lapic_nmi() >= 0) { + perfctr_x86_init_tests(); + release_lapic_nmi(); + } +#endif +} + +static int init_done; + +int __init perfctr_cpu_init(void) +{ + int err = -ENODEV; + + preempt_disable(); + + /* RDPMC and RDTSC are on by default. They will be disabled + by the init procedures if necessary. */ + perfctr_info.cpu_features = PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_RDTSC; + + if (cpu_has_msr) { + switch (current_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + err = intel_init(); + break; + case X86_VENDOR_AMD: + err = amd_init(); + break; + case X86_VENDOR_CYRIX: + err = cyrix_init(); + break; + case X86_VENDOR_CENTAUR: + err = centaur_init(); + } + } + if (err) { + err = generic_init(); /* last resort */ + if (err) + goto out; + } + do_init_tests(); + finalise_backpatching(); + + perfctr_info.cpu_khz = cpu_khz; + perfctr_info.tsc_to_cpu_mult = 1; + init_done = 1; + + out: + preempt_enable(); + return err; +} + +void __exit perfctr_cpu_exit(void) +{ +} + +/**************************************************************** + * * + * Hardware reservation. * + * * + ****************************************************************/ + +static DECLARE_MUTEX(mutex); +static const char *current_service = 0; + +const char *perfctr_cpu_reserve(const char *service) +{ + const char *ret; + + if (!init_done) + return "unsupported hardware"; + down(&mutex); + ret = current_service; + if (ret) + goto out_up; + ret = "unknown driver (oprofile?)"; + if (reserve_lapic_nmi() < 0) + goto out_up; + current_service = service; + if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC) + mmu_cr4_features |= X86_CR4_PCE; + on_each_cpu(perfctr_cpu_init_one, NULL, 1, 1); + perfctr_cpu_set_ihandler(NULL); + x86_pm_init(); + ret = NULL; + out_up: + up(&mutex); + return ret; +} + +void perfctr_cpu_release(const char *service) +{ + down(&mutex); + if (service != current_service) { + printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n", + __FUNCTION__, service, current_service); + goto out_up; + } + /* power down the counters */ + if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC) + mmu_cr4_features &= ~X86_CR4_PCE; + on_each_cpu(perfctr_cpu_exit_one, NULL, 1, 1); + perfctr_cpu_set_ihandler(NULL); + x86_pm_exit(); + current_service = 0; + release_lapic_nmi(); + out_up: + up(&mutex); +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/x86_tests.c 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,280 @@ +/* $Id: x86_tests.c,v 1.28 2004/05/23 23:22:44 mikpe Exp $ + * Performance-monitoring counters driver. + * Optional x86/x86_64-specific init-time tests. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#include +#include +#include +#include +#include +#include +#undef MSR_P6_PERFCTR0 +#undef MSR_P4_IQ_CCCR0 +#undef MSR_P4_CRU_ESCR0 +#include +#include +#include /* cpu_khz */ +#include "x86_tests.h" + +#define MSR_P5_CESR 0x11 +#define MSR_P5_CTR0 0x12 +#define P5_CESR_VAL (0x16 | (3<<6)) +#define MSR_P6_PERFCTR0 0xC1 +#define MSR_P6_EVNTSEL0 0x186 +#define P6_EVNTSEL0_VAL (0xC0 | (3<<16) | (1<<22)) +#define MSR_K7_EVNTSEL0 0xC0010000 +#define MSR_K7_PERFCTR0 0xC0010004 +#define K7_EVNTSEL0_VAL (0xC0 | (3<<16) | (1<<22)) +#define VC3_EVNTSEL1_VAL 0xC0 +#define MSR_P4_IQ_COUNTER0 0x30C +#define MSR_P4_IQ_CCCR0 0x36C +#define MSR_P4_CRU_ESCR0 0x3B8 +#define P4_CRU_ESCR0_VAL ((2<<25) | (1<<9) | (0x3<<2)) +#define P4_IQ_CCCR0_VAL ((0x3<<16) | (4<<13) | (1<<12)) + +#define NITER 64 +#define X2(S) S";"S +#define X8(S) X2(X2(X2(S))) + +#ifdef __x86_64__ +#define CR4MOV "movq" +#else +#define CR4MOV "movl" +#endif + +#ifndef CONFIG_X86_LOCAL_APIC +#undef apic_write +#define apic_write(reg,vector) do{}while(0) +#endif + +static void __init do_rdpmc(unsigned pmc, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("rdpmc") : : "c"(pmc) : "eax", "edx"); +} + +static void __init do_rdmsr(unsigned msr, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("rdmsr") : : "c"(msr) : "eax", "edx"); +} + +static void __init do_wrmsr(unsigned msr, unsigned data) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("wrmsr") : : "c"(msr), "a"(data), "d"(0)); +} + +static void __init do_rdcr4(unsigned unused1, unsigned unused2) +{ + unsigned i; + unsigned long dummy; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8(CR4MOV" %%cr4,%0") : "=r"(dummy)); +} + +static void __init do_wrcr4(unsigned cr4, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8(CR4MOV" %0,%%cr4") : : "r"((long)cr4)); +} + +static void __init do_rdtsc(unsigned unused1, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__(X8("rdtsc") : : : "eax", "edx"); +} + +static void __init do_wrlvtpc(unsigned val, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) { + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + apic_write(APIC_LVTPC, val); + } +} + +static void __init do_empty_loop(unsigned unused1, unsigned unused2) +{ + unsigned i; + for(i = 0; i < NITER/8; ++i) + __asm__ __volatile__("" : : "c"(0)); +} + +static unsigned __init run(void (*doit)(unsigned, unsigned), + unsigned arg1, unsigned arg2) +{ + unsigned start, dummy, stop; + rdtsc(start, dummy); + (*doit)(arg1, arg2); /* should take < 2^32 cycles to complete */ + rdtsc(stop, dummy); + return stop - start; +} + +static void __init init_tests_message(void) +{ + printk(KERN_INFO "Please email the following PERFCTR INIT lines " + "to mikpe@csd.uu.se\n" + KERN_INFO "To remove this message, rebuild the driver " + "with CONFIG_PERFCTR_INIT_TESTS=n\n"); + printk(KERN_INFO "PERFCTR INIT: vendor %u, family %u, model %u, stepping %u, clock %u kHz\n", + current_cpu_data.x86_vendor, + current_cpu_data.x86, + current_cpu_data.x86_model, + current_cpu_data.x86_mask, + (unsigned int)cpu_khz); +} + +static void __init +measure_overheads(unsigned msr_evntsel0, unsigned evntsel0, unsigned msr_perfctr0, + unsigned msr_cccr, unsigned cccr_val) +{ + int i; + unsigned int loop, ticks[12]; + const char *name[12]; + + if (msr_evntsel0) + wrmsr(msr_evntsel0, 0, 0); + if (msr_cccr) + wrmsr(msr_cccr, 0, 0); + + name[0] = "rdtsc"; + ticks[0] = run(do_rdtsc, 0, 0); + name[1] = "rdpmc"; + ticks[1] = (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC) + ? run(do_rdpmc,1,0) : 0; + name[2] = "rdmsr (counter)"; + ticks[2] = msr_perfctr0 ? run(do_rdmsr, msr_perfctr0, 0) : 0; + name[3] = msr_cccr ? "rdmsr (escr)" : "rdmsr (evntsel)"; + ticks[3] = msr_evntsel0 ? run(do_rdmsr, msr_evntsel0, 0) : 0; + name[4] = "wrmsr (counter)"; + ticks[4] = msr_perfctr0 ? run(do_wrmsr, msr_perfctr0, 0) : 0; + name[5] = msr_cccr ? "wrmsr (escr)" : "wrmsr (evntsel)"; + ticks[5] = msr_evntsel0 ? run(do_wrmsr, msr_evntsel0, evntsel0) : 0; + name[6] = "read cr4"; + ticks[6] = run(do_rdcr4, 0, 0); + name[7] = "write cr4"; + ticks[7] = run(do_wrcr4, read_cr4(), 0); + name[8] = "rdpmc (fast)"; + ticks[8] = msr_cccr ? run(do_rdpmc, 0x80000001, 0) : 0; + name[9] = "rdmsr (cccr)"; + ticks[9] = msr_cccr ? run(do_rdmsr, msr_cccr, 0) : 0; + name[10] = "wrmsr (cccr)"; + ticks[10] = msr_cccr ? run(do_wrmsr, msr_cccr, cccr_val) : 0; + name[11] = "write LVTPC"; + ticks[11] = (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT) + ? run(do_wrlvtpc, APIC_DM_NMI|APIC_LVT_MASKED, 0) : 0; + + loop = run(do_empty_loop, 0, 0); + + if (msr_evntsel0) + wrmsr(msr_evntsel0, 0, 0); + if (msr_cccr) + wrmsr(msr_cccr, 0, 0); + + init_tests_message(); + printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER); + printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop); + for(i = 0; i < ARRAY_SIZE(ticks); ++i) { + unsigned int x; + if (!ticks[i]) + continue; + x = ((ticks[i] - loop) * 10) / NITER; + printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n", + name[i], x/10, x%10, ticks[i]); + } +} + +#ifndef __x86_64__ +static inline void perfctr_p5_init_tests(void) +{ + measure_overheads(MSR_P5_CESR, P5_CESR_VAL, MSR_P5_CTR0, 0, 0); +} + +static inline void perfctr_p6_init_tests(void) +{ + measure_overheads(MSR_P6_EVNTSEL0, P6_EVNTSEL0_VAL, MSR_P6_PERFCTR0, 0, 0); +} + +#if !defined(CONFIG_X86_TSC) +static inline void perfctr_c6_init_tests(void) +{ + unsigned int cesr, dummy; + + rdmsr(MSR_P5_CESR, cesr, dummy); + init_tests_message(); + printk(KERN_INFO "PERFCTR INIT: boot CESR == %#08x\n", cesr); +} +#endif + +static inline void perfctr_vc3_init_tests(void) +{ + measure_overheads(MSR_P6_EVNTSEL0+1, VC3_EVNTSEL1_VAL, MSR_P6_PERFCTR0+1, 0, 0); +} + +static inline void perfctr_p4_init_tests(void) +{ + measure_overheads(MSR_P4_CRU_ESCR0, P4_CRU_ESCR0_VAL, MSR_P4_IQ_COUNTER0, + MSR_P4_IQ_CCCR0, P4_IQ_CCCR0_VAL); +} +#endif /* !__x86_64__ */ + +static inline void perfctr_k7_init_tests(void) +{ + measure_overheads(MSR_K7_EVNTSEL0, K7_EVNTSEL0_VAL, MSR_K7_PERFCTR0, 0, 0); +} + +static inline void perfctr_generic_init_tests(void) +{ + measure_overheads(0, 0, 0, 0, 0); +} + +enum perfctr_x86_tests_type perfctr_x86_tests_type __initdata = PTT_UNKNOWN; + +void __init perfctr_x86_init_tests(void) +{ + switch (perfctr_x86_tests_type) { +#ifndef __x86_64__ + case PTT_P5: /* Intel P5, P5MMX; Cyrix 6x86MX, MII, III */ + perfctr_p5_init_tests(); + break; + case PTT_P6: /* Intel PPro, PII, PIII, PENTM */ + perfctr_p6_init_tests(); + break; +#if !defined(CONFIG_X86_TSC) + case PTT_WINCHIP: /* WinChip C6, 2, 3 */ + perfctr_c6_init_tests(); + break; +#endif + case PTT_VC3: /* VIA C3 */ + perfctr_vc3_init_tests(); + break; + case PTT_P4: /* Intel P4 */ + perfctr_p4_init_tests(); + break; +#endif /* !__x86_64__ */ + case PTT_AMD: /* AMD K7, K8 */ + perfctr_k7_init_tests(); + break; + case PTT_GENERIC: + perfctr_generic_init_tests(); + break; + default: + printk(KERN_INFO "%s: unknown CPU type %u\n", + __FUNCTION__, perfctr_x86_tests_type); + break; + } +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/perfctr/x86_tests.h 2004-07-13 17:09:34.000000000 -0700 @@ -0,0 +1,30 @@ +/* $Id: x86_tests.h,v 1.10 2004/05/22 20:48:57 mikpe Exp $ + * Performance-monitoring counters driver. + * Optional x86/x86_64-specific init-time tests. + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ + +/* 'enum perfctr_x86_tests_type' classifies CPUs according + to relevance for perfctr_x86_init_tests(). */ +enum perfctr_x86_tests_type { + PTT_UNKNOWN, + PTT_GENERIC, + PTT_P5, + PTT_P6, + PTT_P4, + PTT_AMD, + PTT_WINCHIP, + PTT_VC3, +}; + +extern enum perfctr_x86_tests_type perfctr_x86_tests_type; + +static inline void perfctr_set_tests_type(enum perfctr_x86_tests_type t) +{ +#ifdef CONFIG_PERFCTR_INIT_TESTS + perfctr_x86_tests_type = t; +#endif +} + +extern void perfctr_x86_init_tests(void); --- linux-2.6.8-rc1/drivers/pnp/driver.c 2003-06-14 12:18:29.000000000 -0700 +++ 25/drivers/pnp/driver.c 2004-07-13 17:09:24.000000000 -0700 @@ -50,6 +50,11 @@ int compare_pnp_id(struct pnp_id *pos, c return 0; } +static struct pnp_device_id generic_id = { + .id = "ANYDEVS", + .driver_data = 0, +}; + static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev) { const struct pnp_device_id *drv_id = drv->id_table; @@ -61,6 +66,8 @@ static const struct pnp_device_id * matc return drv_id; drv_id++; } + if ((drv->match && !drv->match(dev))) + return &generic_id; return NULL; } --- linux-2.6.8-rc1/drivers/pnp/pnpbios/bioscalls.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/pnp/pnpbios/bioscalls.c 2004-07-13 17:09:52.000000000 -0700 @@ -69,14 +69,14 @@ __asm__( #define Q_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], __va((u32)(address))); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(cpu_gdt_table[cpu][(selname) >> 3], (u32)(address)); \ -set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ +set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \ +set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ } while(0) static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; @@ -115,8 +115,8 @@ static inline u16 call_pnp_bios(u16 func return PNP_FUNCTION_NOT_SUPPORTED; cpu = get_cpu(); - save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; - cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8]; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc; /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); @@ -158,7 +158,7 @@ static inline u16 call_pnp_bios(u16 func ); spin_unlock_irqrestore(&pnp_bios_lock, flags); - cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40; put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ @@ -260,7 +260,7 @@ static int __pnp_bios_dev_node_info(stru if (!pnp_bios_present()) return PNP_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0, - data, sizeof(struct pnp_dev_node_info), 0, 0); + data, sizeof(struct pnp_dev_node_info), NULL, 0); data->no_nodes &= 0xff; return status; } @@ -323,7 +323,7 @@ static int __pnp_bios_set_dev_node(u8 no if ( !boot && pnpbios_dont_use_current_config ) return PNP_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0, - data, 65536, 0, 0); + data, 65536, NULL, 0); return status; } @@ -381,7 +381,7 @@ int pnp_bios_dock_station_info(struct pn if (!pnp_bios_present()) return PNP_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0, - data, sizeof(struct pnp_docking_station_info), 0, 0); + data, sizeof(struct pnp_docking_station_info), NULL, 0); return status; } --- linux-2.6.8-rc1/drivers/pnp/pnpbios/core.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/pnp/pnpbios/core.c 2004-07-13 17:09:13.000000000 -0700 @@ -130,7 +130,7 @@ static int pnp_dock_event(int dock, stru /* only one standardized param to hotplug command: type */ argv [0] = hotplug_path; argv [1] = "dock"; - argv [2] = 0; + argv [2] = NULL; /* minimal command environment */ envp [i++] = "HOME=/"; @@ -153,7 +153,7 @@ static int pnp_dock_event(int dock, stru envp [i++] = scratch; scratch += sprintf (scratch, "DOCK=%x/%x/%x", info->location_id, info->serial, info->capabilities); - envp[i] = 0; + envp[i] = NULL; value = call_usermodehelper (argv [0], argv, envp, 0); kfree (buf); --- linux-2.6.8-rc1/drivers/sbus/char/bpp.c 2004-01-09 00:04:32.000000000 -0800 +++ 25/drivers/sbus/char/bpp.c 2004-07-13 17:09:13.000000000 -0700 @@ -482,7 +482,7 @@ static int bpp_release(struct inode *ino return 0; } -static long read_nibble(unsigned minor, char *c, unsigned long cnt) +static long read_nibble(unsigned minor, char __user *c, unsigned long cnt) { unsigned long remaining = cnt; long rc; @@ -535,7 +535,7 @@ static long read_nibble(unsigned minor, return cnt - remaining; } -static long read_ecp(unsigned minor, char *c, unsigned long cnt) +static long read_ecp(unsigned minor, char __user *c, unsigned long cnt) { unsigned long remaining; long rc; @@ -630,7 +630,7 @@ static long read_ecp(unsigned minor, cha return cnt - remaining; } -static ssize_t bpp_read(struct file *f, char *c, size_t cnt, loff_t * ppos) +static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos) { long rc; unsigned minor = iminor(f->f_dentry->d_inode); @@ -692,7 +692,7 @@ static ssize_t bpp_read(struct file *f, * Compatibility mode handshaking is a matter of writing data, * strobing it, and waiting for the printer to stop being busy. */ -static long write_compat(unsigned minor, const char *c, unsigned long cnt) +static long write_compat(unsigned minor, const char __user *c, unsigned long cnt) { long rc; unsigned short pins = get_pins(minor); @@ -730,7 +730,7 @@ static long write_compat(unsigned minor, * Write data using ECP mode. Watch out that the port may be set up * for reading. If so, turn the port around. */ -static long write_ecp(unsigned minor, const char *c, unsigned long cnt) +static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt) { unsigned short pins = get_pins(minor); unsigned long remaining = cnt; @@ -783,7 +783,7 @@ static long write_ecp(unsigned minor, co * that. Otherwise, terminate and do my writing in compat mode. This * is the safest course as any device can handle it. */ -static ssize_t bpp_write(struct file *f, const char *c, size_t cnt, loff_t * ppos) +static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos) { long errno = 0; unsigned minor = iminor(f->f_dentry->d_inode); --- linux-2.6.8-rc1/drivers/sbus/char/cpwatchdog.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/sbus/char/cpwatchdog.c 2004-07-13 17:09:13.000000000 -0700 @@ -337,6 +337,7 @@ static int wd_ioctl(struct inode *inode, { int setopt = 0; struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + void __user *argp = (void __user *)arg; struct watchdog_info info = { 0, 0, @@ -351,22 +352,20 @@ static int wd_ioctl(struct inode *inode, { /* Generic Linux IOCTLs */ case WDIOC_GETSUPPORT: - if(copy_to_user((struct watchdog_info *)arg, - (struct watchdog_info *)&info, - sizeof(struct watchdog_info))) { + if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { return(-EFAULT); } break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int *) arg)) + if (put_user(0, (int __user *)argp)) return -EFAULT; break; case WDIOC_KEEPALIVE: wd_pingtimer(pTimer); break; case WDIOC_SETOPTIONS: - if(copy_from_user(&setopt, (void*) arg, sizeof(unsigned int))) { + if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { return -EFAULT; } if(setopt & WDIOS_DISABLECARD) { @@ -388,7 +387,7 @@ static int wd_ioctl(struct inode *inode, /* Solaris-compatible IOCTLs */ case WIOCGSTAT: setopt = wd_getstatus(pTimer); - if(copy_to_user((void*)arg, &setopt, sizeof(unsigned int))) { + if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { return(-EFAULT); } break; @@ -409,10 +408,10 @@ static int wd_ioctl(struct inode *inode, return(0); } -static ssize_t wd_write( struct file *file, - const char *buf, - size_t count, - loff_t *ppos) +static ssize_t wd_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) { struct wd_timer* pTimer = (struct wd_timer*)file->private_data; @@ -430,7 +429,7 @@ static ssize_t wd_write( struct file *f return 0; } -static ssize_t wd_read(struct file * file, char * buffer, +static ssize_t wd_read(struct file * file, char __user *buffer, size_t count, loff_t *ppos) { #ifdef WD_DEBUG --- linux-2.6.8-rc1/drivers/sbus/char/display7seg.c 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/sbus/char/display7seg.c 2004-07-13 17:09:13.000000000 -0700 @@ -70,7 +70,7 @@ MODULE_SUPPORTED_DEVICE * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ -volatile u8* d7s_regs = 0; +volatile u8* d7s_regs = NULL; static inline void d7s_free(void) { @@ -128,7 +128,7 @@ static int d7s_ioctl(struct inode *inode /* assign device register values * we mask-out D7S_FLIP if in sol_compat mode */ - if (get_user(ireg, (int *) arg)) + if (get_user(ireg, (int __user *) arg)) return -EFAULT; if (0 != sol_compat) { (regs & D7S_FLIP) ? @@ -144,7 +144,7 @@ static int d7s_ioctl(struct inode *inode * This driver will not misinform you about the state * of your hardware while in sol_compat mode */ - if (put_user(regs, (int *) arg)) + if (put_user(regs, (int __user *) arg)) return -EFAULT; break; --- linux-2.6.8-rc1/drivers/sbus/char/envctrl.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/sbus/char/envctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -556,7 +556,7 @@ static unsigned char envctrl_i2c_voltage * Return: Number of read bytes. 0 for error. */ static ssize_t -envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) +envctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct i2c_child_t *pchild; unsigned char data[10]; @@ -574,7 +574,7 @@ envctrl_read(struct file *file, char *bu data[0] = (unsigned char)(warning_temperature); ret = 1; - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -584,7 +584,7 @@ envctrl_read(struct file *file, char *bu data[0] = (unsigned char)(shutdown_temperature); ret = 1; - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -592,7 +592,7 @@ envctrl_read(struct file *file, char *bu if (!(pchild = envctrl_get_i2c_child(ENVCTRL_MTHRBDTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_MTHRBDTEMP_MON, data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -602,7 +602,7 @@ envctrl_read(struct file *file, char *bu ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUTEMP_MON, data); /* Reset cpu to the default cpu0. */ - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -612,7 +612,7 @@ envctrl_read(struct file *file, char *bu ret = envctrl_read_cpu_info(read_cpu, pchild, ENVCTRL_CPUVOLTAGE_MON, data); /* Reset cpu to the default cpu0. */ - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -620,7 +620,7 @@ envctrl_read(struct file *file, char *bu if (!(pchild = envctrl_get_i2c_child(ENVCTRL_SCSITEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_SCSITEMP_MON, data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -628,7 +628,7 @@ envctrl_read(struct file *file, char *bu if (!(pchild = envctrl_get_i2c_child(ENVCTRL_ETHERTEMP_MON))) return 0; ret = envctrl_read_noncpu_info(pchild, ENVCTRL_ETHERTEMP_MON, data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -637,7 +637,7 @@ envctrl_read(struct file *file, char *bu return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_fan_status(pchild,data[0], data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -646,7 +646,7 @@ envctrl_read(struct file *file, char *bu return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_globaladdr(pchild, data[0], data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -657,7 +657,7 @@ envctrl_read(struct file *file, char *bu return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_voltage_status(pchild, data[0], data); - if (copy_to_user((unsigned char *)buf, data, ret)) + if (copy_to_user(buf, data, ret)) ret = -EFAULT; break; @@ -676,7 +676,7 @@ static int envctrl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - char *infobuf; + char __user *infobuf; switch (cmd) { case ENVCTRL_RD_WARNING_TEMPERATURE: @@ -695,7 +695,7 @@ envctrl_ioctl(struct inode *inode, struc /* Check to see if application passes in any cpu number, * the default is cpu0. */ - infobuf = (char *) arg; + infobuf = (char __user *) arg; if (infobuf == NULL) { read_cpu = 0; }else { @@ -719,7 +719,7 @@ envctrl_ioctl(struct inode *inode, struc static int envctrl_open(struct inode *inode, struct file *file) { - file->private_data = 0; + file->private_data = NULL; return 0; } --- linux-2.6.8-rc1/drivers/sbus/char/flash.c 2003-07-27 12:14:39.000000000 -0700 +++ 25/drivers/sbus/char/flash.c 2004-07-13 17:09:13.000000000 -0700 @@ -105,7 +105,7 @@ flash_llseek(struct file *file, long lon } static ssize_t -flash_read(struct file * file, char * buf, +flash_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { unsigned long p = file->f_pos; @@ -161,10 +161,10 @@ static struct miscdevice flash_dev = { F static int __init flash_init(void) { struct sbus_bus *sbus; - struct sbus_dev *sdev = 0; + struct sbus_dev *sdev = NULL; #ifdef CONFIG_PCI struct linux_ebus *ebus; - struct linux_ebus_device *edev = 0; + struct linux_ebus_device *edev = NULL; struct linux_prom_registers regs[2]; int len, nregs; #endif --- linux-2.6.8-rc1/drivers/sbus/char/Kconfig 2003-09-27 18:57:45.000000000 -0700 +++ 25/drivers/sbus/char/Kconfig 2004-07-13 17:09:13.000000000 -0700 @@ -39,7 +39,7 @@ config SUN_BPP config SUN_VIDEOPIX tristate "Videopix Frame Grabber (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && (BROKEN || !64BIT) help Say Y here to support the Videopix Frame Grabber from Sun Microsystems, commonly found on SPARCstations. This card, which is @@ -48,7 +48,7 @@ config SUN_VIDEOPIX config SUN_AURORA tristate "Aurora Multiboard 1600se (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && BROKEN help The Aurora Multiboard is a multi-port high-speed serial controller. If you have one of these, say Y. --- linux-2.6.8-rc1/drivers/sbus/char/openprom.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/sbus/char/openprom.c 2004-07-13 17:09:13.000000000 -0700 @@ -67,7 +67,7 @@ static int options_node = 0; * structure will be placed in "*opp_p". Return value is the length * of the user supplied buffer. */ -static int copyin(struct openpromio *info, struct openpromio **opp_p) +static int copyin(struct openpromio __user *info, struct openpromio **opp_p) { unsigned int bufsize; @@ -98,7 +98,7 @@ static int copyin(struct openpromio *inf return bufsize; } -static int getstrings(struct openpromio *info, struct openpromio **opp_p) +static int getstrings(struct openpromio __user *info, struct openpromio **opp_p) { int n, bufsize; char c; @@ -132,7 +132,7 @@ static int getstrings(struct openpromio /* * Copy an openpromio structure in kernel space back to user space. */ -static int copyout(void *info, struct openpromio *opp, int len) +static int copyout(void __user *info, struct openpromio *opp, int len) { if (copy_to_user(info, opp, len)) return -EFAULT; @@ -150,11 +150,12 @@ static int openprom_sunos_ioctl(struct i struct openpromio *opp; int bufsize, len, error = 0; static int cnt; + void __user *argp = (void __user *)arg; if (cmd == OPROMSETOPT) - bufsize = getstrings((void *)arg, &opp); + bufsize = getstrings(argp, &opp); else - bufsize = copyin((void *)arg, &opp); + bufsize = copyin(argp, &opp); if (bufsize < 0) return bufsize; @@ -165,7 +166,7 @@ static int openprom_sunos_ioctl(struct i len = prom_getproplen(node, opp->oprom_array); if (len <= 0 || len > bufsize) { - error = copyout((void *)arg, opp, sizeof(int)); + error = copyout(argp, opp, sizeof(int)); break; } @@ -175,7 +176,7 @@ static int openprom_sunos_ioctl(struct i opp->oprom_array[len] = '\0'; opp->oprom_size = len; - error = copyout((void *)arg, opp, sizeof(int) + bufsize); + error = copyout(argp, opp, sizeof(int) + bufsize); break; case OPROMNXTOPT: @@ -184,7 +185,7 @@ static int openprom_sunos_ioctl(struct i len = strlen(buf); if (len == 0 || len + 1 > bufsize) { - error = copyout((void *)arg, opp, sizeof(int)); + error = copyout(argp, opp, sizeof(int)); break; } @@ -192,7 +193,7 @@ static int openprom_sunos_ioctl(struct i opp->oprom_array[len] = '\0'; opp->oprom_size = ++len; - error = copyout((void *)arg, opp, sizeof(int) + bufsize); + error = copyout(argp, opp, sizeof(int) + bufsize); break; case OPROMSETOPT: @@ -227,7 +228,7 @@ static int openprom_sunos_ioctl(struct i *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); - error = copyout((void *)arg, opp, bufsize + sizeof(int)); + error = copyout(argp, opp, bufsize + sizeof(int)); break; case OPROMPCI2NODE: @@ -246,7 +247,7 @@ static int openprom_sunos_ioctl(struct i data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); - error = copyout((void *)arg, opp, bufsize + sizeof(int)); + error = copyout(argp, opp, bufsize + sizeof(int)); } #endif } @@ -258,7 +259,7 @@ static int openprom_sunos_ioctl(struct i *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); - error = copyout((void *)arg, opp, bufsize + sizeof(int)); + error = copyout(argp, opp, bufsize + sizeof(int)); break; case OPROMGETBOOTARGS: @@ -274,7 +275,7 @@ static int openprom_sunos_ioctl(struct i strcpy(opp->oprom_array, buf); opp->oprom_size = len; - error = copyout((void *)arg, opp, bufsize + sizeof(int)); + error = copyout(argp, opp, bufsize + sizeof(int)); break; case OPROMU2P: @@ -317,7 +318,7 @@ static int goodnode(int n, DATA *data) } /* Copy in a whole string from userspace into kernelspace. */ -static int copyin_string(char *user, size_t len, char **ptr) +static int copyin_string(char __user *user, size_t len, char **ptr) { char *tmp; @@ -347,6 +348,7 @@ static int openprom_bsd_ioctl(struct ino unsigned int cmd, unsigned long arg) { DATA *data = (DATA *) file->private_data; + void __user *argp = (void __user *)arg; struct opiocdesc op; int error, node, len; char *str, *tmp; @@ -355,7 +357,7 @@ static int openprom_bsd_ioctl(struct ino switch (cmd) { case OPIOCGET: - if (copy_from_user(&op, (void *)arg, sizeof(op))) + if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) @@ -377,7 +379,7 @@ static int openprom_bsd_ioctl(struct ino if (len <= 0) { kfree(str); /* Verified by the above copy_from_user */ - if (__copy_to_user((void *)arg, &op, + if (__copy_to_user(argp, &op, sizeof(op))) return -EFAULT; return 0; @@ -393,7 +395,7 @@ static int openprom_bsd_ioctl(struct ino tmp[len] = '\0'; - if (__copy_to_user((void *)arg, &op, sizeof(op)) != 0 + if (__copy_to_user(argp, &op, sizeof(op)) != 0 || copy_to_user(op.op_buf, tmp, len) != 0) error = -EFAULT; @@ -403,7 +405,7 @@ static int openprom_bsd_ioctl(struct ino return error; case OPIOCNEXTPROP: - if (copy_from_user(&op, (void *)arg, sizeof(op))) + if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) @@ -425,7 +427,7 @@ static int openprom_bsd_ioctl(struct ino len = op.op_buflen = 0; } - error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op)); + error = verify_area(VERIFY_WRITE, argp, sizeof(op)); if (error) { kfree(str); return error; @@ -437,7 +439,7 @@ static int openprom_bsd_ioctl(struct ino return error; } - error = __copy_to_user((void *)arg, &op, sizeof(op)); + error = __copy_to_user(argp, &op, sizeof(op)); if (!error) error = __copy_to_user(op.op_buf, tmp, len); kfree(str); @@ -445,7 +447,7 @@ static int openprom_bsd_ioctl(struct ino return error; case OPIOCSET: - if (copy_from_user(&op, (void *)arg, sizeof(op))) + if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) @@ -472,13 +474,13 @@ static int openprom_bsd_ioctl(struct ino return 0; case OPIOCGETOPTNODE: - if (copy_to_user((void *)arg, &options_node, sizeof(int))) + if (copy_to_user(argp, &options_node, sizeof(int))) return -EFAULT; return 0; case OPIOCGETNEXT: case OPIOCGETCHILD: - if (copy_from_user(&node, (void *)arg, sizeof(int))) + if (copy_from_user(&node, argp, sizeof(int))) return -EFAULT; if (cmd == OPIOCGETNEXT) @@ -486,7 +488,7 @@ static int openprom_bsd_ioctl(struct ino else node = __prom_getchild(node); - if (__copy_to_user((void *)arg, &node, sizeof(int))) + if (__copy_to_user(argp, &node, sizeof(int))) return -EFAULT; return 0; --- linux-2.6.8-rc1/drivers/sbus/char/riowatchdog.c 2003-08-22 19:23:41.000000000 -0700 +++ 25/drivers/sbus/char/riowatchdog.c 2004-07-13 17:09:13.000000000 -0700 @@ -130,18 +130,19 @@ static int riowd_ioctl(struct inode *ino static struct watchdog_info info = { WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" }; + void __user *argp = (void __user *)arg; unsigned int options; int new_margin; switch (cmd) { case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *) arg, &info, sizeof(info))) + if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int *) arg)) + if (put_user(0, (int __user *)argp)) return -EFAULT; break; @@ -150,7 +151,7 @@ static int riowd_ioctl(struct inode *ino break; case WDIOC_SETOPTIONS: - if (copy_from_user(&options, (void *) arg, sizeof(options))) + if (copy_from_user(&options, argp, sizeof(options))) return -EFAULT; if (options & WDIOS_DISABLECARD) @@ -163,7 +164,7 @@ static int riowd_ioctl(struct inode *ino break; case WDIOC_SETTIMEOUT: - if (get_user(new_margin, (int *)arg)) + if (get_user(new_margin, (int __user *)argp)) return -EFAULT; if ((new_margin < 60) || (new_margin > (255 * 60))) return -EINVAL; @@ -172,7 +173,7 @@ static int riowd_ioctl(struct inode *ino /* Fall */ case WDIOC_GETTIMEOUT: - return put_user(riowd_timeout * 60, (int *)arg); + return put_user(riowd_timeout * 60, (int __user *)argp); default: return -EINVAL; @@ -181,7 +182,7 @@ static int riowd_ioctl(struct inode *ino return 0; } -static ssize_t riowd_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { if (ppos != &file->f_pos) return -ESPIPE; --- linux-2.6.8-rc1/drivers/sbus/char/rtc.c 2004-02-03 20:42:37.000000000 -0800 +++ 25/drivers/sbus/char/rtc.c 2004-07-13 17:09:13.000000000 -0700 @@ -85,6 +85,7 @@ static int rtc_ioctl(struct inode *inode unsigned long arg) { struct rtc_time rtc_tm; + void __user *argp = (void __user *)arg; switch (cmd) { @@ -92,7 +93,7 @@ static int rtc_ioctl(struct inode *inode memset(&rtc_tm, 0, sizeof(struct rtc_time)); get_rtc_time(&rtc_tm); - if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + if (copy_to_user(argp, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; @@ -102,7 +103,7 @@ static int rtc_ioctl(struct inode *inode if (!capable(CAP_SYS_TIME)) return -EPERM; - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time))) return -EFAULT; set_rtc_time(&rtc_tm); --- linux-2.6.8-rc1/drivers/sbus/char/vfc_dev.c 2004-03-10 20:41:29.000000000 -0800 +++ 25/drivers/sbus/char/vfc_dev.c 2004-07-13 17:09:13.000000000 -0700 @@ -226,7 +226,7 @@ static int vfc_release(struct inode *ino return 0; } -static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) +static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp) { struct vfc_debug_inout inout; unsigned char *buffer; @@ -236,15 +236,14 @@ static int vfc_debug(struct vfc_dev *dev switch(cmd) { case VFC_I2C_SEND: - if(copy_from_user(&inout, (void *)arg, sizeof(inout))) + if(copy_from_user(&inout, argp, sizeof(inout))) return -EFAULT; - buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL); + buffer = kmalloc(inout.len, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - if(copy_from_user(buffer, inout.buffer, - inout.len*sizeof(char))) { + if(copy_from_user(buffer, inout.buffer, inout.len)) { kfree(buffer); return -EFAULT; } @@ -253,9 +252,9 @@ static int vfc_debug(struct vfc_dev *dev vfc_lock_device(dev); inout.ret= vfc_i2c_sendbuf(dev,inout.addr & 0xff, - inout.buffer,inout.len); + buffer,inout.len); - if (copy_to_user((void *)arg,&inout,sizeof(inout))) { + if (copy_to_user(argp,&inout,sizeof(inout))) { kfree(buffer); return -EFAULT; } @@ -263,14 +262,14 @@ static int vfc_debug(struct vfc_dev *dev break; case VFC_I2C_RECV: - if (copy_from_user(&inout, (void *)arg, sizeof(inout))) + if (copy_from_user(&inout, argp, sizeof(inout))) return -EFAULT; buffer = kmalloc(inout.len, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - memset(buffer,0,inout.len*sizeof(char)); + memset(buffer,0,inout.len); vfc_lock_device(dev); inout.ret= vfc_i2c_recvbuf(dev,inout.addr & 0xff @@ -281,7 +280,7 @@ static int vfc_debug(struct vfc_dev *dev kfree(buffer); return -EFAULT; } - if (copy_to_user((void *)arg,&inout,sizeof(inout))) { + if (copy_to_user(argp,&inout,sizeof(inout))) { kfree(buffer); return -EFAULT; } @@ -340,7 +339,7 @@ static int vfc_set_control_ioctl(struct { int setcmd, ret = 0; - if (copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int))) + if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int))) return -EFAULT; VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", @@ -398,7 +397,7 @@ int vfc_port_change_ioctl(struct inode * int ret = 0; int cmd; - if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { + if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_port_change_ioctl\n", dev->instance)); @@ -468,7 +467,7 @@ int vfc_set_video_ioctl(struct inode *in int ret = 0; int cmd; - if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) { + if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_set_video_ioctl\n", dev->instance)); @@ -542,7 +541,7 @@ int vfc_get_video_ioctl(struct inode *in VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; " "buf[0]=%x\n", dev->instance, status, buf[0])); - if (copy_to_user((void *)arg,&status,sizeof(unsigned int))) { + if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) { VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " "vfc_get_video_ioctl\n", dev->instance)); @@ -557,6 +556,7 @@ static int vfc_ioctl(struct inode *inode int ret = 0; unsigned int tmp; struct vfc_dev *dev; + void __user *argp = (void __user *)arg; dev = vfc_get_dev_ptr(iminor(inode)); if(dev == NULL) @@ -568,7 +568,7 @@ static int vfc_ioctl(struct inode *inode VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance)); #endif tmp = sbus_readl(&dev->regs->control); - if(copy_to_user((void *)arg, &tmp, sizeof(unsigned int))) { + if(copy_to_user(argp, &tmp, sizeof(unsigned int))) { ret = -EFAULT; break; } @@ -585,7 +585,7 @@ static int vfc_ioctl(struct inode *inode break; case VFCHUE: VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance)); - if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) { + if(copy_from_user(&tmp,argp,sizeof(unsigned int))) { VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " "to IOCTL(VFCHUE)", dev->instance)); ret = -EFAULT; @@ -603,21 +603,19 @@ static int vfc_ioctl(struct inode *inode VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance)); break; default: - ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), - cmd, arg); + ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp); break; }; return ret; } -static int vfc_mmap(struct inode *inode, struct file *file, - struct vm_area_struct *vma) +static int vfc_mmap(struct file *file, struct vm_area_struct *vma) { unsigned int map_size, ret, map_offset; struct vfc_dev *dev; - dev = vfc_get_dev_ptr(iminor(inode)); + dev = vfc_get_dev_ptr(iminor(file->f_dentry->d_inode)); if(dev == NULL) return -ENODEV; --- linux-2.6.8-rc1/drivers/sbus/dvma.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/drivers/sbus/dvma.c 2004-07-13 17:09:13.000000000 -0700 @@ -29,7 +29,7 @@ void __init init_one_dvma(struct sbus_dm { printk("dma%d: ", num_dma); - dma->next = 0; + dma->next = NULL; dma->running = 0; /* No transfers going on as of yet */ dma->allocated = 0; /* No one has allocated us yet */ switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) { --- linux-2.6.8-rc1/drivers/sbus/sbus.c 2003-07-27 12:14:39.000000000 -0700 +++ 25/drivers/sbus/sbus.c 2004-07-13 17:09:13.000000000 -0700 @@ -192,7 +192,7 @@ static void __init sbus_do_child_sibling while((this_node = prom_getsibling(this_node)) != 0) { this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); this_dev = this_dev->next; - this_dev->next = 0; + this_dev->next = NULL; this_dev->parent = parent; this_dev->bus = sbus; @@ -202,7 +202,7 @@ static void __init sbus_do_child_sibling this_dev->child = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); this_dev->child->bus = sbus; - this_dev->child->next = 0; + this_dev->child->next = NULL; fill_sbus_device(prom_getchild(this_node), this_dev->child); sbus_do_child_siblings(prom_getchild(this_node), this_dev->child, this_dev, sbus); @@ -309,6 +309,10 @@ static void __init sbus_fixup_all_regs(s extern void register_proc_sparc_ioport(void); extern void firetruck_init(void); +#ifdef CONFIG_SUN4 +extern void sun4_dvma_init(void); +#endif + static int __init sbus_init(void) { int nd, this_sbus, sbus_devs, topnd, iommund; @@ -439,7 +443,7 @@ static int __init sbus_init(void) GFP_ATOMIC); /* Fill it */ this_dev->child->bus = sbus; - this_dev->child->next = 0; + this_dev->child->next = NULL; fill_sbus_device(prom_getchild(sbus_devs), this_dev->child); sbus_do_child_siblings(prom_getchild(sbus_devs), @@ -469,7 +473,7 @@ static int __init sbus_init(void) GFP_ATOMIC); /* Fill it */ this_dev->child->bus = sbus; - this_dev->child->next = 0; + this_dev->child->next = NULL; fill_sbus_device(prom_getchild(sbus_devs), this_dev->child); sbus_do_child_siblings(prom_getchild(sbus_devs), --- linux-2.6.8-rc1/drivers/scsi/aacraid/aachba.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/aacraid/aachba.c 2004-07-13 17:09:13.000000000 -0700 @@ -1080,7 +1080,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi } } -static int query_disk(struct aac_dev *dev, void *arg) +static int query_disk(struct aac_dev *dev, void __user *arg) { struct aac_query_disk qd; struct fsa_scsi_hba *fsa_dev_ptr; @@ -1117,7 +1117,7 @@ static int query_disk(struct aac_dev *de return 0; } -static int force_delete_disk(struct aac_dev *dev, void *arg) +static int force_delete_disk(struct aac_dev *dev, void __user *arg) { struct aac_delete_disk dd; struct fsa_scsi_hba *fsa_dev_ptr; @@ -1140,7 +1140,7 @@ static int force_delete_disk(struct aac_ return 0; } -static int delete_disk(struct aac_dev *dev, void *arg) +static int delete_disk(struct aac_dev *dev, void __user *arg) { struct aac_delete_disk dd; struct fsa_scsi_hba *fsa_dev_ptr; @@ -1167,7 +1167,7 @@ static int delete_disk(struct aac_dev *d } } -int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg) +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg) { switch (cmd) { case FSACTL_QUERY_DISK: --- linux-2.6.8-rc1/drivers/scsi/aacraid/aacraid.h 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/aacraid/aacraid.h 2004-07-13 17:09:13.000000000 -0700 @@ -1237,7 +1237,7 @@ struct fib_ioctl { u32 fibctx; s32 wait; - char *fib; + char __user *fib; }; struct revision @@ -1448,8 +1448,8 @@ int fib_complete(struct fib * context); struct aac_dev *aac_init_adapter(struct aac_dev *dev); int aac_get_containers(struct aac_dev *dev); int aac_scsi_cmd(struct scsi_cmnd *cmd); -int aac_dev_ioctl(struct aac_dev *dev, int cmd, void *arg); -int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg); +int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg); +int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg); int aac_rx_init(struct aac_dev *dev); int aac_rkt_init(struct aac_dev *dev); int aac_sa_init(struct aac_dev *dev); --- linux-2.6.8-rc1/drivers/scsi/aacraid/commctrl.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/aacraid/commctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -52,7 +52,7 @@ * program. */ -static int ioctl_send_fib(struct aac_dev * dev, void *arg) +static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) { struct hw_fib * kfib; struct fib *fibptr; @@ -127,7 +127,7 @@ static int ioctl_send_fib(struct aac_dev * passed in from the user. */ -static int open_getadapter_fib(struct aac_dev * dev, void *arg) +static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) { struct aac_fib_context * fibctx; int status; @@ -199,7 +199,7 @@ static int open_getadapter_fib(struct aa * passed in from the user. */ -static int next_getadapter_fib(struct aac_dev * dev, void *arg) +static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) { struct fib_ioctl f; struct fib *fib; @@ -332,7 +332,7 @@ int aac_close_fib_context(struct aac_dev * This routine will close down the fibctx passed in from the user. */ -static int close_getadapter_fib(struct aac_dev * dev, void *arg) +static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) { struct aac_fib_context *fibctx; int status; @@ -384,7 +384,7 @@ static int close_getadapter_fib(struct a * simple! */ -static int check_revision(struct aac_dev *dev, void *arg) +static int check_revision(struct aac_dev *dev, void __user *arg) { struct revision response; @@ -403,20 +403,20 @@ static int check_revision(struct aac_dev * */ -int aac_send_raw_srb(struct aac_dev* dev, void* arg) +int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) { struct fib* srbfib; int status; struct aac_srb *srbcmd; - struct aac_srb *user_srb = arg; - struct aac_srb_reply* user_reply; + struct aac_srb __user *user_srb = arg; + struct aac_srb_reply __user *user_reply; struct aac_srb_reply* reply; u32 fibsize = 0; u32 flags = 0; s32 rcode = 0; u32 data_dir; - ulong sg_user[32]; - ulong sg_list[32]; + void __user *sg_user[32]; + void *sg_list[32]; u32 sg_indx = 0; u32 byte_count = 0; u32 actual_fibsize = 0; @@ -437,7 +437,7 @@ int aac_send_raw_srb(struct aac_dev* dev srbcmd = (struct aac_srb*) fib_data(srbfib); - if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){ + if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); rcode = -EFAULT; goto cleanup; @@ -512,12 +512,12 @@ int aac_send_raw_srb(struct aac_dev* dev rcode = -ENOMEM; goto cleanup; } - sg_user[i] = (ulong)psg->sg[i].addr; - sg_list[i] = (ulong)p; // save so we can clean up later + sg_user[i] = (void __user *)psg->sg[i].addr; + sg_list[i] = p; // save so we can clean up later sg_indx = i; if( flags & SRB_DataOut ){ - if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){ + if(copy_from_user(p,sg_user[i],psg->sg[i].count)){ printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); rcode = -EFAULT; goto cleanup; @@ -533,7 +533,7 @@ int aac_send_raw_srb(struct aac_dev* dev } srbcmd->count = cpu_to_le32(byte_count); - status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0); + status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); } else { struct sgmap* psg = &srbcmd->sg; byte_count = 0; @@ -559,12 +559,12 @@ int aac_send_raw_srb(struct aac_dev* dev rcode = -ENOMEM; goto cleanup; } - sg_user[i] = (ulong)(psg->sg[i].addr); - sg_list[i] = (ulong)p; // save so we can clean up later + sg_user[i] = (void __user *)(psg->sg[i].addr); + sg_list[i] = p; // save so we can clean up later sg_indx = i; if( flags & SRB_DataOut ){ - if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){ + if(copy_from_user(p,sg_user[i],psg->sg[i].count)){ printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); rcode = -EFAULT; goto cleanup; @@ -577,7 +577,7 @@ int aac_send_raw_srb(struct aac_dev* dev byte_count += psg->sg[i].count; } srbcmd->count = cpu_to_le32(byte_count); - status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0); + status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); } if (status != 0){ @@ -588,7 +588,7 @@ int aac_send_raw_srb(struct aac_dev* dev if( flags & SRB_DataIn ) { for(i = 0 ; i <= sg_indx; i++){ - if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){ + if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){ printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); rcode = -EFAULT; goto cleanup; @@ -606,7 +606,7 @@ int aac_send_raw_srb(struct aac_dev* dev cleanup: for(i=0; i <= sg_indx; i++){ - kfree((void*)sg_list[i]); + kfree(sg_list[i]); } fib_complete(srbfib); fib_free(srbfib); @@ -621,14 +621,14 @@ struct aac_pci_info { }; -int aac_get_pci_info(struct aac_dev* dev, void* arg) +int aac_get_pci_info(struct aac_dev* dev, void __user *arg) { struct aac_pci_info pci_info; pci_info.bus = dev->pdev->bus->number; pci_info.slot = PCI_SLOT(dev->pdev->devfn); - if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info))){ + if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { printk(KERN_DEBUG "aacraid: Could not copy pci info\n"); return -EFAULT; } @@ -636,7 +636,7 @@ int aac_get_pci_info(struct aac_dev* dev } -int aac_do_ioctl(struct aac_dev * dev, int cmd, void *arg) +int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) { int status; --- linux-2.6.8-rc1/drivers/scsi/aacraid/linit.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/aacraid/linit.c 2004-07-13 17:09:24.000000000 -0700 @@ -356,7 +356,7 @@ static int aac_slave_configure(struct sc return 0; } -static int aac_ioctl(struct scsi_device *sdev, int cmd, void * arg) +static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) { struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; return aac_do_ioctl(dev, cmd, arg); @@ -409,13 +409,15 @@ static int aac_eh_reset(struct scsi_cmnd } } spin_unlock_irqrestore(&dev->list_lock, flags); + if (active) + break; - /* - * We can exit If all the commands are complete - */ - if (active == 0) - return SUCCESS; } + /* + * We can exit If all the commands are complete + */ + if (active == 0) + return SUCCESS; spin_unlock_irq(host->host_lock); scsi_sleep(HZ); spin_lock_irq(host->host_lock); @@ -463,7 +465,7 @@ static int aac_cfg_open(struct inode *in static int aac_cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return aac_do_ioctl(file->private_data, cmd, (void *)arg); + return aac_do_ioctl(file->private_data, cmd, (void __user *)arg); } static struct file_operations aac_cfg_fops = { --- linux-2.6.8-rc1/drivers/scsi/advansys.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/advansys.c 2004-07-13 17:09:52.000000000 -0700 @@ -3370,9 +3370,9 @@ do { \ /* * Default EEPROM Configuration structure defined in a_init.c. */ -extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; -extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; -extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; +static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config; +static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config; +static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config; /* * DvcGetPhyAddr() flag arguments --- linux-2.6.8-rc1/drivers/scsi/aic7xxx/aic79xx_pci.c 2004-01-09 00:04:32.000000000 -0800 +++ 25/drivers/scsi/aic7xxx/aic79xx_pci.c 2004-07-13 17:35:10.000000000 -0700 @@ -452,8 +452,10 @@ ahd_pci_test_register_access(struct ahd_ * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flaged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); while (ahd_is_paused(ahd) == 0) ; --- linux-2.6.8-rc1/drivers/scsi/ata_piix.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/ata_piix.c 2004-07-13 17:09:22.000000000 -0700 @@ -39,6 +39,7 @@ enum { ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ @@ -58,6 +59,7 @@ enum { ich5_sata = 1, piix4_pata = 2, ich6_sata = 3, + ich6_sata_rm = 4, }; static int piix_init_one (struct pci_dev *pdev, @@ -65,10 +67,8 @@ static int piix_init_one (struct pci_dev static void piix_pata_phy_reset(struct ata_port *ap); static void piix_sata_phy_reset(struct ata_port *ap); -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static unsigned int in_module_init = 1; @@ -87,13 +87,9 @@ static struct pci_device_id piix_pci_tbl { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, - - /* ICH6 operates in two modes, "looks-like-ICH5" mode, - * and enhanced mode, with queueing and other fancy stuff. - * This is distinguished by PCI class code. - */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, - { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, { } /* terminate list */ }; @@ -126,7 +122,7 @@ static Scsi_Host_Template piix_sht = { static struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, + .set_dmamode = piix_set_dmamode, .tf_load = ata_tf_load_pio, .tf_read = ata_tf_read_pio, @@ -151,8 +147,6 @@ static struct ata_port_operations piix_p static struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, .tf_load = ata_tf_load_pio, .tf_read = ata_tf_read_pio, @@ -181,7 +175,12 @@ static struct ata_port_info piix_port_in .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -191,8 +190,9 @@ static struct ata_port_info piix_port_in .sht = &piix_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, @@ -200,7 +200,12 @@ static struct ata_port_info piix_port_in { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -211,8 +216,21 @@ static struct ata_port_info piix_port_in .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, }; @@ -368,11 +386,11 @@ static void piix_sata_phy_reset(struct a * None (inherited from caller). */ -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) { + unsigned int pio = adev->pio_mode; struct pci_dev *dev = ap->host_set->pdev; - unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1; + unsigned int is_slave = (adev->devno != 0); unsigned int master_port= ap->port_no ? 0x42 : 0x40; unsigned int slave_port = 0x44; u16 master_data; @@ -409,7 +427,7 @@ static void piix_set_piomode (struct ata } /** - * piix_set_udmamode - Initialize host controller PATA PIO timings + * piix_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um * @udma: udma mode, 0 - 6 @@ -420,9 +438,9 @@ static void piix_set_piomode (struct ata * None (inherited from caller). */ -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) { + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ struct pci_dev *dev = ap->host_set->pdev; u8 maslave = ap->port_no ? 0x42 : 0x40; u8 speed = udma; @@ -452,25 +470,38 @@ static void piix_set_udmamode (struct at case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; default: BUG(); return; } - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } /* move to PCI layer, integrate w/ MSI stuff */ @@ -485,6 +516,42 @@ static void pci_enable_intx(struct pci_d } } +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -517,6 +584,12 @@ static int piix_init_one (struct pci_dev port_info[0] = &piix_port_info[ent->driver_data]; port_info[1] = NULL; + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { u8 tmp; pci_read_config_byte(pdev, ICH5_PMR, &tmp); --- linux-2.6.8-rc1/drivers/scsi/esp.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/scsi/esp.c 2004-07-13 17:09:24.000000000 -0700 @@ -27,6 +27,8 @@ #include #include +#include "scsi.h" +#include #include "esp.h" #include --- linux-2.6.8-rc1/drivers/scsi/i60uscsi.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/i60uscsi.c 2004-07-13 17:09:13.000000000 -0700 @@ -621,7 +621,7 @@ int orc_device_reset(ORC_HCS * pHCB, Scs pScb->SCB_XferLen = 0; pScb->SCB_SGLen = 0; - pVirEscb->SCB_Srb = 0; + pVirEscb->SCB_Srb = NULL; pVirEscb->SCB_Srb = SCpnt; orc_exec_scb(pHCB, pScb); /* Start execute SCB */ spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); --- linux-2.6.8-rc1/drivers/scsi/imm.c 2004-06-15 23:29:42.000000000 -0700 +++ 25/drivers/scsi/imm.c 2004-07-13 17:09:13.000000000 -0700 @@ -793,7 +793,7 @@ static void imm_interrupt(void *data) imm_pb_dismiss(dev); spin_lock_irqsave(host->host_lock, flags); - dev->cur_cmd = 0; + dev->cur_cmd = NULL; cmd->scsi_done(cmd); spin_unlock_irqrestore(host->host_lock, flags); return; --- linux-2.6.8-rc1/drivers/scsi/ips.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/ips.c 2004-07-13 17:09:24.000000000 -0700 @@ -474,21 +474,17 @@ static uint32_t ips_statupd_copperhead(i static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); static uint32_t ips_statupd_morpheus(ips_ha_t *); static ips_scb_t *ips_getscb(ips_ha_t *); -static inline void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_scb_tail(ips_scb_queue_t *, ips_scb_t *); -static inline void ips_putq_wait_head(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); -static inline void ips_putq_copp_head(ips_copp_queue_t *, +static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); +static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *); +static void ips_putq_copp_tail(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline void ips_putq_copp_tail(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static inline ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); -static inline ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static inline Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static inline Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); -static inline ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, +static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); +static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); +static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *); +static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *); +static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, ips_copp_wait_item_t *); -static inline ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); +static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); static int ips_is_passthru(Scsi_Cmnd *); static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int); @@ -1885,7 +1881,7 @@ ips_flash_bios(ips_ha_t * ha, ips_passth /* Fill in a single scb sg_list element from an address */ /* return a -1 if a breakup occurred */ /****************************************************************************/ -static inline int +static int ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, ips_scb_t * scb, int indx, unsigned int e_len) { @@ -2950,7 +2946,7 @@ ips_next(ips_ha_t * ha, int intr) /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) { METHOD_TRACE("ips_putq_scb_head", 1); @@ -2969,38 +2965,6 @@ ips_putq_scb_head(ips_scb_queue_t * queu /****************************************************************************/ /* */ -/* Routine Name: ips_putq_scb_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_scb_tail(ips_scb_queue_t * queue, ips_scb_t * item) -{ - METHOD_TRACE("ips_putq_scb_tail", 1); - - if (!item) - return; - - item->q_next = NULL; - - if (queue->tail) - queue->tail->q_next = item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_removeq_scb_head */ /* */ /* Routine Description: */ @@ -3010,7 +2974,7 @@ ips_putq_scb_tail(ips_scb_queue_t * queu /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb_head(ips_scb_queue_t * queue) { ips_scb_t *item; @@ -3045,7 +3009,7 @@ ips_removeq_scb_head(ips_scb_queue_t * q /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_scb_t * +static ips_scb_t * ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) { ips_scb_t *p; @@ -3082,34 +3046,6 @@ ips_removeq_scb(ips_scb_queue_t * queue, /****************************************************************************/ /* */ -/* Routine Name: ips_putq_wait_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_wait_head(ips_wait_queue_t * queue, Scsi_Cmnd * item) -{ - METHOD_TRACE("ips_putq_wait_head", 1); - - if (!item) - return; - - item->host_scribble = (char *) queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_wait_tail */ /* */ /* Routine Description: */ @@ -3119,7 +3055,7 @@ ips_putq_wait_head(ips_wait_queue_t * qu /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item) { METHOD_TRACE("ips_putq_wait_tail", 1); @@ -3151,7 +3087,7 @@ ips_putq_wait_tail(ips_wait_queue_t * qu /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait_head(ips_wait_queue_t * queue) { Scsi_Cmnd *item; @@ -3186,7 +3122,7 @@ ips_removeq_wait_head(ips_wait_queue_t * /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline Scsi_Cmnd * +static Scsi_Cmnd * ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item) { Scsi_Cmnd *p; @@ -3223,34 +3159,6 @@ ips_removeq_wait(ips_wait_queue_t * queu /****************************************************************************/ /* */ -/* Routine Name: ips_putq_copp_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static inline void -ips_putq_copp_head(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - METHOD_TRACE("ips_putq_copp_head", 1); - - if (!item) - return; - - item->next = queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ /* Routine Name: ips_putq_copp_tail */ /* */ /* Routine Description: */ @@ -3260,7 +3168,7 @@ ips_putq_copp_head(ips_copp_queue_t * qu /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline void +static void ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { METHOD_TRACE("ips_putq_copp_tail", 1); @@ -3292,7 +3200,7 @@ ips_putq_copp_tail(ips_copp_queue_t * qu /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp_head(ips_copp_queue_t * queue) { ips_copp_wait_item_t *item; @@ -3327,7 +3235,7 @@ ips_removeq_copp_head(ips_copp_queue_t * /* ASSUMED to be called from within the HA lock */ /* */ /****************************************************************************/ -static inline ips_copp_wait_item_t * +static ips_copp_wait_item_t * ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) { ips_copp_wait_item_t *p; --- linux-2.6.8-rc1/drivers/scsi/Kconfig 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/Kconfig 2004-07-13 17:09:30.000000000 -0700 @@ -1001,7 +1001,7 @@ config SCSI_SYM53C8XX_IOMAPPED config SCSI_IPR tristate "IBM Power Linux RAID adapter support" - depends on PCI && SCSI + depends on PCI && SCSI && PPC select FW_LOADER ---help--- This driver supports the IBM Power Linux family RAID adapters. @@ -1507,7 +1507,7 @@ source "drivers/scsi/arm/Kconfig" config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" - depends on MIPS_JAZZ && SCSI + depends on MACH_JAZZ && SCSI help This is the driver for the onboard SCSI host adapter of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM --- linux-2.6.8-rc1/drivers/scsi/libata-core.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/libata-core.c 2004-07-13 17:09:22.000000000 -0700 @@ -50,11 +50,14 @@ static unsigned int ata_busy_sleep (stru unsigned long tmout_pat, unsigned long tmout); static void __ata_dev_select (struct ata_port *ap, unsigned int device); -static void ata_host_set_pio(struct ata_port *ap); -static void ata_host_set_udma(struct ata_port *ap); -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device); -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device); static void ata_set_mode(struct ata_port *ap); +static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static int fgb(u32 bitmap); +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out); +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static unsigned int ata_unique_id = 1; static struct workqueue_struct *ata_wq; @@ -524,7 +527,7 @@ static void ata_dev_set_protocol(struct dev->write_cmd = (cmd >> 8) & 0xff; } -static const char * udma_str[] = { +static const char * xfer_mode_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", @@ -533,6 +536,14 @@ static const char * udma_str[] = { "UDMA/100", "UDMA/133", "UDMA7", + "MWDMA0", + "MWDMA1", + "MWDMA2", + "PIO0", + "PIO1", + "PIO2", + "PIO3", + "PIO4", }; /** @@ -550,16 +561,24 @@ static const char * udma_str[] = { * @udma_mask, or the constant C string "". */ -static const char *ata_udma_string(unsigned int udma_mask) +static const char *ata_mode_string(unsigned int mask) { int i; - for (i = 7; i >= 0; i--) { - if (udma_mask & (1 << i)) - return udma_str[i]; - } + for (i = 7; i >= 0; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--) + if (mask & (1 << i)) + goto out; + for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--) + if (mask & (1 << i)) + goto out; return ""; + +out: + return xfer_mode_str[i]; } /** @@ -930,10 +949,14 @@ static void ata_dev_identify(struct ata_ { struct ata_device *dev = &ap->device[device]; unsigned int i; - u16 tmp, udma_modes; + u16 tmp; + unsigned long xfer_modes; u8 status; - struct ata_taskfile tf; unsigned int using_edd; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; if (!ata_dev_present(dev)) { DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n", @@ -953,27 +976,34 @@ static void ata_dev_identify(struct ata_ ata_dev_select(ap, device, 1, 1); /* select device 0/1 */ -retry: - ata_tf_init(ap, &tf, device); - tf.ctl |= ATA_NIEN; - tf.protocol = ATA_PROT_PIO; + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->pci_dma_dir = PCI_DMA_FROMDEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; +retry: if (dev->class == ATA_DEV_ATA) { - tf.command = ATA_CMD_ID_ATA; + qc->tf.command = ATA_CMD_ID_ATA; DPRINTK("do ATA identify\n"); } else { - tf.command = ATA_CMD_ID_ATAPI; + qc->tf.command = ATA_CMD_ID_ATAPI; DPRINTK("do ATAPI identify\n"); } - ata_tf_to_host(ap, &tf); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) + if (rc) goto err_out; + else + wait_for_completion(&wait); status = ata_chk_status(ap); if (status & ATA_ERR) { @@ -988,45 +1018,20 @@ retry: * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (tf.command == ATA_CMD_ID_ATA)) { + if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { u8 err = ata_chk_err(ap); if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; + qc->cursg = 0; + qc->cursg_ofs = 0; + qc->cursect = 0; + qc->nsect = 1; goto retry; } } goto err_out; } - /* make sure we have BSY=0, DRQ=1 */ - if ((status & ATA_DRQ) == 0) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) not returning id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - /* read IDENTIFY [X] DEVICE page */ - if (ap->flags & ATA_FLAG_MMIO) { - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = readw((void *)ap->ioaddr.data_addr); - } else - for (i = 0; i < ATA_ID_WORDS; i++) - dev->id[i] = inw(ap->ioaddr.data_addr); - - /* wait for host_idle */ - status = ata_wait_idle(ap); - if (status & (ATA_BUSY | ATA_DRQ)) { - printk(KERN_WARNING "ata%u: dev %u (ATA%s?) error after id page (0x%x)\n", - ap->id, device, - dev->class == ATA_DEV_ATA ? "" : "PI", - status); - goto err_out; - } - - ata_irq_on(ap); /* re-enable interrupts */ - /* print device capabilities */ printk(KERN_DEBUG "ata%u: dev %u cfg " "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", @@ -1045,12 +1050,13 @@ retry: goto err_out_nosup; } - /* we require UDMA support */ - udma_modes = - tmp = dev->id[ATA_ID_UDMA_MODES]; - if ((tmp & 0xff) == 0) { - printk(KERN_DEBUG "ata%u: no udma\n", ap->id); - goto err_out_nosup; + /* quick-n-dirty find max transfer mode; for printk only */ + xfer_modes = dev->id[ATA_ID_UDMA_MODES]; + if (!xfer_modes) + xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; + if (!xfer_modes) { + xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); + xfer_modes |= (0x7 << ATA_SHIFT_PIO); } ata_dump_id(dev); @@ -1083,7 +1089,7 @@ retry: /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", ap->id, device, - ata_udma_string(udma_modes), + ata_mode_string(xfer_modes), (unsigned long long)dev->n_sectors, dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } @@ -1093,15 +1099,18 @@ retry: if (ata_id_is_ata(dev)) /* sanity check */ goto err_out_nosup; - /* see if 16-byte commands supported */ - tmp = dev->id[0] & 0x3; - if (tmp == 1) - ap->host->max_cmd_len = 16; + rc = atapi_cdb_len(dev->id); + if ((rc < 12) || (rc > ATAPI_CDB_LEN)) { + printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id); + goto err_out_nosup; + } + ap->cdb_len = (unsigned int) rc; + ap->host->max_cmd_len = (unsigned char) ap->cdb_len; /* print device info to dmesg */ printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n", ap->id, device, - ata_udma_string(udma_modes)); + ata_mode_string(xfer_modes)); } DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap)); @@ -1232,6 +1241,101 @@ void ata_port_disable(struct ata_port *a ap->flags |= ATA_FLAG_PORT_DISABLED; } +static struct { + unsigned int shift; + u8 base; +} xfer_mode_classes[] = { + { ATA_SHIFT_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_PIO, XFER_PIO_0 }, +}; + +static inline u8 base_from_shift(unsigned int shift) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) + if (xfer_mode_classes[i].shift == shift) + return xfer_mode_classes[i].base; + + return 0xff; +} + +static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev) +{ + int ofs, idx; + u8 base; + + if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) + return; + + if (dev->xfer_shift == ATA_SHIFT_PIO) + dev->flags |= ATA_DFLAG_PIO; + + ata_dev_set_xfermode(ap, dev); + + base = base_from_shift(dev->xfer_shift); + ofs = dev->xfer_mode - base; + idx = ofs + dev->xfer_shift; + WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str)); + + DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n", + idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs); + + printk(KERN_INFO "ata%u: dev %u configured for %s\n", + ap->id, dev->devno, xfer_mode_str[idx]); +} + +static int ata_host_set_pio(struct ata_port *ap) +{ + unsigned int mask; + int x, i; + u8 base, xfer_mode; + + mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO); + x = fgb(mask); + if (x < 0) { + printk(KERN_WARNING "ata%u: no PIO support\n", ap->id); + return -1; + } + + base = base_from_shift(ATA_SHIFT_PIO); + xfer_mode = base + x; + + DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n", + (int)base, (int)xfer_mode, mask, x); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->pio_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = ATA_SHIFT_PIO; + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, dev); + } + } + + return 0; +} + +static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, + unsigned int xfer_shift) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + if (ata_dev_present(dev)) { + dev->dma_mode = xfer_mode; + dev->xfer_mode = xfer_mode; + dev->xfer_shift = xfer_shift; + if (ap->ops->set_dmamode) + ap->ops->set_dmamode(ap, dev); + } + } +} + /** * ata_set_mode - Program timings and issue SET FEATURES - XFER * @ap: port on which timings will be programmed @@ -1241,29 +1345,28 @@ void ata_port_disable(struct ata_port *a */ static void ata_set_mode(struct ata_port *ap) { - unsigned int force_pio, i; - - ata_host_set_pio(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + unsigned int i, xfer_shift; + u8 xfer_mode; + int rc; - ata_host_set_udma(ap); - if (ap->flags & ATA_FLAG_PORT_DISABLED) - return; + /* step 1: always set host PIO timings */ + rc = ata_host_set_pio(ap); + if (rc) + goto err_out; -#ifdef ATA_FORCE_PIO - force_pio = 1; -#else - force_pio = 0; -#endif + /* step 2: choose the best data xfer mode */ + xfer_mode = xfer_shift = 0; + rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift); + if (rc) + goto err_out; - if (force_pio) { - ata_dev_set_pio(ap, 0); - ata_dev_set_pio(ap, 1); - } else { - ata_dev_set_udma(ap, 0); - ata_dev_set_udma(ap, 1); - } + /* step 3: if that xfer mode isn't PIO, set host DMA timings */ + if (xfer_shift != ATA_SHIFT_PIO) + ata_host_set_dma(ap, xfer_mode, xfer_shift); + + /* step 4: update devices' xfer mode */ + ata_dev_set_mode(ap, &ap->device[0]); + ata_dev_set_mode(ap, &ap->device[1]); if (ap->flags & ATA_FLAG_PORT_DISABLED) return; @@ -1275,6 +1378,11 @@ static void ata_set_mode(struct ata_port struct ata_device *dev = &ap->device[i]; ata_dev_set_protocol(dev); } + + return; + +err_out: + ata_port_disable(ap); } /** @@ -1536,116 +1644,102 @@ err_out: DPRINTK("EXIT\n"); } -/** - * ata_host_set_pio - - * @ap: - * - * LOCKING: - */ - -static void ata_host_set_pio(struct ata_port *ap) +static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; - unsigned int pio, i; - u16 mask; + unsigned int mask; master = &ap->device[0]; slave = &ap->device[1]; assert (ata_dev_present(master) || ata_dev_present(slave)); - mask = ap->pio_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_PIO_MODES] & 0x03); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_PIO_MODES] & 0x03); - - /* require pio mode 3 or 4 support for host and all devices */ - if (mask == 0) { - printk(KERN_WARNING "ata%u: no PIO3/4 support, ignoring\n", - ap->id); - goto err_out; + if (shift == ATA_SHIFT_UDMA) { + mask = ap->udma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + } + else if (shift == ATA_SHIFT_MWDMA) { + mask = ap->mwdma_mask; + if (ata_dev_present(master)) + mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dev_present(slave)) + mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + } + else if (shift == ATA_SHIFT_PIO) { + mask = ap->pio_mask; + if (ata_dev_present(master)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + if (ata_dev_present(slave)) { + /* spec doesn't return explicit support for + * PIO0-2, so we fake it + */ + u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03; + tmp_mode <<= 3; + tmp_mode |= 0x7; + mask &= tmp_mode; + } + } + else { + mask = 0xffffffff; /* shut up compiler warning */ + BUG(); } - pio = (mask & ATA_ID_PIO4) ? 4 : 3; - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].pio_mode = (pio == 3) ? - XFER_PIO_3 : XFER_PIO_4; - if (ap->ops->set_piomode) - ap->ops->set_piomode(ap, &ap->device[i], pio); - } + return mask; +} - return; +/* find greatest bit */ +static int fgb(u32 bitmap) +{ + unsigned int i; + int x = -1; -err_out: - ap->ops->port_disable(ap); + for (i = 0; i < 32; i++) + if (bitmap & (1 << i)) + x = i; + + return x; } /** - * ata_host_set_udma - + * ata_choose_xfer_mode - * @ap: * * LOCKING: + * + * RETURNS: + * Zero on success, negative on error. */ -static void ata_host_set_udma(struct ata_port *ap) -{ - struct ata_device *master, *slave; - u16 mask; - unsigned int i, j; - int udma_mode = -1; - - master = &ap->device[0]; - slave = &ap->device[1]; - - assert (ata_dev_present(master) || ata_dev_present(slave)); - assert ((ap->flags & ATA_FLAG_PORT_DISABLED) == 0); - - DPRINTK("udma masks: host 0x%X, master 0x%X, slave 0x%X\n", - ap->udma_mask, - (!ata_dev_present(master)) ? 0xff : - (master->id[ATA_ID_UDMA_MODES] & 0xff), - (!ata_dev_present(slave)) ? 0xff : - (slave->id[ATA_ID_UDMA_MODES] & 0xff)); - - mask = ap->udma_mask; - if (ata_dev_present(master)) - mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) - mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - - i = XFER_UDMA_7; - while (i >= XFER_UDMA_0) { - j = i - XFER_UDMA_0; - DPRINTK("mask 0x%X i 0x%X j %u\n", mask, i, j); - if (mask & (1 << j)) { - udma_mode = i; - break; +static int ata_choose_xfer_mode(struct ata_port *ap, + u8 *xfer_mode_out, + unsigned int *xfer_shift_out) +{ + unsigned int mask, shift; + int x, i; + + for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) { + shift = xfer_mode_classes[i].shift; + mask = ata_get_mode_mask(ap, shift); + + x = fgb(mask); + if (x >= 0) { + *xfer_mode_out = xfer_mode_classes[i].base + x; + *xfer_shift_out = shift; + return 0; } - - i--; - } - - /* require udma for host and all attached devices */ - if (udma_mode < 0) { - printk(KERN_WARNING "ata%u: no UltraDMA support, ignoring\n", - ap->id); - goto err_out; } - for (i = 0; i < ATA_MAX_DEVICES; i++) - if (ata_dev_present(&ap->device[i])) { - ap->device[i].udma_mode = udma_mode; - if (ap->ops->set_udmamode) - ap->ops->set_udmamode(ap, &ap->device[i], - udma_mode); - } - - return; - -err_out: - ap->ops->port_disable(ap); + return -1; } /** @@ -1658,89 +1752,39 @@ err_out: static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev) { - struct ata_taskfile tf; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; /* set up set-features taskfile */ DPRINTK("set features - xfer mode\n"); - ata_tf_init(ap, &tf, dev->devno); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = SETFEATURES_XFER; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - if (dev->flags & ATA_DFLAG_PIO) - tf.nsect = dev->pio_mode; - else - tf.nsect = dev->udma_mode; - /* do bus reset */ - ata_tf_to_host(ap, &tf); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - /* crazy ATAPI devices... */ - if (dev->class == ATA_DEV_ATAPI) - msleep(150); + qc->tf.command = ATA_CMD_SET_FEATURES; + qc->tf.feature = SETFEATURES_XFER; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = dev->xfer_mode; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - ata_irq_on(ap); /* re-enable interrupts */ + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - ata_wait_idle(ap); + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); DPRINTK("EXIT\n"); } /** - * ata_dev_set_udma - Set ATA device's transfer mode to Ultra DMA - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_udma(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->udma_mode >= XFER_UDMA_0) && - (dev->udma_mode <= XFER_UDMA_7)); - printk(KERN_INFO "ata%u: dev %u configured for %s\n", - ap->id, device, - udma_str[dev->udma_mode - XFER_UDMA_0]); -} - -/** - * ata_dev_set_pio - Set ATA device's transfer mode to PIO - * @ap: Port associated with device @dev - * @device: Device whose mode will be set - * - * LOCKING: - */ - -static void ata_dev_set_pio(struct ata_port *ap, unsigned int device) -{ - struct ata_device *dev = &ap->device[device]; - - if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED)) - return; - - /* force PIO mode */ - dev->flags |= ATA_DFLAG_PIO; - - ata_dev_set_xfermode(ap, dev); - - assert((dev->pio_mode >= XFER_PIO_3) && - (dev->pio_mode <= XFER_PIO_4)); - printk(KERN_INFO "ata%u: dev %u configured for PIO%c\n", - ap->id, device, - dev->pio_mode == 3 ? '3' : '4'); -} - -/** * ata_sg_clean - * @qc: * @@ -2003,7 +2047,7 @@ static void ata_pio_complete (struct ata } drv_stat = ata_wait_idle(ap); - if (drv_stat & (ATA_BUSY | ATA_DRQ)) { + if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; return; } @@ -2018,6 +2062,43 @@ static void ata_pio_complete (struct ata ata_qc_complete(qc, drv_stat); } +static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int i; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *) buf; + void *mmio = (void *)ap->ioaddr.data_addr; + + if (write_data) { + for (i = 0; i < words; i++) + writew(buf16[i], mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = readw(mmio); + } +} + +static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int write_data) +{ + unsigned int dwords = buflen >> 2; + + if (write_data) + outsl(ap->ioaddr.data_addr, buf, dwords); + else + insl(ap->ioaddr.data_addr, buf, dwords); +} + +static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, + unsigned int buflen, int do_write) +{ + if (ap->flags & ATA_FLAG_MMIO) + ata_mmio_data_xfer(ap, buf, buflen, do_write); + else + ata_pio_data_xfer(ap, buf, buflen, do_write); +} + /** * ata_pio_sector - * @ap: @@ -2031,6 +2112,7 @@ static void ata_pio_sector(struct ata_po struct scatterlist *sg; unsigned char *buf; u8 status; + int do_write; /* * This is purely hueristic. This is a fast path. @@ -2071,26 +2153,41 @@ static void ata_pio_sector(struct ata_po qc->cursect++; qc->cursg_ofs++; - if (qc->flags & ATA_QCFLAG_SG) - if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { - qc->cursg++; - qc->cursg_ofs = 0; - } + if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) { + qc->cursg++; + qc->cursg_ofs = 0; + } DPRINTK("data %s, drv_stat 0x%X\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read", status); /* do the actual data transfer */ - /* FIXME: mmio-ize */ - if (qc->tf.flags & ATA_TFLAG_WRITE) - outsl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); - else - insl(ap->ioaddr.data_addr, buf, ATA_SECT_DWORDS); + do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write); kunmap(sg[qc->cursg].page); } +static void ata_pio_error(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + u8 drv_stat; + + qc = ata_qc_from_tag(ap, ap->active_tag); + assert(qc != NULL); + + drv_stat = ata_chk_status(ap); + printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", + ap->id, drv_stat); + + ap->pio_task_state = PIO_ST_IDLE; + + ata_irq_on(ap); + + ata_qc_complete(qc, drv_stat | ATA_ERR); +} + static void ata_pio_task(void *_data) { struct ata_port *ap = _data; @@ -2111,15 +2208,8 @@ static void ata_pio_task(void *_data) break; case PIO_ST_TMOUT: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; - break; - case PIO_ST_ERR: - printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */ - ap->id); - timeout = 11 * HZ; + ata_pio_error(ap); break; } @@ -2178,7 +2268,6 @@ static void ata_qc_timeout(struct ata_qu /* fall through */ - case ATA_PROT_NODATA: default: ata_altstatus(ap); drv_stat = ata_chk_status(ap); @@ -2285,8 +2374,6 @@ struct ata_queued_cmd *ata_qc_new_init(s ata_tf_init(ap, &qc->tf, dev->devno); - if (likely((dev->flags & ATA_DFLAG_PIO) == 0)) - qc->flags |= ATA_QCFLAG_DMA; if (dev->flags & ATA_DFLAG_LBA48) qc->tf.flags |= ATA_TFLAG_LBA48; } @@ -2294,6 +2381,11 @@ struct ata_queued_cmd *ata_qc_new_init(s return qc; } +static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +{ + return 0; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -2333,11 +2425,16 @@ void ata_qc_complete(struct ata_queued_c do_clear = 1; } - if (qc->waiting) - complete(qc->waiting); + if (qc->waiting) { + struct completion *waiting = qc->waiting; + qc->waiting = NULL; + complete(waiting); + } if (likely(do_clear)) clear_bit(tag, &ap->qactive); + + VPRINTK("EXIT\n"); } /** @@ -2420,6 +2517,12 @@ int ata_qc_issue_prot(struct ata_queued_ break; case ATA_PROT_ATAPI: + ata_qc_set_polling(qc); + ata_tf_to_host_nolock(ap, &qc->tf); + queue_work(ata_wq, &ap->packet_task); + break; + + case ATA_PROT_ATAPI_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); queue_work(ata_wq, &ap->packet_task); break; @@ -2578,7 +2681,7 @@ inline unsigned int ata_host_intr (struc case ATA_PROT_ATAPI_DMA: /* check status of DMA engine */ host_stat = ata_bmdma_status(ap); - VPRINTK("BUS_DMA (host_stat 0x%X)\n", host_stat); + VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); /* if it's not our irq... */ if (!(host_stat & ATA_DMA_INTR)) @@ -2589,6 +2692,7 @@ inline unsigned int ata_host_intr (struc /* fall through */ + case ATA_PROT_ATAPI_NODATA: case ATA_PROT_NODATA: /* check altstatus */ status = ata_altstatus(ap); @@ -2599,7 +2703,8 @@ inline unsigned int ata_host_intr (struc status = ata_chk_status(ap); if (unlikely(status & ATA_BUSY)) goto idle_irq; - DPRINTK("BUS_NODATA (dev_stat 0x%X)\n", status); + DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", + ap->id, qc->tf.protocol, status); /* ack bmdma irq events */ ata_bmdma_ack_irq(ap); @@ -2698,21 +2803,20 @@ static void atapi_packet_task(void *_dat /* make sure DRQ is set */ status = ata_chk_status(ap); - if ((status & ATA_DRQ) == 0) + if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ) goto err_out; /* send SCSI cdb */ - /* FIXME: mmio-ize */ DPRINTK("send cdb\n"); - outsl(ap->ioaddr.data_addr, - qc->scsicmd->cmnd, ap->host->max_cmd_len / 4); + assert(ap->cdb_len >= 12); + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) ap->ops->bmdma_start(qc); /* initiate bmdma */ /* non-data commands are also handled via irq */ - else if (qc->scsicmd->sc_data_direction == SCSI_DATA_NONE) { + else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { /* do nothing */ } @@ -2801,11 +2905,11 @@ static void ata_host_init(struct ata_por ap->host_set = host_set; ap->port_no = port_no; ap->pio_mask = ent->pio_mask; + ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; ap->ops = ent->port_ops; ap->cbl = ATA_CBL_NONE; - ap->device[0].flags = ATA_DFLAG_MASTER; ap->active_tag = ATA_TAG_POISON; ap->last_ctl = 0xFF; @@ -2898,19 +3002,23 @@ int ata_device_add(struct ata_probe_ent /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { struct ata_port *ap; + unsigned long xfer_mode_mask; ap = ata_host_add(ent, host_set, i); if (!ap) goto err_out; host_set->ports[i] = ap; + xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) | + (ap->mwdma_mask << ATA_SHIFT_MWDMA) | + (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " "bmdma 0x%lX irq %lu\n", ap->id, ap->flags & ATA_FLAG_SATA ? 'S' : 'P', - ata_udma_string(ent->udma_mask), + ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, ap->ioaddr.ctl_addr, ap->ioaddr.bmdma_addr, @@ -3149,6 +3257,7 @@ int ata_pci_init_one (struct pci_dev *pd probe_ent->sht = port0->sht; probe_ent->host_flags = port0->host_flags; probe_ent->pio_mask = port0->pio_mask; + probe_ent->mwdma_mask = port0->mwdma_mask; probe_ent->udma_mask = port0->udma_mask; probe_ent->port_ops = port0->port_ops; @@ -3171,6 +3280,7 @@ int ata_pci_init_one (struct pci_dev *pd probe_ent2->sht = port1->sht; probe_ent2->host_flags = port1->host_flags; probe_ent2->pio_mask = port1->pio_mask; + probe_ent2->mwdma_mask = port1->mwdma_mask; probe_ent2->udma_mask = port1->udma_mask; probe_ent2->port_ops = port1->port_ops; } else { --- linux-2.6.8-rc1/drivers/scsi/libata-scsi.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/libata-scsi.c 2004-07-13 17:09:22.000000000 -0700 @@ -339,14 +339,10 @@ static int ata_scsi_qc_complete(struct a { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - if (is_atapi_taskfile(&qc->tf)) - cmd->result = SAM_STAT_CHECK_CONDITION; - else - ata_to_sense_error(qc); - } else { + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc); + else cmd->result = SAM_STAT_GOOD; - } qc->scsidone(cmd); @@ -964,6 +960,31 @@ void ata_scsi_badcmd(struct scsi_cmnd *c done(cmd); } +static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + cmd->result = SAM_STAT_CHECK_CONDITION; + else { + u8 *scsicmd = cmd->cmnd; + + if (scsicmd[0] == INQUIRY) { + u8 *buf = NULL; + unsigned int buflen; + + buflen = ata_scsi_rbuf_get(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + + qc->scsidone(cmd); + + return 0; +} /** * atapi_xlat - Initialize PACKET taskfile * @qc: command structure to be initialized @@ -979,6 +1000,13 @@ void ata_scsi_badcmd(struct scsi_cmnd *c static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + int using_pio = (dev->flags & ATA_DFLAG_PIO); + int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + + memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len); + + qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; if (cmd->sc_data_direction == SCSI_DATA_WRITE) { @@ -988,19 +1016,18 @@ static unsigned int atapi_xlat(struct at qc->tf.command = ATA_CMD_PACKET; - /* no data - interrupt-driven */ - if (cmd->sc_data_direction == SCSI_DATA_NONE) - qc->tf.protocol = ATA_PROT_ATAPI; - - /* PIO data xfer - polling */ - else if ((qc->flags & ATA_QCFLAG_DMA) == 0) { - ata_qc_set_polling(qc); - qc->tf.protocol = ATA_PROT_ATAPI; + /* no data, or PIO data xfer */ + if (using_pio || nodata) { + if (nodata) + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + else + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = (8 * 1024) & 0xff; qc->tf.lbah = (8 * 1024) >> 8; + } - /* DMA data xfer - interrupt-driven */ - } else { + /* DMA data xfer */ + else { qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; --- linux-2.6.8-rc1/drivers/scsi/megaraid.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/megaraid.c 2004-07-13 17:09:24.000000000 -0700 @@ -25,11 +25,8 @@ * 518, 520, 531, 532 * * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, - * and others. Please send updates to the public mailing list - * linux-megaraid-devel@dell.com, and subscribe to and read archives of this - * list at http://lists.us.dell.com/. - * - * For history of changes, see ChangeLog.megaraid. + * and others. Please send updates to the mailing list + * linux-scsi@vger.kernel.org . * */ @@ -335,6 +332,18 @@ mega_query_adapter(adapter_t *adapter) return 0; } +/** + * mega_runpendq() + * @adapter - pointer to our soft state + * + * Runs through the list of pending requests. + */ +static inline void +mega_runpendq(adapter_t *adapter) +{ + if(!list_empty(&adapter->pending_list)) + __mega_runpendq(adapter); +} /* * megaraid_queue() @@ -384,6 +393,95 @@ megaraid_queue(Scsi_Cmnd *scmd, void (*d return busy; } +/** + * mega_allocate_scb() + * @adapter - pointer to our soft state + * @cmd - scsi command from the mid-layer + * + * Allocate a SCB structure. This is the central structure for controller + * commands. + */ +static inline scb_t * +mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd) +{ + struct list_head *head = &adapter->free_list; + scb_t *scb; + + /* Unlink command from Free List */ + if( !list_empty(head) ) { + + scb = list_entry(head->next, scb_t, list); + + list_del_init(head->next); + + scb->state = SCB_ACTIVE; + scb->cmd = cmd; + scb->dma_type = MEGA_DMA_TYPE_NONE; + + return scb; + } + + return NULL; +} + +/** + * mega_get_ldrv_num() + * @adapter - pointer to our soft state + * @cmd - scsi mid layer command + * @channel - channel on the controller + * + * Calculate the logical drive number based on the information in scsi command + * and the channel number. + */ +static inline int +mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel) +{ + int tgt; + int ldrv_num; + + tgt = cmd->device->id; + + if ( tgt > adapter->this_id ) + tgt--; /* we do not get inquires for initiator id */ + + ldrv_num = (channel * 15) + tgt; + + + /* + * If we have a logical drive with boot enabled, project it first + */ + if( adapter->boot_ldrv_enabled ) { + if( ldrv_num == 0 ) { + ldrv_num = adapter->boot_ldrv; + } + else { + if( ldrv_num <= adapter->boot_ldrv ) { + ldrv_num--; + } + } + } + + /* + * If "delete logical drive" feature is enabled on this controller. + * Do only if at least one delete logical drive operation was done. + * + * Also, after logical drive deletion, instead of logical drive number, + * the value returned should be 0x80+logical drive id. + * + * These is valid only for IO commands. + */ + + if (adapter->support_random_del && adapter->read_ldidmap ) + switch (cmd->cmnd[0]) { + case READ_6: /* fall through */ + case WRITE_6: /* fall through */ + case READ_10: /* fall through */ + case WRITE_10: + ldrv_num += 0x80; + } + + return ldrv_num; +} /** * mega_build_cmd() @@ -966,52 +1064,6 @@ mega_prepare_extpassthru(adapter_t *adap return epthru; } - -/** - * mega_allocate_scb() - * @adapter - pointer to our soft state - * @cmd - scsi command from the mid-layer - * - * Allocate a SCB structure. This is the central structure for controller - * commands. - */ -static inline scb_t * -mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd) -{ - struct list_head *head = &adapter->free_list; - scb_t *scb; - - /* Unlink command from Free List */ - if( !list_empty(head) ) { - - scb = list_entry(head->next, scb_t, list); - - list_del_init(head->next); - - scb->state = SCB_ACTIVE; - scb->cmd = cmd; - scb->dma_type = MEGA_DMA_TYPE_NONE; - - return scb; - } - - return NULL; -} - - -/** - * mega_runpendq() - * @adapter - pointer to our soft state - * - * Runs through the list of pending requests. - */ -static inline void -mega_runpendq(adapter_t *adapter) -{ - if(!list_empty(&adapter->pending_list)) - __mega_runpendq(adapter); -} - static void __mega_runpendq(adapter_t *adapter) { @@ -1043,7 +1095,7 @@ __mega_runpendq(adapter_t *adapter) * busy. We also take the scb from the pending list if the mailbox is * available. */ -static inline int +static int issue_scb(adapter_t *adapter, scb_t *scb) { volatile mbox64_t *mbox64 = adapter->mbox64; @@ -1104,6 +1156,16 @@ issue_scb(adapter_t *adapter, scb_t *scb return 0; } +/* + * Wait until the controller's mailbox is available + */ +static inline int +mega_busywait_mbox (adapter_t *adapter) +{ + if (adapter->mbox->m_in.busy) + return __mega_busywait_mbox(adapter); + return 0; +} /** * issue_scb_block() @@ -1350,7 +1412,7 @@ megaraid_isr_memmapped(int irq, void *de * * Complete the comamnds and call the scsi mid-layer callback hooks. */ -static inline void +static void mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) { mega_ext_passthru *epthru = NULL; @@ -1671,17 +1733,6 @@ mega_free_scb(adapter_t *adapter, scb_t } -/* - * Wait until the controller's mailbox is available - */ -static inline int -mega_busywait_mbox (adapter_t *adapter) -{ - if (adapter->mbox->m_in.busy) - return __mega_busywait_mbox(adapter); - return 0; -} - static int __mega_busywait_mbox (adapter_t *adapter) { @@ -2017,6 +2068,49 @@ megaraid_abort_and_reset(adapter_t *adap return FALSE; } +static inline int +make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) +{ + *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + + if( *pdev == NULL ) return -1; + + memcpy(*pdev, adapter->dev, sizeof(struct pci_dev)); + + if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) { + kfree(*pdev); + return -1; + } + + return 0; +} + +static inline void +free_local_pdev(struct pci_dev *pdev) +{ + kfree(pdev); +} + +/** + * mega_allocate_inquiry() + * @dma_handle - handle returned for dma address + * @pdev - handle to pci device + * + * allocates memory for inquiry structure + */ +static inline void * +mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) +{ + return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle); +} + + +static inline void +mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) +{ + pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle); +} + #ifdef CONFIG_PROC_FS /* Following code handles /proc fs */ @@ -3269,13 +3363,13 @@ megadev_ioctl(struct inode *inode, struc nitioctl_t uioc; int adapno; int rval; - mega_passthru *upthru; /* user address for passthru */ + mega_passthru __user *upthru; /* user address for passthru */ mega_passthru *pthru; /* copy user passthru here */ dma_addr_t pthru_dma_hndl; void *data = NULL; /* data to be transferred */ dma_addr_t data_dma_hndl; /* dma handle for data xfer area */ megacmd_t mc; - megastat_t *ustats; + megastat_t __user *ustats; int num_ldrv; u32 uxferaddr = 0; struct pci_dev *pdev; @@ -3300,20 +3394,20 @@ megadev_ioctl(struct inode *inode, struc * addresses. */ memset(&uioc, 0, sizeof(nitioctl_t)); - if( (rval = mega_m_to_n( (void *)arg, &uioc)) != 0 ) + if( (rval = mega_m_to_n( (void __user *)arg, &uioc)) != 0 ) return rval; switch( uioc.opcode ) { case GET_DRIVER_VER: - if( put_user(driver_ver, (u32 *)uioc.uioc_uaddr) ) + if( put_user(driver_ver, (u32 __user *)uioc.uioc_uaddr) ) return (-EFAULT); break; case GET_N_ADAP: - if( put_user(hba_count, (u32 *)uioc.uioc_uaddr) ) + if( put_user(hba_count, (u32 __user *)uioc.uioc_uaddr) ) return (-EFAULT); /* @@ -3347,7 +3441,7 @@ megadev_ioctl(struct inode *inode, struc adapter = hba_soft_state[adapno]; - ustats = (megastat_t *)uioc.uioc_uaddr; + ustats = uioc.uioc_uaddr; if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) ) return (-EFAULT); @@ -3418,7 +3512,7 @@ megadev_ioctl(struct inode *inode, struc mc.status = rval; - rval = mega_n_to_m((void *)arg, &mc); + rval = mega_n_to_m((void __user *)arg, &mc); } return rval; @@ -3458,12 +3552,12 @@ megadev_ioctl(struct inode *inode, struc /* * The user passthru structure */ - upthru = (mega_passthru *)MBOX(uioc)->xferaddr; + upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr; /* * Copy in the user passthru here. */ - if( copy_from_user(pthru, (char *)upthru, + if( copy_from_user(pthru, upthru, sizeof(mega_passthru)) ) { pci_free_consistent(pdev, @@ -3510,7 +3604,7 @@ megadev_ioctl(struct inode *inode, struc /* * Get the user data */ - if( copy_from_user(data, (char *)uxferaddr, + if( copy_from_user(data, (char __user *)uxferaddr, pthru->dataxferlen) ) { rval = (-EFAULT); goto freemem_and_return; @@ -3527,7 +3621,7 @@ megadev_ioctl(struct inode *inode, struc */ mega_internal_command(adapter, LOCK_INT, &mc, pthru); - rval = mega_n_to_m((void *)arg, &mc); + rval = mega_n_to_m((void __user *)arg, &mc); if( rval ) goto freemem_and_return; @@ -3536,7 +3630,7 @@ megadev_ioctl(struct inode *inode, struc * Is data going up-stream */ if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) { - if( copy_to_user((char *)uxferaddr, data, + if( copy_to_user((char __user *)uxferaddr, data, pthru->dataxferlen) ) { rval = (-EFAULT); } @@ -3588,7 +3682,7 @@ freemem_and_return: /* * Get the user data */ - if( copy_from_user(data, (char *)uxferaddr, + if( copy_from_user(data, (char __user *)uxferaddr, uioc.xferlen) ) { pci_free_consistent(pdev, @@ -3610,7 +3704,7 @@ freemem_and_return: */ mega_internal_command(adapter, LOCK_INT, &mc, NULL); - rval = mega_n_to_m((void *)arg, &mc); + rval = mega_n_to_m((void __user *)arg, &mc); if( rval ) { if( uioc.xferlen ) { @@ -3628,7 +3722,7 @@ freemem_and_return: * Is data going up-stream */ if( uioc.xferlen && (uioc.flags & UIOC_RD) ) { - if( copy_to_user((char *)uxferaddr, data, + if( copy_to_user((char __user *)uxferaddr, data, uioc.xferlen) ) { rval = (-EFAULT); @@ -3664,7 +3758,7 @@ freemem_and_return: * Converts the older mimd ioctl structure to newer NIT structure */ static int -mega_m_to_n(void *arg, nitioctl_t *uioc) +mega_m_to_n(void __user *arg, nitioctl_t *uioc) { struct uioctl_t uioc_mimd; char signature[8] = {0}; @@ -3679,7 +3773,7 @@ mega_m_to_n(void *arg, nitioctl_t *uioc) * begining of the structure. */ - if( copy_from_user(signature, (char *)arg, 7) ) + if( copy_from_user(signature, arg, 7) ) return (-EFAULT); if( memcmp(signature, "MEGANIT", 7) == 0 ) { @@ -3692,7 +3786,7 @@ mega_m_to_n(void *arg, nitioctl_t *uioc) */ return -EINVAL; #if 0 - if( copy_from_user(uioc, (char *)arg, sizeof(nitioctl_t)) ) + if( copy_from_user(uioc, arg, sizeof(nitioctl_t)) ) return (-EFAULT); return 0; #endif @@ -3703,7 +3797,7 @@ mega_m_to_n(void *arg, nitioctl_t *uioc) * * Get the user ioctl structure */ - if( copy_from_user(&uioc_mimd, (char *)arg, sizeof(struct uioctl_t)) ) + if( copy_from_user(&uioc_mimd, arg, sizeof(struct uioctl_t)) ) return (-EFAULT); @@ -3790,52 +3884,52 @@ mega_m_to_n(void *arg, nitioctl_t *uioc) * conforms to older mimd ioctl interface or newer NIT ioctl interface */ static int -mega_n_to_m(void *arg, megacmd_t *mc) +mega_n_to_m(void __user *arg, megacmd_t *mc) { - nitioctl_t *uiocp; - megacmd_t *umc; - mega_passthru *upthru; - struct uioctl_t *uioc_mimd; + nitioctl_t __user *uiocp; + megacmd_t __user *umc; + mega_passthru __user *upthru; + struct uioctl_t __user *uioc_mimd; char signature[8] = {0}; /* * check is the application conforms to NIT. */ - if( copy_from_user(signature, (char *)arg, 7) ) + if( copy_from_user(signature, arg, 7) ) return -EFAULT; if( memcmp(signature, "MEGANIT", 7) == 0 ) { - uiocp = (nitioctl_t *)arg; + uiocp = arg; - if( put_user(mc->status, (u8 *)&MBOX_P(uiocp)->status) ) + if( put_user(mc->status, (u8 __user *)&MBOX_P(uiocp)->status) ) return (-EFAULT); if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { umc = MBOX_P(uiocp); - if (get_user(upthru, (mega_passthru **)&umc->xferaddr)) - return (-EFAULT); + if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) + return -EFAULT; - if( put_user(mc->status, (u8 *)&upthru->scsistatus) ) + if( put_user(mc->status, (u8 __user *)&upthru->scsistatus)) return (-EFAULT); } } else { - uioc_mimd = (struct uioctl_t *)arg; + uioc_mimd = arg; - if( put_user(mc->status, (u8 *)&uioc_mimd->mbox[17]) ) + if( put_user(mc->status, (u8 __user *)&uioc_mimd->mbox[17]) ) return (-EFAULT); if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { - umc = (megacmd_t *)uioc_mimd->mbox; + umc = (megacmd_t __user *)uioc_mimd->mbox; - if (get_user(upthru, (mega_passthru **)&umc->xferaddr)) + if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) return (-EFAULT); - if( put_user(mc->status, (u8 *)&upthru->scsistatus) ) + if( put_user(mc->status, (u8 __user *)&upthru->scsistatus) ) return (-EFAULT); } } @@ -4233,67 +4327,6 @@ mega_support_cluster(adapter_t *adapter) } - -/** - * mega_get_ldrv_num() - * @adapter - pointer to our soft state - * @cmd - scsi mid layer command - * @channel - channel on the controller - * - * Calculate the logical drive number based on the information in scsi command - * and the channel number. - */ -static inline int -mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel) -{ - int tgt; - int ldrv_num; - - tgt = cmd->device->id; - - if ( tgt > adapter->this_id ) - tgt--; /* we do not get inquires for initiator id */ - - ldrv_num = (channel * 15) + tgt; - - - /* - * If we have a logical drive with boot enabled, project it first - */ - if( adapter->boot_ldrv_enabled ) { - if( ldrv_num == 0 ) { - ldrv_num = adapter->boot_ldrv; - } - else { - if( ldrv_num <= adapter->boot_ldrv ) { - ldrv_num--; - } - } - } - - /* - * If "delete logical drive" feature is enabled on this controller. - * Do only if at least one delete logical drive operation was done. - * - * Also, after logical drive deletion, instead of logical drive number, - * the value returned should be 0x80+logical drive id. - * - * These is valid only for IO commands. - */ - - if (adapter->support_random_del && adapter->read_ldidmap ) - switch (cmd->cmnd[0]) { - case READ_6: /* fall through */ - case WRITE_6: /* fall through */ - case READ_10: /* fall through */ - case WRITE_10: - ldrv_num += 0x80; - } - - return ldrv_num; -} - - /** * mega_adapinq() * @adapter - pointer to our soft state @@ -4329,27 +4362,6 @@ mega_adapinq(adapter_t *adapter, dma_add } -/** - * mega_allocate_inquiry() - * @dma_handle - handle returned for dma address - * @pdev - handle to pci device - * - * allocates memory for inquiry structure - */ -static inline caddr_t -mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) -{ - return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle); -} - - -static inline void -mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) -{ - pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle); -} - - /** mega_internal_dev_inquiry() * @adapter - pointer to our soft state * @ch - channel for this device @@ -4550,29 +4562,6 @@ mega_internal_done(Scsi_Cmnd *scmd) } -static inline int -make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) -{ - *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); - - if( *pdev == NULL ) return -1; - - memcpy(*pdev, adapter->dev, sizeof(struct pci_dev)); - - if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) { - kfree(*pdev); - return -1; - } - - return 0; -} - -static inline void -free_local_pdev(struct pci_dev *pdev) -{ - kfree(pdev); -} - static struct scsi_host_template megaraid_template = { .module = THIS_MODULE, .name = "MegaRAID", --- linux-2.6.8-rc1/drivers/scsi/megaraid.h 2004-01-09 00:04:32.000000000 -0800 +++ 25/drivers/scsi/megaraid.h 2004-07-13 17:09:13.000000000 -0700 @@ -522,11 +522,11 @@ struct uioctl_t { u8 mbox[18]; /* 16 bytes + 2 status bytes */ mega_passthru pthru; #if BITS_PER_LONG == 32 - char *data; /* buffer <= 4096 for 0x80 commands */ + char __user *data; /* buffer <= 4096 for 0x80 commands */ char pad[4]; #endif #if BITS_PER_LONG == 64 - char *data; + char __user *data; #endif } __attribute__ ((packed)); @@ -622,12 +622,12 @@ typedef struct { u32 adapno; /* adapter number */ union { u8 __raw_mbox[18]; - caddr_t __uaddr; /* xferaddr for non-mbox cmds */ + void __user *__uaddr; /* xferaddr for non-mbox cmds */ }__ua; #define uioc_rmbox __ua.__raw_mbox #define MBOX(uioc) ((megacmd_t *)&((uioc).__ua.__raw_mbox[0])) -#define MBOX_P(uioc) ((megacmd_t *)&((uioc)->__ua.__raw_mbox[0])) +#define MBOX_P(uioc) ((megacmd_t __user *)&((uioc)->__ua.__raw_mbox[0])) #define uioc_uaddr __ua.__uaddr u32 xferlen; /* xferlen for DCMD and non-mbox @@ -990,14 +990,12 @@ typedef enum { LOCK_INT, LOCK_EXT } lock const char *megaraid_info (struct Scsi_Host *); static int mega_query_adapter(adapter_t *); -static inline int issue_scb(adapter_t *, scb_t *); +static int issue_scb(adapter_t *, scb_t *); static int mega_setup_mailbox(adapter_t *); static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *); -static inline scb_t *mega_allocate_scb(adapter_t *, Scsi_Cmnd *); static void __mega_runpendq(adapter_t *); -static inline void mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *); @@ -1014,10 +1012,9 @@ static int mega_print_inquiry(char *, ch static int mega_build_sglist (adapter_t *adapter, scb_t *scb, u32 *buffer, u32 *length); -static inline int mega_busywait_mbox (adapter_t *); static int __mega_busywait_mbox (adapter_t *); static void mega_rundoneq (adapter_t *); -static inline void mega_cmd_done(adapter_t *, u8 [], int, int); +static void mega_cmd_done(adapter_t *, u8 [], int, int); static inline void mega_free_sgl (adapter_t *adapter); static void mega_8_to_40ld (mraid_inquiry *inquiry, mega_inquiry3 *enquiry3, mega_product_info *); @@ -1025,8 +1022,8 @@ static void mega_8_to_40ld (mraid_inquir static int megadev_open (struct inode *, struct file *); static int megadev_ioctl (struct inode *, struct file *, unsigned int, unsigned long); -static int mega_m_to_n(void *, nitioctl_t *); -static int mega_n_to_m(void *, megacmd_t *); +static int mega_m_to_n(void __user *, nitioctl_t *); +static int mega_n_to_m(void __user *, megacmd_t *); static int mega_init_scb (adapter_t *); @@ -1053,10 +1050,6 @@ static int proc_rdrv(adapter_t *, char * static int mega_adapinq(adapter_t *, dma_addr_t); static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t); -static inline caddr_t mega_allocate_inquiry(dma_addr_t *, struct pci_dev *); -static inline void mega_free_inquiry(caddr_t, dma_addr_t, struct pci_dev *); -static inline int make_local_pdev(adapter_t *, struct pci_dev **); -static inline void free_local_pdev(struct pci_dev *); static int mega_support_ext_cdb(adapter_t *); static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *, @@ -1065,7 +1058,6 @@ static mega_ext_passthru* mega_prepare_e scb_t *, Scsi_Cmnd *, int, int); static void mega_enum_raid_scsi(adapter_t *); static void mega_get_boot_drv(adapter_t *); -static inline int mega_get_ldrv_num(adapter_t *, Scsi_Cmnd *, int); static int mega_support_random_del(adapter_t *); static int mega_del_logdrv(adapter_t *, int); static int mega_do_del_logdrv(adapter_t *, int); --- linux-2.6.8-rc1/drivers/scsi/NCR_Q720.c 2004-07-11 14:13:27.000000000 -0700 +++ 25/drivers/scsi/NCR_Q720.c 2004-07-13 17:09:21.000000000 -0700 @@ -216,7 +216,21 @@ NCR_Q720_probe(struct device *dev) goto out_free; } - mem_base = (__u32)ioremap(base_addr, mem_size); + if (dma_declare_coherent_memory(dev, base_addr, base_addr, + mem_size, DMA_MEMORY_MAP) + != DMA_MEMORY_MAP) { + printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n"); + goto out_release_region; + } + + /* The first 1k of the memory buffer is a memory map of the registers + */ + mem_base = (__u32)dma_mark_declared_memory_occupied(dev, base_addr, + 1024); + if (IS_ERR((void *)mem_base)) { + printk("NCR_Q720 failed to reserve memory mapped region\n"); + goto out_release; + } /* now also enable accesses in asr 2 */ asr2 = inb(io_base + 0x0a); @@ -296,7 +310,8 @@ NCR_Q720_probe(struct device *dev) return 0; out_release: - iounmap((void *)mem_base); + dma_release_declared_memory(dev); + out_release_region: release_mem_region(base_addr, mem_size); out_free: kfree(p); @@ -321,7 +336,7 @@ NCR_Q720_remove(struct device *dev) if(p->hosts[i]) NCR_Q720_remove_one(p->hosts[i]); - iounmap((void *)p->mem_base); + dma_release_declared_memory(dev); release_mem_region(p->phys_mem_base, p->mem_size); free_irq(p->irq, p); kfree(p); --- linux-2.6.8-rc1/drivers/scsi/pcmcia/Kconfig 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/scsi/pcmcia/Kconfig 2004-07-13 17:35:09.000000000 -0700 @@ -17,7 +17,7 @@ config PCMCIA_AHA152X config PCMCIA_FDOMAIN tristate "Future Domain PCMCIA support" - depends on m + depends on m && ISA help Say Y here if you intend to attach this type of PCMCIA SCSI host adapter to your computer. --- linux-2.6.8-rc1/drivers/scsi/ppa.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/scsi/ppa.c 2004-07-13 17:09:13.000000000 -0700 @@ -682,7 +682,7 @@ static void ppa_interrupt(void *data) ppa_pb_dismiss(dev); - dev->cur_cmd = 0; + dev->cur_cmd = NULL; cmd->scsi_done(cmd); } --- linux-2.6.8-rc1/drivers/scsi/qla1280.c 2004-07-11 14:13:28.000000000 -0700 +++ 25/drivers/scsi/qla1280.c 2004-07-13 17:09:24.000000000 -0700 @@ -4,7 +4,7 @@ * QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver * Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) * Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc. -* Copyright (C) 2003 Christoph Hellwig +* Copyright (C) 2003-2004 Christoph Hellwig * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,9 +17,12 @@ * General Public License for more details. * ******************************************************************************/ -#define QLA1280_VERSION "3.24.3" +#define QLA1280_VERSION "3.24.4" /***************************************************************************** Revision History: + Rev 3.24.4 June 7, 2004 Christoph Hellwig + - restructure firmware loading, cleanup initialization code + - prepare support for ISP1020/1040 chips Rev 3.24.3 January 19, 2004, Jes Sorensen - Handle PCI DMA mask settings correctly - Correct order of error handling in probe_one, free_irq should not @@ -485,6 +488,14 @@ static inline void scsi_host_put(struct #define ia64_platform_is(foo) (!strcmp(x, platform_name)) #endif + +#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) +#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) +#define IS_ISP1x160(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \ + ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160) + + static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *); static void qla1280_remove_one(struct pci_dev *); @@ -501,9 +512,7 @@ static int qla1280_setup(char *s) __init /* * QLogic ISP1280 Hardware Support Function Prototypes. */ -static int qla1280_isp_firmware(struct scsi_qla_host *); -static int qla1280_chip_diag(struct scsi_qla_host *); -static int qla1280_setup_chip(struct scsi_qla_host *); +static int qla1280_load_firmware(struct scsi_qla_host *); static int qla1280_init_rings(struct scsi_qla_host *); static int qla1280_nvram_config(struct scsi_qla_host *); static int qla1280_mailbox_command(struct scsi_qla_host *, @@ -1384,16 +1393,10 @@ qla1280_set_target_parameters(struct scs uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; - int is1x160, status; + int status; nv = &ha->nvram; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; /* Set Target Parameters. */ @@ -1403,17 +1406,16 @@ qla1280_set_target_parameters(struct scs mb[2] = (nv->bus[bus].target[target].parameter.c << 8); - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - - if (is1x160) { + if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; + mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; + mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; + } else { + mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | + nv->bus[bus].target[target].sync_period; } status = qla1280_mailbox_command(ha, mr, &mb[0]); @@ -1476,8 +1478,7 @@ qla1280_slave_configure(struct scsi_devi (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) nv->bus[bus].target[target].parameter.f.enable_wide = 0; - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) { + if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && (~driver_setup.ppr_mask & (1 << target)))) @@ -1802,17 +1803,8 @@ qla1280_initialize_adapter(struct scsi_q */ spin_lock_irqsave(HOST_LOCK, flags); #endif - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware(ha)) { - if (!(status = qla1280_chip_diag(ha))) { - status = qla1280_setup_chip(ha); - } - } else { - printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", - ha->host_no); - status = 1; - } + status = qla1280_load_firmware(ha); if (status) { printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", ha->host_no); @@ -1823,36 +1815,24 @@ qla1280_initialize_adapter(struct scsi_q dprintk(1, "scsi(%ld): Configure NVRAM parameters\n", ha->host_no); qla1280_nvram_config(ha); - if (!ha->flags.disable_host_adapter && !qla1280_init_rings(ha)) { - /* Issue SCSI reset. */ - /* dg 03/13 if we can't reset twice then bus is dead */ - for (bus = 0; bus < ha->ports; bus++) { - if (!ha->bus_settings[bus].disable_scsi_reset){ - if (qla1280_bus_reset(ha, bus)) { - if (qla1280_bus_reset(ha, bus)) { - ha->bus_settings[bus].scsi_bus_dead = 1; - } - } - } - } + if (ha->flags.disable_host_adapter) { + status = 1; + goto out; + } - /* - * qla1280_bus_reset() will take care of issueing markers, - * no need to do that here as well! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus].reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL); - } -#endif + status = qla1280_init_rings(ha); + if (status) + goto out; - ha->flags.online = 1; - } else - status = 1; + /* Issue SCSI reset, if we can't reset twice then bus is dead */ + for (bus = 0; bus < ha->ports; bus++) { + if (!ha->bus_settings[bus].disable_scsi_reset && + qla1280_bus_reset(ha, bus) && + qla1280_bus_reset(ha, bus)) + ha->bus_settings[bus].scsi_bus_dead = 1; + } + ha->flags.online = 1; out: #if LINUX_VERSION_CODE >= 0x020500 spin_unlock_irqrestore(HOST_LOCK, flags); @@ -1945,13 +1925,13 @@ qla1280_chip_diag(struct scsi_qla_host * int status = 0; int cnt; uint16_t data; - dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", ®->id_l); dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no); /* Soft reset chip and wait for it to finish. */ WRT_REG_WORD(®->ictrl, ISP_RESET); + /* * We can't do a traditional PCI write flush here by reading * back the register. The card will not respond once the reset @@ -1969,145 +1949,138 @@ qla1280_chip_diag(struct scsi_qla_host * data = RD_REG_WORD(®->ictrl); } - if (cnt) { - /* Reset register cleared by chip reset. */ - dprintk(3, "qla1280_chip_diag: reset register cleared by " - "chip reset\n"); + if (!cnt) + goto fail; - WRT_REG_WORD(®->cfg_1, 0); + /* Reset register cleared by chip reset. */ + dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n"); - /* Reset RISC and disable BIOS which - allows RISC to execute out of RAM. */ -#if 0 - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); -#else - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | - HC_RELEASE_RISC | HC_DISABLE_BIOS); -#endif - RD_REG_WORD(®->id_l); /* Flush PCI write */ - data = qla1280_debounce_register(®->mailbox0); - /* - * I *LOVE* this code! - */ - for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { - udelay(5); - data = RD_REG_WORD(®->mailbox0); - } + WRT_REG_WORD(®->cfg_1, 0); - if (cnt) { - /* Check product ID of chip */ - dprintk(3, "qla1280_chip_diag: Checking product " - "ID of chip\n"); - - if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || - (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && - RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || - RD_REG_WORD(®->mailbox3) != PROD_ID_3 || - RD_REG_WORD(®->mailbox4) != PROD_ID_4) { - printk(KERN_INFO "qla1280: Wrong product ID = " - "0x%x,0x%x,0x%x,0x%x\n", - RD_REG_WORD(®->mailbox1), - RD_REG_WORD(®->mailbox2), - RD_REG_WORD(®->mailbox3), - RD_REG_WORD(®->mailbox4)); - status = 1; - } else { - /* - * Enable ints early!!! - */ - qla1280_enable_intrs(ha); - - dprintk(1, "qla1280_chip_diag: Checking " - "mailboxes of chip\n"); - /* Wrap Incoming Mailboxes Test. */ - mb[0] = MBC_MAILBOX_REGISTER_TEST; - mb[1] = 0xAAAA; - mb[2] = 0x5555; - mb[3] = 0xAA55; - mb[4] = 0x55AA; - mb[5] = 0xA5A5; - mb[6] = 0x5A5A; - mb[7] = 0x2525; - if (!(status = qla1280_mailbox_command(ha, - 0xff, - &mb - [0]))) { - if (mb[1] != 0xAAAA || - mb[2] != 0x5555 || - mb[3] != 0xAA55 || - mb[4] != 0x55AA || - mb[5] != 0xA5A5 || - mb[6] != 0x5A5A || - mb[7] != 0x2525) { - status = 1; - printk(KERN_INFO "qla1280: " - "Failed mbox check\n"); - } - } - } - } else - status = 1; - } else - status = 1; + /* Reset RISC and disable BIOS which + allows RISC to execute out of RAM. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | + HC_RELEASE_RISC | HC_DISABLE_BIOS); + + RD_REG_WORD(®->id_l); /* Flush PCI write */ + data = qla1280_debounce_register(®->mailbox0); + + /* + * I *LOVE* this code! + */ + for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { + udelay(5); + data = RD_REG_WORD(®->mailbox0); + } + + if (!cnt) + goto fail; + + /* Check product ID of chip */ + dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n"); + + if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + RD_REG_WORD(®->mailbox4) != PROD_ID_4) { + printk(KERN_INFO "qla1280: Wrong product ID = " + "0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4)); + goto fail; + } + /* + * Enable ints early!!! + */ + qla1280_enable_intrs(ha); + + dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n"); + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + + status = qla1280_mailbox_command(ha, 0xff, mb); if (status) - dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); - else - dprintk(3, "qla1280_chip_diag: exiting normally\n"); + goto fail; + if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 || + mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525) { + printk(KERN_INFO "qla1280: Failed mbox check\n"); + goto fail; + } + + dprintk(3, "qla1280_chip_diag: exiting normally\n"); + return 0; + fail: + dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); return status; } -/* - * Setup chip - * Load and start RISC firmware. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - */ -#define DUMP_IT_BACK 0 /* for debug of RISC loading */ static int -qla1280_setup_chip(struct scsi_qla_host *ha) +qla1280_load_firmware_pio(struct scsi_qla_host *ha) { - int status = 0; - uint16_t risc_address; - uint16_t *risc_code_address; - int risc_code_size; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t cnt; - int num, i; -#if DUMP_IT_BACK - uint8_t *sp; - uint8_t *tbuf; - dma_addr_t p_tbuf; -#endif + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], i; + int err; - ENTER("qla1280_setup_chip"); + /* Load RISC code. */ + risc_address = *ql1280_board_tbl[ha->devnum].fwstart; + risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; - dprintk(1, "scsi(%ld): Setup chip\n", ha->host_no); + for (i = 0; i < risc_code_size; i++) { + mb[0] = MBC_WRITE_RAM_WORD; + mb[1] = risc_address + i; + mb[2] = risc_code_address[i]; + + err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to load firmware\n", + ha->host_no); + return err; + } + } + return 0; +} + +#define DUMP_IT_BACK 0 /* for debug of RISC loading */ +static int +qla1280_load_firmware_dma(struct scsi_qla_host *ha) +{ + uint16_t risc_address, *risc_code_address, risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT], cnt; + int err = 0, num, i; #if DUMP_IT_BACK - /* get consistent memory allocated for setup_chip */ + uint8_t *sp, *tbuf; + dma_addr_t p_tbuf; + tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); + if (!tbuf) + return -ENOMEM; #endif /* Load RISC code. */ risc_address = *ql1280_board_tbl[ha->devnum].fwstart; risc_code_address = ql1280_board_tbl[ha->devnum].fwcode; - risc_code_size = (int) *ql1280_board_tbl[ha->devnum].fwlen; + risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen; - dprintk(1, "qla1280_setup_chip: DMA RISC code (%i) words\n", - risc_code_size); + dprintk(1, "%s: DMA RISC code (%i) words\n", + __FUNCTION__, risc_code_size); num = 0; - while (risc_code_size > 0 && !status) { + while (risc_code_size > 0) { int warn __attribute__((unused)) = 0; cnt = 2000 >> 1; @@ -2129,15 +2102,16 @@ qla1280_setup_chip(struct scsi_qla_host mb[2] = (ha->request_dma >> 16) & 0xffff; mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; mb[6] = pci_dma_hi32(ha->request_dma) >> 16; - dprintk(2, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," - "0x%4x,0x%4x\n", mb[0], (void *)(long)ha->request_dma, - mb[6], mb[7], mb[2], mb[3]); - if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | - BIT_2 | BIT_1 | BIT_0, - &mb[0]))) { + dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", + __FUNCTION__, mb[0], + (void *)(long)ha->request_dma, + mb[6], mb[7], mb[2], mb[3]); + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "scsi(%li): Failed to load partial " "segment of f\n", ha->host_no); - break; + goto out; } #if DUMP_IT_BACK @@ -2149,22 +2123,22 @@ qla1280_setup_chip(struct scsi_qla_host mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; mb[6] = pci_dma_hi32(p_tbuf) >> 16; - if ((status = qla1280_mailbox_command(ha, - BIT_4 | BIT_3 | BIT_2 | - BIT_1 | BIT_0, - &mb[0]))) { + err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | + BIT_1 | BIT_0, mb); + if (err) { printk(KERN_ERR "Failed to dump partial segment of f/w\n"); - break; + goto out; } sp = (uint8_t *)ha->request_ring; for (i = 0; i < (cnt << 1); i++) { if (tbuf[i] != sp[i] && warn++ < 10) { - printk(KERN_ERR "qla1280_setup_chip: FW " - "compare error @ byte(0x%x) loop#=%x\n", - i, num); - printk(KERN_ERR "setup_chip: FWbyte=%x " - "FWfromChip=%x\n", sp[i], tbuf[i]); + printk(KERN_ERR "%s: FW compare error @ " + "byte(0x%x) loop#=%x\n", + __FUNCTION__, i, num); + printk(KERN_ERR "%s: FWbyte=%x " + "FWfromChip=%x\n", + __FUNCTION__, sp[i], tbuf[i]); /*break; */ } } @@ -2175,37 +2149,69 @@ qla1280_setup_chip(struct scsi_qla_host num++; } - /* Verify checksum of loaded RISC code. */ - if (!status) { - dprintk(1, "qla1280_setup_chip: Verifying checksum of " - "loaded RISC code.\n"); - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - - if (!(status = - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { - /* Start firmware execution. */ - dprintk(1, - "qla1280_setup_chip: start firmware running.\n"); - mb[0] = MBC_EXECUTE_FIRMWARE; - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - } else - printk(KERN_ERR "scsi(%li): qla1280_setup_chip: " - "Failed checksum\n", ha->host_no); - } - + out: #if DUMP_IT_BACK - /* free consistent memory allocated for setup_chip */ pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); #endif + return err; +} - if (status) - dprintk(2, "qla1280_setup_chip: **** FAILED ****\n"); +static int +qla1280_start_firmware(struct scsi_qla_host *ha) +{ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int err; - LEAVE("qla1280_setup_chip"); - return status; + dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", + __FUNCTION__); + + /* Verify checksum of loaded RISC code. */ + mb[0] = MBC_VERIFY_CHECKSUM; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + if (err) { + printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no); + return err; + } + + /* Start firmware execution. */ + dprintk(1, "%s: start firmware running.\n", __FUNCTION__); + mb[0] = MBC_EXECUTE_FIRMWARE; + mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; + err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + if (err) { + printk(KERN_ERR "scsi(%li): Failed to start firmware\n", + ha->host_no); + } + + return err; +} + +static int +qla1280_load_firmware(struct scsi_qla_host *ha) +{ + int err = -ENODEV; + + /* If firmware needs to be loaded */ + if (!qla1280_isp_firmware(ha)) { + printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", + ha->host_no); + goto out; + } + + err = qla1280_chip_diag(ha); + if (err) + goto out; + if (IS_ISP1040(ha)) + err = qla1280_load_firmware_pio(ha); + else + err = qla1280_load_firmware_dma(ha); + if (err) + goto out; + err = qla1280_start_firmware(ha); + out: + return err; } /* @@ -2271,123 +2277,9 @@ qla1280_init_rings(struct scsi_qla_host return status; } -/* - * NVRAM configuration. - * - * Input: - * ha = adapter block pointer. - * ha->request_ring = request ring virtual address - * - * Output: - * host adapters parameters in host adapter block - * - * Returns: - * 0 = success. - */ -static int -qla1280_nvram_config(struct scsi_qla_host *ha) +static void +qla1280_print_settings(struct nvram *nv) { - struct device_reg *reg = ha->iobase; - struct nvram *nv; - int is1x160, status = 0; - int bus, target, lun; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t mask; - - ENTER("qla1280_nvram_config"); - - if (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160 || - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160) - is1x160 = 1; - else - is1x160 = 0; - - nv = &ha->nvram; - if (!ha->nvram_valid) { - dprintk(1, "Using defaults for NVRAM: \n"); - memset(nv, 0, sizeof(struct nvram)); - - /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ - nv->firmware_feature.f.enable_fast_posting = 1; - nv->firmware_feature.f.disable_synchronous_backoff = 1; - - nv->termination.f.scsi_bus_0_control = 3; - nv->termination.f.scsi_bus_1_control = 3; - nv->termination.f.auto_term_support = 1; - - /* - * Set default FIFO magic - What appropriate values - * would be here is unknown. This is what I have found - * testing with 12160s. - * Now, I would love the magic decoder ring for this one, - * the header file provided by QLogic seems to be bogus - * or incomplete at best. - */ - nv->isp_config.c = 0x44; - - if (is1x160) - nv->isp_parameter = 0x01; - - for (bus = 0; bus < MAX_BUSES; bus++) { - nv->bus[bus].config_1.initiator_id = 7; - nv->bus[bus].bus_reset_delay = 5; - /* 8 = 5.0 clocks */ - nv->bus[bus].config_2.async_data_setup_time = 8; - nv->bus[bus].config_2.req_ack_active_negation = 1; - nv->bus[bus].config_2.data_line_active_negation = 1; - nv->bus[bus].selection_timeout = 250; - nv->bus[bus].max_queue_depth = 256; - - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - tag_queuing = 1; - nv->bus[bus].target[target].parameter.f. - enable_sync = 1; -#if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.f. - enable_wide = 1; -#endif - nv->bus[bus].target[target].parameter.f. - parity_checking = 1; - nv->bus[bus].target[target].parameter.f. - disconnect_allowed = 1; - nv->bus[bus].target[target].execution_throttle= - nv->bus[bus].max_queue_depth - 1; - if (is1x160) { - nv->bus[bus].target[target].flags. - flags1x160.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x160.sync_offset = 0x0e; - nv->bus[bus].target[target]. - sync_period = 9; - nv->bus[bus].target[target]. - ppr_1x160.flags.enable_ppr = 1; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_options = 2; - nv->bus[bus].target[target].ppr_1x160. - flags.ppr_bus_width = 1; - } else { - nv->bus[bus].target[target].flags. - flags1x80.device_enable = 1; - nv->bus[bus].target[target].flags. - flags1x80.sync_offset = 0x8; - nv->bus[bus].target[target]. - sync_period = 10; - } - } - } - } else { - /* Always force AUTO sense for LINUX SCSI */ - for (bus = 0; bus < MAX_BUSES; bus++) - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - } - } dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n", nv->bus[0].config_1.initiator_id); dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n", @@ -2433,36 +2325,264 @@ qla1280_nvram_config(struct scsi_qla_hos nv->bus[0].max_queue_depth); dprintk(1, "qla1280 : max queue depth[1]=%d\n", nv->bus[1].max_queue_depth); +} + +static void +qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + + nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1; + nv->bus[bus].target[target].parameter.f.auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f.tag_queuing = 1; + nv->bus[bus].target[target].parameter.f.enable_sync = 1; +#if 1 /* Some SCSI Processors do not seem to like this */ + nv->bus[bus].target[target].parameter.f.enable_wide = 1; +#endif + if (!IS_ISP1040(ha)) + nv->bus[bus].target[target].parameter.f.parity_checking = 1; + + nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1; + nv->bus[bus].target[target].execution_throttle = + nv->bus[bus].max_queue_depth - 1; + + if (IS_ISP1x160(ha)) { + nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x160.sync_offset = 0x0e; + nv->bus[bus].target[target].sync_period = 9; + nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_options = 2; + nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width = 1; + } else { + nv->bus[bus].target[target].flags.flags1x80.device_enable = 1; + nv->bus[bus].target[target].flags.flags1x80.sync_offset = 12; + nv->bus[bus].target[target].sync_period = 10; + } +} + +static void +qla1280_set_defaults(struct scsi_qla_host *ha) +{ + struct nvram *nv = &ha->nvram; + int bus, target; + + dprintk(1, "Using defaults for NVRAM: \n"); + memset(nv, 0, sizeof(struct nvram)); + + /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ + nv->firmware_feature.f.enable_fast_posting = 1; + nv->firmware_feature.f.disable_synchronous_backoff = 1; + nv->termination.f.scsi_bus_0_control = 3; + nv->termination.f.scsi_bus_1_control = 3; + nv->termination.f.auto_term_support = 1; + + /* + * Set default FIFO magic - What appropriate values would be here + * is unknown. This is what I have found testing with 12160s. + * + * Now, I would love the magic decoder ring for this one, the + * header file provided by QLogic seems to be bogus or incomplete + * at best. + */ + nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128; + if (IS_ISP1x160(ha)) + nv->isp_parameter = 0x01; /* fast memory enable */ + + for (bus = 0; bus < MAX_BUSES; bus++) { + nv->bus[bus].config_1.initiator_id = 7; + nv->bus[bus].config_2.req_ack_active_negation = 1; + nv->bus[bus].config_2.data_line_active_negation = 1; + nv->bus[bus].selection_timeout = 250; + nv->bus[bus].max_queue_depth = 256; + + if (IS_ISP1040(ha)) { + nv->bus[bus].bus_reset_delay = 3; + nv->bus[bus].config_2.async_data_setup_time = 6; + nv->bus[bus].retry_delay = 1; + } else { + nv->bus[bus].bus_reset_delay = 5; + nv->bus[bus].config_2.async_data_setup_time = 8; + } + + for (target = 0; target < MAX_TARGETS; target++) + qla1280_set_target_defaults(ha, bus, target); + } +} + +static int +qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int status, lun; + + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t) (bus ? target | BIT_7 : target); + mb[1] <<= 8; + + /* + * Do not enable wide, sync, and ppr for the initial + * INQUIRY run. We enable this later if we determine + * the target actually supports it. + */ + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + nv->bus[bus].target[target].parameter.f. + stop_queue_on_check = 0; + + if (IS_ISP1x160(ha)) + nv->bus[bus].target[target].ppr_1x160. + flags.enable_ppr = 0; + + /* + * No sync, wide, etc. while probing + */ + mb[2] = (nv->bus[bus].target[target].parameter.c << 8) & + ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); + + if (IS_ISP1x160(ha)) + mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; + else + mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; + mb[3] |= nv->bus[bus].target[target].sync_period; + + status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); + + /* Save Tag queuing enable flag. */ + mb[0] = BIT_0 << target; + if (nv->bus[bus].target[target].parameter.f.tag_queuing) + ha->bus_settings[bus].qtag_enables |= mb[0]; + + /* Save Device enable flag. */ + if (IS_ISP1x160(ha)) { + if (nv->bus[bus].target[target].flags.flags1x160.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].lun_disables |= 0; + } else { + if (nv->bus[bus].target[target].flags.flags1x80.device_enable) + ha->bus_settings[bus].device_enables |= mb[0]; + /* Save LUN disable flag. */ + if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) + ha->bus_settings[bus].lun_disables |= mb[0]; + } + + /* Set Device Queue Parameters. */ + for (lun = 0; lun < MAX_LUNS; lun++) { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)(bus ? target | BIT_7 : target); + mb[1] = mb[1] << 8 | lun; + mb[2] = nv->bus[bus].max_queue_depth; + mb[3] = nv->bus[bus].target[target].execution_throttle; + status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]); + } + + return status; +} + +static int +qla1280_config_bus(struct scsi_qla_host *ha, int bus) +{ + struct nvram *nv = &ha->nvram; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + int target, status; + + /* SCSI Reset Disable. */ + ha->bus_settings[bus].disable_scsi_reset = + nv->bus[bus].config_1.scsi_reset_disable; + + /* Initiator ID. */ + ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; + mb[0] = MBC_SET_INITIATOR_ID; + mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : + ha->bus_settings[bus].id; + status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + + /* Reset Delay. */ + ha->bus_settings[bus].bus_reset_delay = + nv->bus[bus].bus_reset_delay; + + /* Command queue depth per device. */ + ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; + + /* Set target parameters. */ + for (target = 0; target < MAX_TARGETS; target++) + status |= qla1280_config_target(ha, bus, target); + + return status; +} + +static int +qla1280_nvram_config(struct scsi_qla_host *ha) +{ + struct device_reg *reg = ha->iobase; + struct nvram *nv = &ha->nvram; + int bus, target, status = 0; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint16_t mask; + + ENTER("qla1280_nvram_config"); + + if (ha->nvram_valid) { + /* Always force AUTO sense for LINUX SCSI */ + for (bus = 0; bus < MAX_BUSES; bus++) + for (target = 0; target < MAX_TARGETS; target++) { + nv->bus[bus].target[target].parameter.f. + auto_request_sense = 1; + } + } else { + qla1280_set_defaults(ha); + } + + qla1280_print_settings(nv); /* Disable RISC load of firmware. */ ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; - /* Set ISP hardware DMA burst */ - mb[0] = nv->isp_config.c; - /* Enable DMA arbitration on dual channel controllers */ - if (ha->ports > 1) - mb[0] |= BIT_13; - WRT_REG_WORD(®->cfg_1, mb[0]); - -#if 1 /* Is this safe? */ - /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); - mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); - WRT_REG_WORD(®->gpio_data, mb[0]); -#endif + if (IS_ISP1040(ha)) { + uint16_t hwrev, cfg1, cdma_conf, ddma_conf; + + hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; + + cfg1 = RD_REG_WORD(®->cfg_1); + cdma_conf = RD_REG_WORD(®->cdma_cfg); + ddma_conf = RD_REG_WORD(®->ddma_cfg); + + /* Busted fifo, says mjacob. */ + if (hwrev == ISP_CFG0_1040A) + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64); + else + WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB); + + WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); + WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); + } else { + /* Set ISP hardware DMA burst */ + mb[0] = nv->isp_config.c; + /* Enable DMA arbitration on dual channel controllers */ + if (ha->ports > 1) + mb[0] |= BIT_13; + WRT_REG_WORD(®->cfg_1, mb[0]); + + /* Set SCSI termination. */ + WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); + mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); + WRT_REG_WORD(®->gpio_data, mb[0]); + } /* ISP parameter word. */ mb[0] = MBC_SET_SYSTEM_PARAMETER; mb[1] = nv->isp_parameter; status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#if 0 - /* clock rate - for qla1240 and older, only */ - mb[0] = MBC_SET_CLOCK_RATE; - mb[1] = 0x50; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); -#endif + if (IS_ISP1x40(ha)) { + /* clock rate - for qla1240 and older, only */ + mb[0] = MBC_SET_CLOCK_RATE; + mb[1] = 40; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); + } + /* Firmware feature word. */ mb[0] = MBC_SET_FIRMWARE_FEATURES; mask = BIT_5 | BIT_1 | BIT_0; @@ -2515,112 +2635,18 @@ qla1280_nvram_config(struct scsi_qla_hos mb[2] = 2; /* Command DMA Channel Burst Enable */ status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + mb[0] = MBC_SET_TAG_AGE_LIMIT; + mb[1] = 8; + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + /* Selection timeout. */ mb[0] = MBC_SET_SELECTION_TIMEOUT; mb[1] = nv->bus[0].selection_timeout; mb[2] = nv->bus[1].selection_timeout; status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - for (bus = 0; bus < ha->ports; bus++) { - /* SCSI Reset Disable. */ - ha->bus_settings[bus].disable_scsi_reset = - nv->bus[bus].config_1.scsi_reset_disable; - - /* Initiator ID. */ - ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; - mb[0] = MBC_SET_INITIATOR_ID; - mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : - ha->bus_settings[bus].id; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - /* Reset Delay. */ - ha->bus_settings[bus].bus_reset_delay = - nv->bus[bus].bus_reset_delay; - - /* Command queue depth per device. */ - ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; - - /* Set target parameters. */ - for (target = 0; target < MAX_TARGETS; target++) { - uint8_t mr = BIT_2 | BIT_1 | BIT_0; - - /* Set Target Parameters. */ - mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - /* - * Do not enable wide, sync, and ppr for the initial - * INQUIRY run. We enable this later if we determine - * the target actually supports it. - */ - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - stop_queue_on_check = 0; - - if (is1x160) - nv->bus[bus].target[target].ppr_1x160. - flags.enable_ppr = 0; - /* - * No sync, wide, etc. while probing - */ - mb[2] = (nv->bus[bus].target[target].parameter.c << 8)& - ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); - - if (is1x160) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - mr |= BIT_3; - - /* - * We don't want to enable ppr etc. before we have - * determined that the target actually supports it - */ -#if 0 - if (is1x160) { - mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - - mb[6] = nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8; - mb[6] |= nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; - mr |= BIT_6; - } -#endif - - status = qla1280_mailbox_command(ha, mr, &mb[0]); - - /* Save Tag queuing enable flag. */ - mb[0] = BIT_0 << target; - if (nv->bus[bus].target[target].parameter.f.tag_queuing) - ha->bus_settings[bus].qtag_enables |= mb[0]; - - /* Save Device enable flag. */ - if (is1x160) { - if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - ha->bus_settings[bus].lun_disables |= 0; - } else { - if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; - /* Save LUN disable flag. */ - if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= mb[0]; - } - - - /* Set Device Queue Parameters. */ - for (lun = 0; lun < MAX_LUNS; lun++) { - mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)(bus ? target | BIT_7 : target); - mb[1] = mb[1] << 8 | lun; - mb[2] = nv->bus[bus].max_queue_depth; - mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, - &mb[0]); - } - } - } + for (bus = 0; bus < ha->ports; bus++) + status |= qla1280_config_bus(ha, bus); if (status) dprintk(2, "qla1280_nvram_config: **** FAILED ****\n"); @@ -4231,6 +4257,7 @@ qla1280_error_entry(struct scsi_qla_host static int qla1280_abort_isp(struct scsi_qla_host *ha) { + struct device_reg *reg = ha->iobase; struct srb *sp; int status = 0; int cnt; @@ -4238,69 +4265,53 @@ qla1280_abort_isp(struct scsi_qla_host * ENTER("qla1280_abort_isp"); - if (!ha->flags.abort_isp_active && ha->flags.online) { - struct device_reg *reg = ha->iobase; - ha->flags.abort_isp_active = 1; + if (ha->flags.abort_isp_active || !ha->flags.online) + goto out; + + ha->flags.abort_isp_active = 1; - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); - RD_REG_WORD(®->id_l); + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + RD_REG_WORD(®->id_l); - printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", - ha->host_no); - /* Dequeue all commands in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - struct scsi_cmnd *cmd; - sp = ha->outstanding_cmds[cnt]; - if (sp) { + printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", + ha->host_no); + /* Dequeue all commands in outstanding command list. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { + struct scsi_cmnd *cmd; + sp = ha->outstanding_cmds[cnt]; + if (sp) { - cmd = sp->cmd; - CMD_RESULT(cmd) = DID_RESET << 16; + cmd = sp->cmd; + CMD_RESULT(cmd) = DID_RESET << 16; - sp->cmd = NULL; - ha->outstanding_cmds[cnt] = NULL; + sp->cmd = NULL; + ha->outstanding_cmds[cnt] = NULL; - (*cmd->scsi_done)(cmd); + (*cmd->scsi_done)(cmd); - sp->flags = 0; - } + sp->flags = 0; } + } - /* If firmware needs to be loaded */ - if (qla1280_isp_firmware (ha)) { - if (!(status = qla1280_chip_diag(ha))) - status = qla1280_setup_chip(ha); - } + status = qla1280_load_firmware(ha); + if (status) + goto out; - if (!status) { - /* Setup adapter based on NVRAM parameters. */ - qla1280_nvram_config (ha); - - if (!(status = qla1280_init_rings(ha))) { - /* Issue SCSI reset. */ - for (bus = 0; bus < ha->ports; bus++) { - qla1280_bus_reset(ha, bus); - } - /* - * qla1280_bus_reset() will do the marker - * dance - no reason to repeat here! - */ -#if 0 - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports; bus++) { - ha->bus_settings[bus]. - reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, - MK_SYNC_ALL); - } -#endif - ha->flags.abort_isp_active = 0; - } - } - } + /* Setup adapter based on NVRAM parameters. */ + qla1280_nvram_config (ha); + status = qla1280_init_rings(ha); + if (status) + goto out; + + /* Issue SCSI reset. */ + for (bus = 0; bus < ha->ports; bus++) + qla1280_bus_reset(ha, bus); + + ha->flags.abort_isp_active = 0; + out: if (status) { printk(KERN_WARNING "qla1280: ISP error recovery failed, board disabled"); --- linux-2.6.8-rc1/drivers/scsi/qla1280.h 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/scsi/qla1280.h 2004-07-13 17:09:24.000000000 -0700 @@ -126,7 +126,20 @@ struct device_reg { uint16_t id_l; /* ID low */ uint16_t id_h; /* ID high */ uint16_t cfg_0; /* Configuration 0 */ +#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */ +#define ISP_CFG0_1020 BIT_0 /* ISP1020 */ +#define ISP_CFG0_1020A BIT_1 /* ISP1020A */ +#define ISP_CFG0_1040 BIT_2 /* ISP1040 */ +#define ISP_CFG0_1040A BIT_3 /* ISP1040A */ +#define ISP_CFG0_1040B BIT_4 /* ISP1040B */ +#define ISP_CFG0_1040C BIT_5 /* ISP1040C */ uint16_t cfg_1; /* Configuration 1 */ +#define ISP_CFG1_F128 BIT_6 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F64 BIT_4|BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F32 BIT_5 /* 128-byte FIFO threshold */ +#define ISP_CFG1_F16 BIT_4 /* 128-byte FIFO threshold */ +#define ISP_CFG1_BENAB BIT_2 /* Global Bus burst enable */ +#define ISP_CFG1_SXP BIT_0 /* SXP register select */ uint16_t ictrl; /* Interface control */ #define ISP_RESET BIT_0 /* ISP soft reset */ #define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ @@ -147,7 +160,42 @@ struct device_reg { uint16_t flash_data; /* Flash BIOS data */ uint16_t flash_address; /* Flash BIOS address */ - uint16_t unused_1[0x2e]; /* 0x14-0x6f Gap */ + uint16_t unused_1[0x06]; + + /* cdma_* and ddma_* are 1040 only */ + uint16_t cdma_cfg; +#define CDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define CDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define CDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define CDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t cdma_ctrl; + uint16_t cdma_status; + uint16_t cdma_fifo_status; + uint16_t cdma_count; + uint16_t cdma_reserved; + uint16_t cdma_address_count_0; + uint16_t cdma_address_count_1; + uint16_t cdma_address_count_2; + uint16_t cdma_address_count_3; + + uint16_t unused_2[0x06]; + + uint16_t ddma_cfg; +#define DDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ +#define DDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ +#define DDMA_CONF_BENAB BIT_1 /* Bus burst enable */ +#define DDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ + uint16_t ddma_ctrl; + uint16_t ddma_status; + uint16_t ddma_fifo_status; + uint16_t ddma_xfer_count_low; + uint16_t ddma_xfer_count_high; + uint16_t ddma_addr_count_0; + uint16_t ddma_addr_count_1; + uint16_t ddma_addr_count_2; + uint16_t ddma_addr_count_3; + + uint16_t unused_3[0x0e]; uint16_t mailbox0; /* Mailbox 0 */ uint16_t mailbox1; /* Mailbox 1 */ @@ -158,18 +206,18 @@ struct device_reg { uint16_t mailbox6; /* Mailbox 6 */ uint16_t mailbox7; /* Mailbox 7 */ - uint16_t unused_2[0x20];/* 0x80-0xbf Gap */ + uint16_t unused_4[0x20];/* 0x80-0xbf Gap */ uint16_t host_cmd; /* Host command and control */ #define HOST_INT BIT_7 /* host interrupt bit */ #define BIOS_ENABLE BIT_0 - uint16_t unused_6[0x5]; /* 0xc2-0xcb Gap */ + uint16_t unused_5[0x5]; /* 0xc2-0xcb Gap */ uint16_t gpio_data; uint16_t gpio_enable; - uint16_t unused_7[0x11]; /* d0-f0 */ + uint16_t unused_6[0x11]; /* d0-f0 */ uint16_t scsiControlPins; /* f2 */ }; --- linux-2.6.8-rc1/drivers/scsi/qlogicpti.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/scsi/qlogicpti.c 2004-07-13 17:09:24.000000000 -0700 @@ -27,6 +27,8 @@ #include +#include "scsi.h" +#include #include "qlogicpti.h" #include --- linux-2.6.8-rc1/drivers/scsi/sata_nv.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_nv.c 2004-07-13 17:09:22.000000000 -0700 @@ -39,6 +39,7 @@ #define NV_PORTS 2 #define NV_PIO_MASK 0x1f +#define NV_MWDMA_MASK 0x07 #define NV_UDMA_MASK 0x7f #define NV_PORT0_BMDMA_REG_OFFSET 0x00 #define NV_PORT1_BMDMA_REG_OFFSET 0x08 @@ -289,6 +290,7 @@ static int nv_init_one (struct pci_dev * probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; probe_ent->pio_mask = NV_PIO_MASK; + probe_ent->mwdma_mask = NV_MWDMA_MASK; probe_ent->udma_mask = NV_UDMA_MASK; probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); --- linux-2.6.8-rc1/drivers/scsi/sata_promise.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_promise.c 2004-07-13 17:09:22.000000000 -0700 @@ -74,7 +74,6 @@ struct pdc_port_priv { static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); @@ -83,8 +82,6 @@ static void pdc_phy_reset(struct ata_por static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); @@ -130,7 +127,8 @@ static struct ata_port_info pdc_port_inf .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -140,7 +138,8 @@ static struct ata_port_info pdc_port_inf .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_sata_ops, }, @@ -269,26 +268,26 @@ static void pdc_qc_prep(struct ata_queue VPRINTK("ENTER\n"); - ata_qc_prep(qc); - - i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, qc->dev->devno, pp->pkt); + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + ata_qc_prep(qc); + /* fall through */ - if (qc->tf.flags & ATA_TFLAG_LBA48) - i = pdc_prep_lba48(&qc->tf, pp->pkt, i); - else - i = pdc_prep_lba28(&qc->tf, pp->pkt, i); + case ATA_PROT_NODATA: + i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma, + qc->dev->devno, pp->pkt); - pdc_pkt_footer(&qc->tf, pp->pkt, i); -} + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, pp->pkt, i); + else + i = pdc_prep_lba28(&qc->tf, pp->pkt, i); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; + pdc_pkt_footer(&qc->tf, pp->pkt, i); + break; - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); + default: + break; + } } static void pdc_eng_timeout(struct ata_port *ap) @@ -315,17 +314,9 @@ static void pdc_eng_timeout(struct ata_p switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -358,13 +349,8 @@ static inline unsigned int pdc_host_intr switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_complete(ap, qc, have_err); - handled = 1; - break; - - case ATA_PROT_NODATA: /* command completion, but no data xfer */ - status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); + case ATA_PROT_NODATA: + status = ata_wait_idle(ap); if (have_err) status |= ATA_ERR; ata_qc_complete(qc, status); @@ -440,7 +426,7 @@ static irqreturn_t pdc_interrupt (int ir return IRQ_RETVAL(handled); } -static inline void pdc_dma_start(struct ata_queued_cmd *qc) +static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; @@ -462,7 +448,8 @@ static int pdc_qc_issue_prot(struct ata_ { switch (qc->tf.protocol) { case ATA_PROT_DMA: - pdc_dma_start(qc); + case ATA_PROT_NODATA: + pdc_packet_start(qc); return 0; case ATA_PROT_ATAPI_DMA: @@ -478,14 +465,16 @@ static int pdc_qc_issue_prot(struct ata_ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); ata_tf_load_mmio(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - WARN_ON (tf->protocol == ATA_PROT_DMA); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); ata_exec_command_mmio(ap, tf); } @@ -539,8 +528,7 @@ static void pdc_host_init(unsigned int c writel(tmp, mmio + PDC_TBG_MODE); readl(mmio + PDC_TBG_MODE); /* flush */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10) + 1); + msleep(10); /* adjust slew rate control register. */ tmp = readl(mmio + PDC_SLEW_CTL); @@ -601,6 +589,7 @@ static int pdc_sata_init_one (struct pci probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; --- linux-2.6.8-rc1/drivers/scsi/sata_sil.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_sil.c 2004-07-13 17:09:22.000000000 -0700 @@ -149,7 +149,8 @@ static struct ata_port_info sil_port_inf .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, /* sil_3114 */ @@ -157,7 +158,8 @@ static struct ata_port_info sil_port_inf .sht = &sil_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, }, @@ -363,6 +365,7 @@ static int sil_init_one (struct pci_dev probe_ent->sht = sil_port_info[ent->driver_data].sht; probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2; probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask; + probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask; probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; --- linux-2.6.8-rc1/drivers/scsi/sata_sis.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_sis.c 2004-07-13 17:09:22.000000000 -0700 @@ -230,7 +230,8 @@ static int sis_init_one (struct pci_dev probe_ent->host_flags |= SIS_FLAG_CFGSCR; } - probe_ent->pio_mask = 0x03; + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; probe_ent->port_ops = &sis_ops; --- linux-2.6.8-rc1/drivers/scsi/sata_svw.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_svw.c 2004-07-13 17:09:22.000000000 -0700 @@ -343,6 +343,7 @@ static int k2_sata_init_one (struct pci_ * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ --- linux-2.6.8-rc1/drivers/scsi/sata_sx4.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_sx4.c 2004-07-13 17:09:22.000000000 -0700 @@ -146,8 +146,6 @@ struct pdc_host_priv { static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void pdc20621_dma_setup(struct ata_queued_cmd *qc); -static void pdc20621_dma_start(struct ata_queued_cmd *qc); static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static void pdc_eng_timeout(struct ata_port *ap); static void pdc_20621_phy_reset (struct ata_port *ap); @@ -157,8 +155,6 @@ static void pdc20621_qc_prep(struct ata_ static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, int have_err); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, @@ -172,6 +168,7 @@ static void pdc20621_get_from_dimm(struc static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); static Scsi_Host_Template pdc_sata_sht = { @@ -199,10 +196,8 @@ static struct ata_port_operations pdc_20 .check_status = ata_check_status_mmio, .exec_command = pdc_exec_command_mmio, .phy_reset = pdc_20621_phy_reset, - .bmdma_setup = pdc20621_dma_setup, - .bmdma_start = pdc20621_dma_start, .qc_prep = pdc20621_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_issue = pdc20621_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, @@ -217,7 +212,8 @@ static struct ata_port_info pdc_port_inf .sht = &pdc_sata_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &pdc_20621_ops, }, @@ -377,7 +373,10 @@ static inline unsigned int pdc20621_ata_ /* dimm dma S/G, and next-pkt */ dw = i >> 2; - buf32[dw] = cpu_to_le32(dimm_sg); + if (tf->protocol == ATA_PROT_NODATA) + buf32[dw] = 0; + else + buf32[dw] = cpu_to_le32(dimm_sg); buf32[dw + 1] = 0; i += 8; @@ -437,7 +436,7 @@ static inline void pdc20621_host_pkt(str buf32[dw + 3]); } -static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; @@ -449,8 +448,7 @@ static void pdc20621_qc_prep(struct ata_ unsigned int i, last, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; - if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; + assert(qc->flags & ATA_QCFLAG_DMAMAP); VPRINTK("ata%u: ENTER\n", ap->id); @@ -501,6 +499,56 @@ static void pdc20621_qc_prep(struct ata_ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); } +static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pdc_port_priv *pp = ap->private_data; + void *mmio = ap->host_set->mmio_base; + struct pdc_host_priv *hpriv = ap->host_set->private_data; + void *dimm_mmio = hpriv->dimm_mmio; + unsigned int portno = ap->port_no; + unsigned int i; + + VPRINTK("ata%u: ENTER\n", ap->id); + + /* hard-code chip #0 */ + mmio += PDC_CHIP0_OFS; + + i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno); + + if (qc->tf.flags & ATA_TFLAG_LBA48) + i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i); + else + i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i); + + pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i); + + /* copy three S/G tables and two packets to DIMM MMIO window */ + memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP), + &pp->dimm_buf, PDC_DIMM_HEADER_SZ); + + /* force host FIFO dump */ + writel(0x00000001, mmio + PDC_20621_GENERAL_CTL); + + readl(dimm_mmio); /* MMIO PCI posting flush */ + + VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len); +} + +static void pdc20621_qc_prep(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + pdc20621_dma_prep(qc); + break; + case ATA_PROT_NODATA: + pdc20621_nodata_prep(qc); + break; + default: + break; + } +} + static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, unsigned int seq, u32 pkt_ofs) @@ -576,13 +624,7 @@ static void pdc20621_dump_hdma(struct at static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { } #endif /* ATA_VERBOSE_DEBUG */ -static void pdc20621_dma_setup(struct ata_queued_cmd *qc) -{ - /* nothing for now. later, we will call standard - * code in libata-core for ATAPI here */ -} - -static void pdc20621_dma_start(struct ata_queued_cmd *qc) +static void pdc20621_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; @@ -590,24 +632,21 @@ static void pdc20621_dma_start(struct at void *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); - unsigned int doing_hdma = 0, port_ofs; + unsigned int port_ofs; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; VPRINTK("ata%u: ENTER\n", ap->id); + wmb(); /* flush PRD, pkt writes */ + port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no); /* if writing, we (1) DMA to DIMM, then (2) do ATA command */ - if (rw) { - doing_hdma = 1; + if (rw && qc->tf.protocol == ATA_PROT_DMA) { seq += 4; - } - wmb(); /* flush PRD, pkt writes */ - - if (doing_hdma) { pdc20621_dump_hdma(qc); pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT); VPRINTK("queued ofs 0x%x (%u), seq %u\n", @@ -628,6 +667,25 @@ static void pdc20621_dma_start(struct at } } +static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) +{ + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + pdc20621_packet_start(qc); + return 0; + + case ATA_PROT_ATAPI_DMA: + BUG(); + break; + + default: + break; + } + + return ata_qc_issue_prot(qc); +} + static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, @@ -648,7 +706,8 @@ static inline unsigned int pdc20621_host if (doing_hdma) { VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } @@ -685,7 +744,8 @@ static inline unsigned int pdc20621_host else { VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); - pdc_dma_complete(ap, qc, 0); + /* get drive status; clear intr; complete txn */ + ata_qc_complete(qc, ata_wait_idle(ap)); pdc20621_pop_hdma(qc); } handled = 1; @@ -779,16 +839,6 @@ static irqreturn_t pdc20621_interrupt (i return IRQ_RETVAL(handled); } -static inline void pdc_dma_complete (struct ata_port *ap, - struct ata_queued_cmd *qc, - int have_err) -{ - u8 err_bit = have_err ? ATA_ERR : 0; - - /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap) | err_bit); -} - static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; @@ -813,17 +863,9 @@ static void pdc_eng_timeout(struct ata_p switch (qc->tf.protocol) { case ATA_PROT_DMA: - printk(KERN_ERR "ata%u: DMA timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); - break; - case ATA_PROT_NODATA: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n", - ap->id, qc->tf.command, drv_stat); - - ata_qc_complete(qc, drv_stat); + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); break; default: @@ -842,15 +884,17 @@ out: static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_tf_load_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_tf_load_mmio(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) { - if (tf->protocol != ATA_PROT_DMA) - ata_exec_command_mmio(ap, tf); + WARN_ON (tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_NODATA); + ata_exec_command_mmio(ap, tf); } @@ -1384,6 +1428,7 @@ static int pdc_sata_init_one (struct pci probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->host_flags = pdc_port_info[board_idx].host_flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; + probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask; probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask; probe_ent->port_ops = pdc_port_info[board_idx].port_ops; @@ -1394,21 +1439,11 @@ static int pdc_sata_init_one (struct pci probe_ent->private_data = hpriv; base += PDC_CHIP0_OFS; + probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); pdc_sata_setup_port(&probe_ent->port[1], base + 0x280); - - /* notice 4-port boards */ - switch (board_idx) { - case board_20621: - probe_ent->n_ports = 4; - - pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); - break; - default: - BUG(); - break; - } + pdc_sata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_sata_setup_port(&probe_ent->port[3], base + 0x380); pci_set_master(pdev); --- linux-2.6.8-rc1/drivers/scsi/sata_via.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_via.c 2004-07-13 17:09:22.000000000 -0700 @@ -214,6 +214,7 @@ static int svia_init_one (struct pci_dev probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); --- linux-2.6.8-rc1/drivers/scsi/sata_vsc.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sata_vsc.c 2004-07-13 17:09:22.000000000 -0700 @@ -320,6 +320,7 @@ static int __devinit vsc_sata_init_one ( * if we don't fill these */ probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; /* We have 4 ports per PCI function */ --- linux-2.6.8-rc1/drivers/scsi/scsiiom.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/scsiiom.c 2004-07-13 17:09:24.000000000 -0700 @@ -890,14 +890,22 @@ dc390_DataIO_Comm( struct dc390_acb* pAC if (pSRB == pACB->pTmpSRB) { - if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", - pDCB->TargetID, pDCB->TargetLUN); - else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); - - pSRB->pSRBDCB = pDCB; - dc390_EnableMsgOut_Abort (pACB, pSRB); - if (pDCB) pDCB->DCBFlag |= ABORT_DEV; - return; + if (pDCB) + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); + else + printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + + /* Try to recover - some broken disks react badly to tagged INQUIRY */ + if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) { + pSRB = pDCB->pGoingSRB; + pDCB->pActiveSRB = pSRB; + } else { + pSRB->pSRBDCB = pDCB; + dc390_EnableMsgOut_Abort(pACB, pSRB); + if (pDCB) + pDCB->DCBFlag |= ABORT_DEV; + return; + } } if( pSRB->SGIndex < pSRB->SGcount ) --- linux-2.6.8-rc1/drivers/scsi/scsi_lib.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/scsi_lib.c 2004-07-13 17:09:31.000000000 -0700 @@ -954,6 +954,22 @@ static int scsi_init_io(struct scsi_cmnd return BLKPREP_KILL; } +static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_driver *drv; + + if (sdev->sdev_state != SDEV_RUNNING) + return -ENXIO; + + drv = *(struct scsi_driver **) disk->private_data; + if (drv->issue_flush) + return drv->issue_flush(&sdev->sdev_gendev, error_sector); + + return -EOPNOTSUPP; +} + static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; @@ -1335,7 +1351,8 @@ struct request_queue *scsi_alloc_queue(s blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); - + blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); return q; --- linux-2.6.8-rc1/drivers/scsi/scsi_sysfs.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/scsi_sysfs.c 2004-07-13 17:09:24.000000000 -0700 @@ -525,8 +525,11 @@ int scsi_sysfs_add_sdev(struct scsi_devi **/ void scsi_remove_device(struct scsi_device *sdev) { + struct Scsi_Host *shost = sdev->host; + + down(&shost->scan_mutex); if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) - return; + goto out; class_device_unregister(&sdev->sdev_classdev); if (sdev->transport_classdev.class) @@ -538,6 +541,9 @@ void scsi_remove_device(struct scsi_devi if (sdev->host->transportt->cleanup) sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); + +out: + up(&shost->scan_mutex); } int scsi_register_driver(struct device_driver *drv) --- linux-2.6.8-rc1/drivers/scsi/sd.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sd.c 2004-07-13 17:09:31.000000000 -0700 @@ -113,6 +113,7 @@ static int sd_remove(struct device *); static void sd_shutdown(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); +static int sd_issue_flush(struct device *, sector_t *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); @@ -126,6 +127,7 @@ static struct scsi_driver sd_template = }, .rescan = sd_rescan, .init_command = sd_init_command, + .issue_flush = sd_issue_flush, }; /* Device no to disk mapping: @@ -676,6 +678,62 @@ not_present: return 1; } +static int sd_sync_cache(struct scsi_device *sdp) +{ + struct scsi_request *sreq; + int retries, res; + + if (!scsi_device_online(sdp)) + return -ENODEV; + + sreq = scsi_allocate_request(sdp, GFP_KERNEL); + if (!sreq) { + printk("FAILED\n No memory for request\n"); + return -ENOMEM; + } + + sreq->sr_data_direction = DMA_NONE; + for (retries = 3; retries > 0; --retries) { + unsigned char cmd[10] = { 0 }; + + cmd[0] = SYNCHRONIZE_CACHE; + /* + * Leave the rest of the command zero to indicate + * flush everything. + */ + scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); + if (sreq->sr_result == 0) + break; + } + + res = sreq->sr_result; + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + scsi_print_req_sense("sd", sreq); + } + + scsi_release_request(sreq); + return res; +} + +static int sd_issue_flush(struct device *dev, sector_t *error_sector) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + if (!sdkp) + return -ENODEV; + + if (!sdkp->WCE) + return 0; + + return sd_sync_cache(sdp); +} + static void sd_rescan(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); @@ -1503,52 +1561,17 @@ static void scsi_disk_release(struct kre static void sd_shutdown(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); - struct scsi_disk *sdkp; - struct scsi_request *sreq; - int retries, res; + struct scsi_disk *sdkp = dev_get_drvdata(dev); - sdkp = dev_get_drvdata(dev); if (!sdkp) - return; /* this can happen */ + return; /* this can happen */ - if (!scsi_device_online(sdp) || !sdkp->WCE) + if (!sdkp->WCE) return; - printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ", + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", sdkp->disk->disk_name); - - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk("FAILED\n No memory for request\n"); - return; - } - - sreq->sr_data_direction = DMA_NONE; - for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* - * Leave the rest of the command zero to indicate - * flush everything. - */ - scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); - if (sreq->sr_result == 0) - break; - } - - res = sreq->sr_result; - if (res) { - printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " - "host = %d, driver = %02x\n ", - status_byte(res), msg_byte(res), - host_byte(res), driver_byte(res)); - if (driver_byte(res) & DRIVER_SENSE) - scsi_print_req_sense("sd", sreq); - } - - scsi_release_request(sreq); - printk("\n"); + sd_sync_cache(sdp); } /** --- linux-2.6.8-rc1/drivers/scsi/sr.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/scsi/sr.c 2004-07-13 17:09:41.000000000 -0700 @@ -183,7 +183,7 @@ int sr_media_change(struct cdrom_device_ return -EINVAL; } - retval = scsi_ioctl(cd->device, SCSI_IOCTL_TEST_UNIT_READY, 0); + retval = scsi_ioctl(cd->device, SCSI_IOCTL_TEST_UNIT_READY, NULL); if (retval) { /* Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, @@ -379,6 +379,7 @@ static int sr_init_command(struct scsi_c return 0; SCpnt->cmnd[0] = WRITE_10; SCpnt->sc_data_direction = DMA_TO_DEVICE; + cd->cdi.media_written = 1; } else if (rq_data_dir(SCpnt->request) == READ) { SCpnt->cmnd[0] = READ_10; SCpnt->sc_data_direction = DMA_FROM_DEVICE; @@ -880,10 +881,10 @@ static void get_capabilities(struct scsi cd->cdi.mask |= CDC_CLOSE_TRAY; */ /* - * if DVD-RAM of MRW-W, we are randomly writeable + * if DVD-RAM, MRW-W or CD-RW, we are randomly writable */ - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) != - (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) { + if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != + (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { cd->device->writeable = 1; set_disk_ro(cd->disk, 0); } --- linux-2.6.8-rc1/drivers/serial/8250.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/serial/8250.c 2004-07-13 17:09:26.000000000 -0700 @@ -832,7 +832,7 @@ receive_chars(struct uart_8250_port *up, if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { tty->flip.work.func((void *)tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) - return; // if TTY_DONT_FLIP is set + return; /* if TTY_DONT_FLIP is set */ } ch = serial_inp(up, UART_RX); *tty->flip.char_buf_ptr = ch; @@ -1193,12 +1193,22 @@ static void serial8250_break_ctl(struct spin_unlock_irqrestore(&up->port.lock, flags); } +#ifdef CONFIG_KGDB +static int kgdb_irq = -1; +static int kgdb_port = -1; +#endif + static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; int retval; +#ifdef CONFIG_KGDB + if (up->port.irq == kgdb_irq) + return -EBUSY; +#endif + up->capabilities = uart_config[up->port.type].flags; up->mcr = 0; @@ -1879,6 +1889,11 @@ static void __init serial8250_register_p for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i]; +#ifdef CONFIG_KGDB + /* at this point irq could be 0 for the port (KGDB_EARLY) */ + if (up->port.irq == kgdb_irq || up->port.iobase == kgdb_port) + up->port.kgdb = 1; +#endif up->port.line = i; up->port.ops = &serial8250_pops; init_timer(&up->timer); @@ -2162,6 +2177,32 @@ void serial8250_resume_port(int line) uart_resume_port(&serial8250_reg, &serial8250_ports[line].port); } +#ifdef CONFIG_KGDB +/* + * Find all the ports using the given irq and shut them down. + * Result should be that the irq will be released. + */ +void shutdown_for_kgdb(struct async_struct * info) +{ + int irq = info->state->irq; + struct uart_8250_port *up; + int ttyS; + + kgdb_irq = irq; /* save for later init */ + kgdb_port = info->port; + for (ttyS = 0; ttyS < UART_NR; ttyS++){ + up = &serial8250_ports[ttyS]; + if (up->port.irq == irq && (irq_lists + irq)->head) { +#ifdef CONFIG_DEBUG_SPINLOCK /* ugly business... */ + if(up->port.lock.magic != SPINLOCK_MAGIC) + spin_lock_init(&up->port.lock); +#endif + serial8250_shutdown(&up->port); + } + } +} +#endif /* CONFIG_KGDB */ + static int __init serial8250_init(void) { int ret, i; --- linux-2.6.8-rc1/drivers/serial/8250_pnp.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/serial/8250_pnp.c 2004-07-13 17:09:24.000000000 -0700 @@ -379,7 +379,7 @@ static int __devinit check_resources(str * PnP modems, alternatively we must hardcode all modems in pnp_devices[] * table. */ -static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) +static int serial_pnp_guess_board(struct pnp_dev *dev) { if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name)))) return -ENODEV; @@ -399,7 +399,7 @@ serial_pnp_probe(struct pnp_dev * dev, c struct serial_struct serial_req; int ret, line, flags = dev_id->driver_data; if (flags & UNKNOWN_DEV) { - ret = serial_pnp_guess_board(dev, &flags); + ret = serial_pnp_guess_board(dev); if (ret < 0) return ret; } @@ -430,11 +430,17 @@ static void __devexit serial_pnp_remove( unregister_serial(line - 1); } +static int serial_pnp_match(struct pnp_dev *dev) +{ + return serial_pnp_guess_board(dev); +} + static struct pnp_driver serial_pnp_driver = { .name = "serial", .id_table = pnp_dev_table, .probe = serial_pnp_probe, .remove = __devexit_p(serial_pnp_remove), + .match = serial_pnp_match, }; static int __init serial8250_pnp_init(void) --- linux-2.6.8-rc1/drivers/serial/Kconfig 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/serial/Kconfig 2004-07-13 17:09:36.000000000 -0700 @@ -677,5 +677,40 @@ config SERIAL_CPM_SMC2 help Select the is option to use SMC2 as a serial port -endmenu +config SERIAL_MPC52xx + tristate "Freescale MPC52xx family PSC serial support" + depends on PPC_MPC52xx + select SERIAL_CORE + help + This drivers support the MPC52xx PSC serial ports. If you would + like to use them, you must answer Y or M to this option. Not that + for use as console, it must be included in kernel and not as a + module. +config SERIAL_MPC52xx_CONSOLE + bool "Console on a Freescale MPC52xx family PSC serial port" + depends on SERIAL_MPC52xx=y + select SERIAL_CORE_CONSOLE + help + Select this options if you'd like to use one of the PSC serial port + of the Freescale MPC52xx family as a console. + +config SERIAL_MPC52xx_CONSOLE_BAUD + int "Freescale MPC52xx family PSC serial port baud" + depends on SERIAL_MPC52xx_CONSOLE=y + default "9600" + help + Select the MPC52xx console baud rate. + This value is only used if the bootloader doesn't pass in the + console baudrate + +config SERIAL_SGI_L1_CONSOLE + bool "SGI Altix L1 serial console support" + depends on IA64_GENERIC || IA64_SGI_SN2 + select SERIAL_CORE + help + If you have an SGI Altix and you would like to use the system + controller serial port as your console (you want this!), + say Y. Otherwise, say N. + +endmenu --- linux-2.6.8-rc1/drivers/serial/Makefile 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/serial/Makefile 2004-07-13 17:09:36.000000000 -0700 @@ -38,4 +38,6 @@ obj-$(CONFIG_SERIAL_AU1X00) += au1x00_ua obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o obj-$(CONFIG_SERIAL_BAST_SIO) += bast_sio.o +obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ +obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/serial/mpc52xx_uart.c 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,869 @@ +/* + * drivers/serial/mpc52xx_uart.c + * + * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. + * + * FIXME According to the usermanual the status bits in the status register + * are only updated when the peripherals access the FIFO and not when the + * CPU access them. So since we use this bits to know when we stop writing + * and reading, they may not be updated in-time and a race condition may + * exists. But I haven't be able to prove this and I don't care. But if + * any problem arises, it might worth checking. The TX/RX FIFO Stats + * registers should be used in addition. + * Update: Actually, they seem updated ... At least the bits we use. + * + * + * Maintainer : Sylvain Munaut + * + * Some of the code has been inspired/copied from the 2.4 code written + * by Dale Farnsworth . + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/* OCP Usage : + * + * This drivers uses the OCP model. To load the serial driver for one of the + * PSCs, just add this to the core_ocp table : + * + * { + * .vendor = OCP_VENDOR_FREESCALE, + * .function = OCP_FUNC_PSC_UART, + * .index = 0, + * .paddr = MPC52xx_PSC1, + * .irq = MPC52xx_PSC1_IRQ, + * .pm = OCP_CPM_NA, + * }, + * + * This is for PSC1, replace the paddr and irq according to the PSC you want to + * use. The driver all necessary registers to place the PSC in uart mode without + * DCD. However, the pin multiplexing aren't changed and should be set either + * by the bootloader or in the platform init code. + * The index field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2, + * and so on). So the PSC1 is mapped to /dev/ttyS0, PSC2 to /dev/ttyS1 and so + * on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly for + * the console code : without this 1:1 mapping, at early boot time, when we are + * parsing the kernel args console=ttyS?, we wouldn't know wich PSC it will be + * mapped to because OCP stuff is not yet initialized. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + + + +#define ISR_PASS_LIMIT 256 /* Max number of iteration in the interrupt */ + + +static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM]; + /* Rem: - We use the read_status_mask as a shadow of + * psc->mpc52xx_psc_imr + * - It's important that is array is all zero on start as we + * use it to know if it's initialized or not ! If it's not sure + * it's cleared, then a memset(...,0,...) should be added to + * the console_init + */ + +#define PSC(port) ((struct mpc52xx_psc *)((port)->membase)) + + +/* Forward declaration of the interruption handling routine */ +static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs); + + +/* Simple macro to test if a port is console or not. This one is taken + * for serial_core.c and maybe should be moved to serial_core.h ? */ +#ifdef CONFIG_SERIAL_CORE_CONSOLE +#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) +#else +#define uart_console(port) (0) +#endif + + +/* ======================================================================== */ +/* UART operations */ +/* ======================================================================== */ + +static unsigned int +mpc52xx_uart_tx_empty(struct uart_port *port) +{ + int status = in_be16(&PSC(port)->mpc52xx_psc_status); + return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; +} + +static void +mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* Not implemented */ +} + +static unsigned int +mpc52xx_uart_get_mctrl(struct uart_port *port) +{ + /* Not implemented */ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void +mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + /* port->lock taken by caller */ + port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); +} + +static void +mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start) +{ + /* port->lock taken by caller */ + port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); +} + +static void +mpc52xx_uart_send_xchar(struct uart_port *port, char ch) +{ + unsigned long flags; + spin_lock_irqsave(&port->lock, flags); + + port->x_char = ch; + if (ch) { + /* Make sure tx interrupts are on */ + /* Truly necessary ??? They should be anyway */ + port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +mpc52xx_uart_stop_rx(struct uart_port *port) +{ + /* port->lock taken by caller */ + port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY; + out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask); +} + +static void +mpc52xx_uart_enable_ms(struct uart_port *port) +{ + /* Not implemented */ +} + +static void +mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) +{ + unsigned long flags; + spin_lock_irqsave(&port->lock, flags); + + if ( ctl == -1 ) + out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK); + else + out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static int +mpc52xx_uart_startup(struct uart_port *port) +{ + struct mpc52xx_psc *psc = PSC(port); + + /* Reset/activate the port, clear and enable interrupts */ + out_8(&psc->command,MPC52xx_PSC_RST_RX); + out_8(&psc->command,MPC52xx_PSC_RST_TX); + + out_be32(&psc->sicr,0); /* UART mode DCD ignored */ + + out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */ + + out_8(&psc->rfcntl, 0x00); + out_be16(&psc->rfalarm, 0x1ff); + out_8(&psc->tfcntl, 0x07); + out_be16(&psc->tfalarm, 0x80); + + port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY; + out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); + + out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); + + return 0; +} + +static void +mpc52xx_uart_shutdown(struct uart_port *port) +{ + struct mpc52xx_psc *psc = PSC(port); + + /* Shut down the port, interrupt and all */ + out_8(&psc->command,MPC52xx_PSC_RST_RX); + out_8(&psc->command,MPC52xx_PSC_RST_TX); + + port->read_status_mask = 0; + out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask); +} + +static void +mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new, + struct termios *old) +{ + struct mpc52xx_psc *psc = PSC(port); + unsigned long flags; + unsigned char mr1, mr2; + unsigned short ctr; + unsigned int j, baud, quot; + + /* Prepare what we're gonna write */ + mr1 = 0; + + switch (new->c_cflag & CSIZE) { + case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS; + break; + case CS6: mr1 |= MPC52xx_PSC_MODE_6_BITS; + break; + case CS7: mr1 |= MPC52xx_PSC_MODE_7_BITS; + break; + case CS8: + default: mr1 |= MPC52xx_PSC_MODE_8_BITS; + } + + if (new->c_cflag & PARENB) { + mr1 |= (new->c_cflag & PARODD) ? + MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; + } else + mr1 |= MPC52xx_PSC_MODE_PARNONE; + + + mr2 = 0; + + if (new->c_cflag & CSTOPB) + mr2 |= MPC52xx_PSC_MODE_TWO_STOP; + else + mr2 |= ((new->c_cflag & CSIZE) == CS5) ? + MPC52xx_PSC_MODE_ONE_STOP_5_BITS : + MPC52xx_PSC_MODE_ONE_STOP; + + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); + quot = uart_get_divisor(port, baud); + ctr = quot & 0xffff; + + /* Get the lock */ + spin_lock_irqsave(&port->lock, flags); + + /* Update the per-port timeout */ + uart_update_timeout(port, new->c_cflag, baud); + + /* Do our best to flush TX & RX, so we don't loose anything */ + /* But we don't wait indefinitly ! */ + j = 5000000; /* Maximum wait */ + /* FIXME Can't receive chars since set_termios might be called at early + * boot for the console, all stuff is not yet ready to receive at that + * time and that just makes the kernel oops */ + /* while (j-- && mpc52xx_uart_int_rx_chars(port)); */ + while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && + --j) + udelay(1); + + if (!j) + printk( KERN_ERR "mpc52xx_uart.c: " + "Unable to flush RX & TX fifos in-time in set_termios." + "Some chars may have been lost.\n" ); + + /* Reset the TX & RX */ + out_8(&psc->command,MPC52xx_PSC_RST_RX); + out_8(&psc->command,MPC52xx_PSC_RST_TX); + + /* Send new mode settings */ + out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&psc->mode,mr1); + out_8(&psc->mode,mr2); + out_8(&psc->ctur,ctr >> 8); + out_8(&psc->ctlr,ctr & 0xff); + + /* Reenable TX & RX */ + out_8(&psc->command,MPC52xx_PSC_TX_ENABLE); + out_8(&psc->command,MPC52xx_PSC_RX_ENABLE); + + /* We're all set, release the lock */ + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char * +mpc52xx_uart_type(struct uart_port *port) +{ + return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL; +} + +static void +mpc52xx_uart_release_port(struct uart_port *port) +{ + if (port->flags & UPF_IOREMAP) { /* remapped by us ? */ + iounmap(port->membase); + port->membase = NULL; + } +} + +static int +mpc52xx_uart_request_port(struct uart_port *port) +{ + if (port->flags & UPF_IOREMAP) /* Need to remap ? */ + port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc)); + + return port->membase != NULL ? 0 : -EBUSY; +} + +static void +mpc52xx_uart_config_port(struct uart_port *port, int flags) +{ + if ( (flags & UART_CONFIG_TYPE) && + (mpc52xx_uart_request_port(port) == 0) ) + port->type = PORT_MPC52xx; +} + +static int +mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx ) + return -EINVAL; + + if ( (ser->irq != port->irq) || + (ser->io_type != SERIAL_IO_MEM) || + (ser->baud_base != port->uartclk) || + // FIXME Should check addresses/irq as well ? + (ser->hub6 != 0 ) ) + return -EINVAL; + + return 0; +} + + +static struct uart_ops mpc52xx_uart_ops = { + .tx_empty = mpc52xx_uart_tx_empty, + .set_mctrl = mpc52xx_uart_set_mctrl, + .get_mctrl = mpc52xx_uart_get_mctrl, + .stop_tx = mpc52xx_uart_stop_tx, + .start_tx = mpc52xx_uart_start_tx, + .send_xchar = mpc52xx_uart_send_xchar, + .stop_rx = mpc52xx_uart_stop_rx, + .enable_ms = mpc52xx_uart_enable_ms, + .break_ctl = mpc52xx_uart_break_ctl, + .startup = mpc52xx_uart_startup, + .shutdown = mpc52xx_uart_shutdown, + .set_termios = mpc52xx_uart_set_termios, +/* .pm = mpc52xx_uart_pm, Not supported yet */ +/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ + .type = mpc52xx_uart_type, + .release_port = mpc52xx_uart_release_port, + .request_port = mpc52xx_uart_request_port, + .config_port = mpc52xx_uart_config_port, + .verify_port = mpc52xx_uart_verify_port +}; + + +/* ======================================================================== */ +/* Interrupt handling */ +/* ======================================================================== */ + +static inline int +mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs) +{ + struct tty_struct *tty = port->info->tty; + unsigned char ch; + unsigned short status; + + /* While we can read, do so ! */ + while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) & + MPC52xx_PSC_SR_RXRDY) { + + /* If we are full, just stop reading */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + + /* Get the char */ + ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8); + + /* Handle sysreq char */ +#ifdef SUPPORT_SYSRQ + if (uart_handle_sysrq_char(port, ch, regs)) { + port->sysrq = 0; + continue; + } +#endif + + /* Store it */ + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = 0; + port->icount.rx++; + + if ( status & (MPC52xx_PSC_SR_PE | + MPC52xx_PSC_SR_FE | + MPC52xx_PSC_SR_RB | + MPC52xx_PSC_SR_OE) ) { + + if (status & MPC52xx_PSC_SR_RB) { + *tty->flip.flag_buf_ptr = TTY_BREAK; + uart_handle_break(port); + } else if (status & MPC52xx_PSC_SR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & MPC52xx_PSC_SR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (status & MPC52xx_PSC_SR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < (TTY_FLIPBUF_SIZE-1)) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + + /* Clear error condition */ + out_8(&PSC(port)->command,MPC52xx_PSC_RST_ERR_STAT); + + } + + tty->flip.char_buf_ptr++; + tty->flip.flag_buf_ptr++; + tty->flip.count++; + + } + + tty_flip_buffer_push(tty); + + return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY; +} + +static inline int +mpc52xx_uart_int_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + /* Process out of band chars */ + if (port->x_char) { + out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char); + port->icount.tx++; + port->x_char = 0; + return 1; + } + + /* Nothing to do ? */ + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + mpc52xx_uart_stop_tx(port,0); + return 0; + } + + /* Send chars */ + while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) { + out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + /* Wake up */ + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* Maybe we're done after all */ + if (uart_circ_empty(xmit)) { + mpc52xx_uart_stop_tx(port,0); + return 0; + } + + return 1; +} + +static irqreturn_t +mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = (struct uart_port *) dev_id; + unsigned long pass = ISR_PASS_LIMIT; + unsigned int keepgoing; + unsigned short status; + + if ( irq != port->irq ) { + printk( KERN_WARNING + "mpc52xx_uart_int : " \ + "Received wrong int %d. Waiting for %d\n", + irq, port->irq); + return IRQ_NONE; + } + + spin_lock(&port->lock); + + /* While we have stuff to do, we continue */ + do { + /* If we don't find anything to do, we stop */ + keepgoing = 0; + + /* Read status */ + status = in_be16(&PSC(port)->mpc52xx_psc_isr); + status &= port->read_status_mask; + + /* Do we need to receive chars ? */ + /* For this RX interrupts must be on and some chars waiting */ + if ( status & MPC52xx_PSC_IMR_RXRDY ) + keepgoing |= mpc52xx_uart_int_rx_chars(port, regs); + + /* Do we need to send chars ? */ + /* For this, TX must be ready and TX interrupt enabled */ + if ( status & MPC52xx_PSC_IMR_TXRDY ) + keepgoing |= mpc52xx_uart_int_tx_chars(port); + + /* Limit number of iteration */ + if ( !(--pass) ) + keepgoing = 0; + + } while (keepgoing); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + + +/* ======================================================================== */ +/* Console ( if applicable ) */ +/* ======================================================================== */ + +#ifdef CONFIG_SERIAL_MPC52xx_CONSOLE + +static void __init +mpc52xx_console_get_options(struct uart_port *port, + int *baud, int *parity, int *bits, int *flow) +{ + struct mpc52xx_psc *psc = PSC(port); + unsigned char mr1; + + /* Read the mode registers */ + out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1); + mr1 = in_8(&psc->mode); + + /* CT{U,L}R are write-only ! */ + *baud = __res.bi_baudrate ? + __res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; + + /* Parse them */ + switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) { + case MPC52xx_PSC_MODE_5_BITS: *bits = 5; break; + case MPC52xx_PSC_MODE_6_BITS: *bits = 6; break; + case MPC52xx_PSC_MODE_7_BITS: *bits = 7; break; + case MPC52xx_PSC_MODE_8_BITS: + default: *bits = 8; + } + + if (mr1 & MPC52xx_PSC_MODE_PARNONE) + *parity = 'n'; + else + *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e'; +} + +static void +mpc52xx_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &mpc52xx_uart_ports[co->index]; + struct mpc52xx_psc *psc = PSC(port); + unsigned int i, j; + + /* Disable interrupts */ + out_be16(&psc->mpc52xx_psc_imr, 0); + + /* Wait the TX buffer to be empty */ + j = 5000000; /* Maximum wait */ + while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && + --j) + udelay(1); + + /* Write all the chars */ + for ( i=0 ; impc52xx_psc_buffer_8, *s); + + /* Line return handling */ + if ( *s++ == '\n' ) + out_8(&psc->mpc52xx_psc_buffer_8, '\r'); + + /* Wait the TX buffer to be empty */ + j = 20000; /* Maximum wait */ + while (!(in_be16(&psc->mpc52xx_psc_status) & + MPC52xx_PSC_SR_TXEMP) && --j) + udelay(1); + } + + /* Restore interrupt state */ + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); +} + +static int __init +mpc52xx_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &mpc52xx_uart_ports[co->index]; + + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM) + return -EINVAL; + + /* Basic port init. Needed since we use some uart_??? func before + * real init for early access */ + port->lock = SPIN_LOCK_UNLOCKED; + port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ + port->ops = &mpc52xx_uart_ops; + port->mapbase = MPC52xx_PSCx(co->index); + + /* We ioremap ourself */ + port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc)); + if (port->membase == NULL) { + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); + return -EBUSY; + } + + /* Setup the port parameters accoding to options */ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + + +extern struct uart_driver mpc52xx_uart_driver; + +static struct console mpc52xx_console = { + .name = "ttyS", + .write = mpc52xx_console_write, + .device = uart_console_device, + .setup = mpc52xx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, /* Specified on the cmdline (e.g. console=ttyS0 ) */ + .data = &mpc52xx_uart_driver, +}; + + +static int __init +mpc52xx_console_init(void) +{ + register_console(&mpc52xx_console); + return 0; +} + +console_initcall(mpc52xx_console_init); + +#define MPC52xx_PSC_CONSOLE &mpc52xx_console +#else +#define MPC52xx_PSC_CONSOLE NULL +#endif + + +/* ======================================================================== */ +/* UART Driver */ +/* ======================================================================== */ + +static struct uart_driver mpc52xx_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "mpc52xx_psc_uart", + .dev_name = "ttyS", + .devfs_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = MPC52xx_PSC_MAXNUM, + .cons = MPC52xx_PSC_CONSOLE, +}; + + +/* ======================================================================== */ +/* OCP Driver */ +/* ======================================================================== */ + +static int __devinit +mpc52xx_uart_probe(struct ocp_device *ocp) +{ + struct uart_port *port = NULL; + int idx, ret; + + /* Get the corresponding port struct */ + idx = ocp->def->index; + if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM) + return -EINVAL; + + port = &mpc52xx_uart_ports[idx]; + + /* Init the port structure */ + port->lock = SPIN_LOCK_UNLOCKED; + port->mapbase = ocp->def->paddr; + port->irq = ocp->def->irq; + port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */ + port->fifosize = 255; /* Should be 512 ! But it can't be */ + /* stored in a unsigned char */ + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF | + ( uart_console(port) ? 0 : UPF_IOREMAP ); + port->line = idx; + port->ops = &mpc52xx_uart_ops; + port->read_status_mask = 0; + + /* Requests the mem & irqs */ + /* Unlike other serial drivers, we reserve the resources here, so we + * can detect early if multiple drivers uses the same PSC. Special + * care must be taken with the console PSC + */ + ret = request_irq( + port->irq, mpc52xx_uart_int, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port); + if (ret) + goto error; + + ret = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), + "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; + if (ret) + goto free_irq; + + /* Add the port to the uart sub-system */ + ret = uart_add_one_port(&mpc52xx_uart_driver, port); + if (ret) + goto release_mem; + + ocp_set_drvdata(ocp, (void*)port); + + return 0; + + +free_irq: + free_irq(port->irq, mpc52xx_uart_int); + +release_mem: + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); + +error: + if (uart_console(port)) + printk( "mpc52xx_uart.c: Error during resource alloction for " + "the console port !!! Check that the console PSC is " + "not used by another OCP driver !!!\n" ); + + return ret; +} + +static void +mpc52xx_uart_remove(struct ocp_device *ocp) +{ + struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); + + ocp_set_drvdata(ocp, NULL); + + if (port) { + uart_remove_one_port(&mpc52xx_uart_driver, port); + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); + free_irq(port->irq, mpc52xx_uart_int); + } +} + +#ifdef CONFIG_PM +static int +mpc52xx_uart_suspend(struct ocp_device *ocp, u32 state) +{ + struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); + + uart_suspend_port(&mpc52xx_uart_driver, port); + + return 0; +} + +static int +mpc52xx_uart_resume(struct ocp_device *ocp) +{ + struct uart_port *port = (struct uart_port *) ocp_get_drvdata(ocp); + + uart_resume_port(&mpc52xx_uart_driver, port); + + return 0; +} +#endif + +static struct ocp_device_id mpc52xx_uart_ids[] __devinitdata = { + { .vendor = OCP_VENDOR_FREESCALE, .function = OCP_FUNC_PSC_UART }, + { .vendor = OCP_VENDOR_INVALID /* Terminating entry */ } +}; + +MODULE_DEVICE_TABLE(ocp, mpc52xx_uart_ids); + +static struct ocp_driver mpc52xx_uart_ocp_driver = { + .name = "mpc52xx_psc_uart", + .id_table = mpc52xx_uart_ids, + .probe = mpc52xx_uart_probe, + .remove = mpc52xx_uart_remove, +#ifdef CONFIG_PM + .suspend = mpc52xx_uart_suspend, + .resume = mpc52xx_uart_resume, +#endif +}; + + +/* ======================================================================== */ +/* Module */ +/* ======================================================================== */ + +static int __init +mpc52xx_uart_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: MPC52xx PSC driver\n"); + + ret = uart_register_driver(&mpc52xx_uart_driver); + if (ret) + return ret; + + ret = ocp_register_driver(&mpc52xx_uart_ocp_driver); + + return ret; +} + +static void __exit +mpc52xx_uart_exit(void) +{ + ocp_unregister_driver(&mpc52xx_uart_ocp_driver); + uart_unregister_driver(&mpc52xx_uart_driver); +} + + +module_init(mpc52xx_uart_init); +module_exit(mpc52xx_uart_exit); + +MODULE_AUTHOR("Sylvain Munaut "); +MODULE_DESCRIPTION("Freescale MPC52xx PSC UART"); +MODULE_LICENSE("GPL"); --- linux-2.6.8-rc1/drivers/serial/pmac_zilog.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/serial/pmac_zilog.c 2004-07-13 17:09:27.000000000 -0700 @@ -1490,6 +1490,7 @@ no_dma: uap->port.ops = &pmz_pops; uap->port.type = PORT_PMAC_ZILOG; uap->port.flags = 0; + spin_lock_init(&uap->port.lock); /* Setup some valid baud rate information in the register * shadows so we don't write crap there before baud rate is @@ -1985,8 +1986,6 @@ static int __init pmz_console_init(void) /* Probe ports */ pmz_probe(); -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE -#endif /* TODO: Autoprobe console based on OF */ /* pmz_console.index = i; */ register_console(&pmz_console); --- linux-2.6.8-rc1/drivers/serial/serial_core.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/serial/serial_core.c 2004-07-13 17:09:25.000000000 -0700 @@ -1990,6 +1990,11 @@ uart_configure_port(struct uart_driver * { unsigned int flags; +#ifdef CONFIG_KGDB + if (port->kgdb) + return; +#endif + /* * If there isn't a port here, don't do anything further. */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/serial/sn_console.c 2004-07-13 17:09:36.000000000 -0700 @@ -0,0 +1,1191 @@ +/* + * C-Brick Serial Port (and console) driver for SGI Altix machines. + * + * This driver is NOT suitable for talking to the l1-controller for + * anything other than 'console activities' --- please use the l1 + * driver for that. + * + * + * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for mdelay */ +#include +#include + +#include +#include +#include + +/* number of characters we can transmit to the SAL console at a time */ +#define SN_SAL_MAX_CHARS 120 + +/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to + * avoid losing chars, (always has to be a power of 2) */ +#define SN_SAL_BUFFER_SIZE (64 * (1 << 10)) + +#define SN_SAL_UART_FIFO_DEPTH 16 +#define SN_SAL_UART_FIFO_SPEED_CPS 9600/10 + +/* sn_transmit_chars() calling args */ +#define TRANSMIT_BUFFERED 0 +#define TRANSMIT_RAW 1 + +/* To use dynamic numbers only and not use the assigned major and minor, + * define the following.. */ +/* #define USE_DYNAMIC_MINOR 1 */ /* use dynamic minor number */ +#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */ + +/* Device name we're using */ +#define DEVICE_NAME "ttySG" +#define DEVICE_NAME_DYNAMIC "ttySG0" /* need full name for misc_register */ +/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */ +#define DEVICE_MAJOR 204 +#define DEVICE_MINOR 40 + +/* + * Port definition - this kinda drives it all + */ +struct sn_cons_port { + struct timer_list sc_timer; + struct uart_port sc_port; + struct sn_sal_ops { + int (*sal_puts_raw) (const char *s, int len); + int (*sal_puts) (const char *s, int len); + int (*sal_getc) (void); + int (*sal_input_pending) (void); + void (*sal_wakeup_transmit) (struct sn_cons_port *, int); + } *sc_ops; + unsigned long sc_interrupt_timeout; + int sc_is_asynch; +}; + +static struct sn_cons_port sal_console_port; + +/* Only used if USE_DYNAMIC_MINOR is set to 1 */ +static struct miscdevice misc; /* used with misc_register for dynamic */ + +extern u64 master_node_bedrock_address; +extern void early_sn_setup(void); + +static int sn_debug_printf(const char *fmt, ...); + +#undef DEBUG +#ifdef DEBUG +#define DPRINTF(x...) sn_debug_printf(x) +#else +#define DPRINTF(x...) do { } while (0) +#endif + +/* Prototypes */ +static int snt_hw_puts_raw(const char *, int); +static int snt_hw_puts_buffered(const char *, int); +static int snt_poll_getc(void); +static int snt_poll_input_pending(void); +static int snt_sim_puts(const char *, int); +static int snt_sim_getc(void); +static int snt_sim_input_pending(void); +static int snt_intr_getc(void); +static int snt_intr_input_pending(void); +static void sn_transmit_chars(struct sn_cons_port *, int); + +/* A table for polling: + */ +static struct sn_sal_ops poll_ops = { + .sal_puts_raw = snt_hw_puts_raw, + .sal_puts = snt_hw_puts_raw, + .sal_getc = snt_poll_getc, + .sal_input_pending = snt_poll_input_pending +}; + +/* A table for the simulator */ +static struct sn_sal_ops sim_ops = { + .sal_puts_raw = snt_sim_puts, + .sal_puts = snt_sim_puts, + .sal_getc = snt_sim_getc, + .sal_input_pending = snt_sim_input_pending +}; + +/* A table for interrupts enabled */ +static struct sn_sal_ops intr_ops = { + .sal_puts_raw = snt_hw_puts_raw, + .sal_puts = snt_hw_puts_buffered, + .sal_getc = snt_intr_getc, + .sal_input_pending = snt_intr_input_pending, + .sal_wakeup_transmit = sn_transmit_chars +}; + +/* the console does output in two distinctly different ways: + * synchronous (raw) and asynchronous (buffered). initally, early_printk + * does synchronous output. any data written goes directly to the SAL + * to be output (incidentally, it is internally buffered by the SAL) + * after interrupts and timers are initialized and available for use, + * the console init code switches to asynchronous output. this is + * also the earliest opportunity to begin polling for console input. + * after console initialization, console output and tty (serial port) + * output is buffered and sent to the SAL asynchronously (either by + * timer callback or by UART interrupt) */ + + +/* routines for running the console in polling mode */ + +/** + * snt_poll_getc - Get a character from the console in polling mode + * + */ +static int +snt_poll_getc(void) +{ + int ch; + + ia64_sn_console_getc(&ch); + return ch; +} + +/** + * snt_poll_input_pending - Check if any input is waiting - polling mode. + * + */ +static int +snt_poll_input_pending(void) +{ + int status, input; + + status = ia64_sn_console_check(&input); + return !status && input; +} + +/* routines for running the console on the simulator */ + +/** + * snt_sim_puts - send to the console, used in simulator mode + * @str: String to send + * @count: length of string + * + */ +static int +snt_sim_puts(const char *str, int count) +{ + int counter = count; + +#ifdef FLAG_DIRECT_CONSOLE_WRITES + /* This is an easy way to pre-pend the output to know whether the output + * was done via sal or directly */ + writeb('[', master_node_bedrock_address + (UART_TX << 3)); + writeb('+', master_node_bedrock_address + (UART_TX << 3)); + writeb(']', master_node_bedrock_address + (UART_TX << 3)); + writeb(' ', master_node_bedrock_address + (UART_TX << 3)); +#endif /* FLAG_DIRECT_CONSOLE_WRITES */ + while (counter > 0) { + writeb(*str, master_node_bedrock_address + (UART_TX << 3)); + counter--; + str++; + } + return count; +} + +/** + * snt_sim_getc - Get character from console in simulator mode + * + */ +static int +snt_sim_getc(void) +{ + return readb(master_node_bedrock_address + (UART_RX << 3)); +} + +/** + * snt_sim_input_pending - Check if there is input pending in simulator mode + * + */ +static int +snt_sim_input_pending(void) +{ + return readb(master_node_bedrock_address + + (UART_LSR << 3)) & UART_LSR_DR; +} + +/* routines for an interrupt driven console (normal) */ + +/** + * snt_intr_getc - Get a character from the console, interrupt mode + * + */ +static int +snt_intr_getc(void) +{ + return ia64_sn_console_readc(); +} + +/** + * snt_intr_input_pending - Check if input is pending, interrupt mode + * + */ +static int +snt_intr_input_pending(void) +{ + return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV; +} + +/* these functions are polled and interrupt */ + +/** + * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode + * @s: String + * @len: Length + * + */ +static int +snt_hw_puts_raw(const char *s, int len) +{ + /* this will call the PROM and not return until this is done */ + return ia64_sn_console_putb(s, len); +} + +/** + * snt_hw_puts_buffered - Send string to console, polled or interrupt mode + * @s: String + * @len: Length + * + */ +static int +snt_hw_puts_buffered(const char *s, int len) +{ + /* queue data to the PROM */ + return ia64_sn_console_xmit_chars((char *)s, len); +} + +/* uart interface structs + * These functions are associated with the uart_port that the serial core + * infrastructure calls. + * + * Note: Due to how the console works, many routines are no-ops. + */ + +/** + * snp_type - What type of console are we? + * @port: Port to operate with (we ignore since we only have one port) + * + */ +static const char * +snp_type(struct uart_port *port) +{ + return ("SGI SN L1"); +} + +/** + * snp_tx_empty - Is the transmitter empty? We pretend we're always empty + * @port: Port to operate on (we ignore since we only have one port) + * + */ +static unsigned int +snp_tx_empty(struct uart_port *port) +{ + return 1; +} + +/** + * snp_stop_tx - stop the transmitter - no-op for us + * @port: Port to operat eon - we ignore - no-op function + * @tty_stop: Set to 1 if called via uart_stop + * + */ +static void +snp_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ +} + +/** + * snp_release_port - Free i/o and resources for port - no-op for us + * @port: Port to operate on - we ignore - no-op function + * + */ +static void +snp_release_port(struct uart_port *port) +{ +} + +/** + * snp_enable_ms - Force modem status interrupts on - no-op for us + * @port: Port to operate on - we ignore - no-op function + * + */ +static void +snp_enable_ms(struct uart_port *port) +{ +} + +/** + * snp_shutdown - shut down the port - free irq and disable - no-op for us + * @port: Port to shut down - we ignore + * + */ +static void +snp_shutdown(struct uart_port *port) +{ +} + +/** + * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console + * @port: Port to operate on - we ignore + * @mctrl: Lines to set/unset - we ignore + * + */ +static void +snp_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/** + * snp_get_mctrl - get contorl line info, we just return a static value + * @port: port to operate on - we only have one port so we ignore this + * + */ +static unsigned int +snp_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS; +} + +/** + * snp_stop_rx - Stop the receiver - we ignor ethis + * @port: Port to operate on - we ignore + * + */ +static void +snp_stop_rx(struct uart_port *port) +{ +} + +/** + * snp_start_tx - Start transmitter + * @port: Port to operate on + * @tty_stop: Set to 1 if called via uart_start + * + */ +static void +snp_start_tx(struct uart_port *port, unsigned int tty_stop) +{ + if (sal_console_port.sc_ops->sal_wakeup_transmit) + sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port, TRANSMIT_BUFFERED); + +} + +/** + * snp_break_ctl - handle breaks - ignored by us + * @port: Port to operate on + * @break_state: Break state + * + */ +static void +snp_break_ctl(struct uart_port *port, int break_state) +{ +} + +/** + * snp_startup - Start up the serial port - always return 0 (We're always on) + * @port: Port to operate on + * + */ +static int +snp_startup(struct uart_port *port) +{ + return 0; +} + +/** + * snp_set_termios - set termios stuff - we ignore these + * @port: port to operate on + * @termios: New settings + * @termios: Old + * + */ +static void +snp_set_termios(struct uart_port *port, struct termios *termios, + struct termios *old) +{ +} + +/** + * snp_request_port - allocate resources for port - ignored by us + * @port: port to operate on + * + */ +static int +snp_request_port(struct uart_port *port) +{ + return 0; +} + +/** + * snp_config_port - allocate resources, set up - we ignore, we're always on + * @port: Port to operate on + * @flags: flags used for port setup + * + */ +static void +snp_config_port(struct uart_port *port, int flags) +{ +} + +/* Associate the uart functions above - given to serial core */ + +static struct uart_ops sn_console_ops = { + .tx_empty = snp_tx_empty, + .set_mctrl = snp_set_mctrl, + .get_mctrl = snp_get_mctrl, + .stop_tx = snp_stop_tx, + .start_tx = snp_start_tx, + .stop_rx = snp_stop_rx, + .enable_ms = snp_enable_ms, + .break_ctl = snp_break_ctl, + .startup = snp_startup, + .shutdown = snp_shutdown, + .set_termios = snp_set_termios, + .pm = NULL, + .type = snp_type, + .release_port = snp_release_port, + .request_port = snp_request_port, + .config_port = snp_config_port, + .verify_port = NULL, +}; + +/* End of uart struct functions and defines */ + +/** + * sn_debug_printf - close to hardware debugging printf + * @fmt: printf format + * + * This is as "close to the metal" as we can get, used when the driver + * itself may be broken. + * + */ +static int +sn_debug_printf(const char *fmt, ...) +{ + static char printk_buf[1024]; + int printed_len; + va_list args; + + va_start(args, fmt); + printed_len = vsnprintf(printk_buf, sizeof (printk_buf), fmt, args); + + if (!sal_console_port.sc_ops) { + if (IS_RUNNING_ON_SIMULATOR()) + sal_console_port.sc_ops = &sim_ops; + else + sal_console_port.sc_ops = &poll_ops; + + early_sn_setup(); + } + sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len); + + va_end(args); + return printed_len; +} + +/* + * Interrupt handling routines. + */ + + +/** + * sn_receive_chars - Grab characters, pass them to tty layer + * @port: Port to operate on + * @regs: Saved registers (needed by uart_handle_sysrq_char) + * + * Note: If we're not registered with the serial core infrastructure yet, + * we don't try to send characters to it... + * + */ +static void +sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs) +{ + int ch; + struct tty_struct *tty; + + if (!port) { + printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n"); + return; + } + + if (!port->sc_ops) { + printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n"); + return; + } + + if (port->sc_port.info) { + /* The serial_core stuffs are initilized, use them */ + tty = port->sc_port.info->tty; + } + else { + /* Not registered yet - can't pass to tty layer. */ + tty = NULL; + } + + while (port->sc_ops->sal_input_pending()) { + ch = port->sc_ops->sal_getc(); + if (ch < 0) { + printk(KERN_ERR "sn_console: An error occured while " + "obtaining data from the console (0x%0x)\n", ch); + break; + } +#if defined(CONFIG_SERIAL_SGI_L1_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (uart_handle_sysrq_char(&port->sc_port, ch, regs)) + continue; +#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE && CONFIG_MAGIC_SYSRQ */ + + /* record the character to pass up to the tty layer */ + if (tty) { + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + tty->flip.char_buf_ptr++; + tty->flip.count++; + if (tty->flip.count == TTY_FLIPBUF_SIZE) + break; + } + else { + } + port->sc_port.icount.rx++; + } + + if (tty) + tty_flip_buffer_push(tty); +} + +/** + * sn_transmit_chars - grab characters from serial core, send off + * @port: Port to operate on + * @raw: Transmit raw or buffered + * + * Note: If we're early, before we're registered with serial core, the + * writes are going through sn_sal_console_write because that's how + * register_console has been set up. We currently could have asynch + * polls calling this function due to sn_sal_switch_to_asynch but we can + * ignore them until we register with the serial core stuffs. + * + */ +static void +sn_transmit_chars(struct sn_cons_port *port, int raw) +{ + int xmit_count, tail, head, loops, ii; + int result; + char *start; + struct circ_buf *xmit; + + if (!port) + return; + + BUG_ON(!port->sc_is_asynch); + + if (port->sc_port.info) { + /* We're initilized, using serial core infrastructure */ + xmit = &port->sc_port.info->xmit; + } + else { + /* Probably sn_sal_switch_to_asynch has been run but serial core isn't + * initilized yet. Just return. Writes are going through + * sn_sal_console_write (due to register_console) at this time. + */ + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) { + /* Nothing to do. */ + return; + } + + head = xmit->head; + tail = xmit->tail; + start = &xmit->buf[tail]; + + /* twice around gets the tail to the end of the buffer and + * then to the head, if needed */ + loops = (head < tail) ? 2 : 1; + + for (ii = 0; ii < loops; ii++) { + xmit_count = (head < tail) ? + (UART_XMIT_SIZE - tail) : (head - tail); + + if (xmit_count > 0) { + if (raw == TRANSMIT_RAW) + result = + port->sc_ops->sal_puts_raw(start, + xmit_count); + else + result = + port->sc_ops->sal_puts(start, xmit_count); +#ifdef DEBUG + if (!result) + sn_debug_printf("`"); +#endif + if (result > 0) { + xmit_count -= result; + port->sc_port.icount.tx += result; + tail += result; + tail &= UART_XMIT_SIZE - 1; + xmit->tail = tail; + start = &xmit->buf[tail]; + } + } + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&port->sc_port); + + if (uart_circ_empty(xmit)) + snp_stop_tx(&port->sc_port, 0); /* no-op for us */ +} + +/** + * sn_sal_interrupt - Handle console interrupts + * @irq: irq #, useful for debug statements + * @dev_id: our pointer to our port (sn_cons_port which contains the uart port) + * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char + * + */ +static irqreturn_t +sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sn_cons_port *port = (struct sn_cons_port *) dev_id; + unsigned long flags; + int status = ia64_sn_console_intr_status(); + + if (!port) + return IRQ_NONE; + + spin_lock_irqsave(&port->sc_port.lock, flags); + if (status & SAL_CONSOLE_INTR_RECV) { + sn_receive_chars(port, regs); + } + if (status & SAL_CONSOLE_INTR_XMIT) { + sn_transmit_chars(port, TRANSMIT_BUFFERED); + } + spin_unlock_irqrestore(&port->sc_port.lock, flags); + return IRQ_HANDLED; +} + +/** + * sn_sal_connect_interrupt - Request interrupt, handled by sn_sal_interrupt + * @port: Our sn_cons_port (which contains the uart port) + * + * returns the console irq if interrupt is successfully registered, else 0 + * + */ +static int +sn_sal_connect_interrupt(struct sn_cons_port *port) +{ + if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, SA_INTERRUPT, + "SAL console driver", port) >= 0) { + return SGI_UART_VECTOR; + } + + printk(KERN_INFO "sn_console: console proceeding in polled mode\n"); + return 0; +} + +/** + * sn_sal_timer_poll - this function handles polled console mode + * @data: A pointer to our sn_cons_port (which contains the uart port) + * + * data is the pointer that init_timer will store for us. This function is + * associated with init_timer to see if there is any console traffic. + * Obviously not used in interrupt mode + * + */ +static void +sn_sal_timer_poll(unsigned long data) +{ + struct sn_cons_port *port = (struct sn_cons_port *) data; + unsigned long flags; + + if (!port) + return; + + if (!port->sc_port.irq) { + spin_lock_irqsave(&port->sc_port.lock, flags); + sn_receive_chars(port, NULL); + sn_transmit_chars(port, TRANSMIT_RAW); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + mod_timer(&port->sc_timer, + jiffies + port->sc_interrupt_timeout); + } +} + +/* + * Boot-time initialization code + */ + +/** + * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch) + * @port: Our sn_cons_port (which contains the uart port) + * + * So this is used by sn_sal_serial_console_init (early on, before we're + * registered with serial core). It's also used by sn_sal_module_init + * right after we've registered with serial core. The later only happens + * if we didn't already come through here via sn_sal_serial_console_init. + * + */ +static void __init +sn_sal_switch_to_asynch(struct sn_cons_port *port) +{ + unsigned long flags; + + if (!port) + return; + + DPRINTF("sn_console: about to switch to asynchronous console\n"); + + /* without early_printk, we may be invoked late enough to race + * with other cpus doing console IO at this point, however + * console interrupts will never be enabled */ + spin_lock_irqsave(&port->sc_port.lock, flags); + + /* early_printk invocation may have done this for us */ + if (!port->sc_ops) { + if (IS_RUNNING_ON_SIMULATOR()) + port->sc_ops = &sim_ops; + else + port->sc_ops = &poll_ops; + } + + /* we can't turn on the console interrupt (as request_irq + * calls kmalloc, which isn't set up yet), so we rely on a + * timer to poll for input and push data from the console + * buffer. + */ + init_timer(&port->sc_timer); + port->sc_timer.function = sn_sal_timer_poll; + port->sc_timer.data = (unsigned long) port; + + if (IS_RUNNING_ON_SIMULATOR()) + port->sc_interrupt_timeout = 6; + else { + /* 960cps / 16 char FIFO = 60HZ + * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */ + port->sc_interrupt_timeout = + HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS; + } + mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout); + + port->sc_is_asynch = 1; + spin_unlock_irqrestore(&port->sc_port.lock, flags); +} + +/** + * sn_sal_switch_to_interrupts - Switch to interrupt driven mode + * @port: Our sn_cons_port (which contains the uart port) + * + * In sn_sal_module_init, after we're registered with serial core and + * the port is added, this function is called to switch us to interrupt + * mode. We were previously in asynch/polling mode (using init_timer). + * + * We attempt to switch to interrupt mode here by calling + * sn_sal_connect_interrupt. If that works out, we enable receive interrupts. + */ +static void __init +sn_sal_switch_to_interrupts(struct sn_cons_port *port) +{ + int irq; + unsigned long flags; + + if (!port) + return; + + DPRINTF("sn_console: switching to interrupt driven console\n"); + + spin_lock_irqsave(&port->sc_port.lock, flags); + + irq = sn_sal_connect_interrupt(port); + + if (irq) { + port->sc_port.irq = irq; + port->sc_ops = &intr_ops; + + /* turn on receive interrupts */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + } + spin_unlock_irqrestore(&port->sc_port.lock, flags); +} + +/* + * Kernel console definitions + */ + +#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE +static void sn_sal_console_write(struct console *, const char *, unsigned); +static int __init sn_sal_console_setup(struct console *, char *); +extern struct uart_driver sal_console_uart; +extern struct tty_driver *uart_console_device(struct console *, int *); + +static struct console sal_console = { + .name = DEVICE_NAME, + .write = sn_sal_console_write, + .device = uart_console_device, + .setup = sn_sal_console_setup, + .index = -1, /* unspecified */ + .data = &sal_console_uart, +}; + +#define SAL_CONSOLE &sal_console +#else +#define SAL_CONSOLE 0 +#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ + +static struct uart_driver sal_console_uart = { + .owner = THIS_MODULE, + .driver_name = "sn_console", + .dev_name = DEVICE_NAME, + .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */ + .minor = 0, + .nr = 1, /* one port */ + .cons = SAL_CONSOLE, +}; + +/** + * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core + * + * Before this is called, we've been printing kernel messages in a special + * early mode not making use of the serial core infrastructure. When our + * driver is loaded for real, we register the driver and port with serial + * core and try to enable interrupt driven mode. + * + */ +static int __init +sn_sal_module_init(void) +{ + int retval; + + printk(KERN_INFO "sn_console: Console driver init\n"); + + if (!ia64_platform_is("sn2")) + return -ENODEV; + + if (USE_DYNAMIC_MINOR == 1) { + misc.minor = MISC_DYNAMIC_MINOR; + misc.name = DEVICE_NAME_DYNAMIC; + retval = misc_register(&misc); + if (retval != 0) { + printk("Failed to register console device using misc_register.\n"); + return -ENODEV; + } + sal_console_uart.major = MISC_MAJOR; + sal_console_uart.minor = misc.minor; + } + else { + sal_console_uart.major = DEVICE_MAJOR; + sal_console_uart.minor = DEVICE_MINOR; + } + + /* We register the driver and the port before switching to interrupts + * or async above so the proper uart structures are populated */ + + if (uart_register_driver(&sal_console_uart) < 0) { + printk("ERROR sn_sal_module_init failed uart_register_driver, line %d\n", + __LINE__); + return -ENODEV; + } + + sal_console_port.sc_port.lock = SPIN_LOCK_UNLOCKED; + + /* Setup the port struct with the minimum needed */ + sal_console_port.sc_port.membase = (char *)1; /* just needs to be non-zero */ + sal_console_port.sc_port.type = PORT_16550A; + sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS; + sal_console_port.sc_port.ops = &sn_console_ops; + sal_console_port.sc_port.line = 0; + + if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) { + /* error - not sure what I'd do - so I'll do nothing */ + printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__); + } + + /* when this driver is compiled in, the console initialization + * will have already switched us into asynchronous operation + * before we get here through the module initcalls */ + if (!sal_console_port.sc_is_asynch) { + sn_sal_switch_to_asynch(&sal_console_port); + } + + /* at this point (module_init) we can try to turn on interrupts */ + if (!IS_RUNNING_ON_SIMULATOR()) { + sn_sal_switch_to_interrupts(&sal_console_port); + } + return 0; +} + +/** + * sn_sal_module_exit - When we're unloaded, remove the driver/port + * + */ +static void __exit +sn_sal_module_exit(void) +{ + del_timer_sync(&sal_console_port.sc_timer); + uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port); + uart_unregister_driver(&sal_console_uart); + misc_deregister(&misc); +} + +module_init(sn_sal_module_init); +module_exit(sn_sal_module_exit); + +#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE + +/** + * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required + * @s: input string + * @count: length + * + * We need a \r ahead of every \n for direct writes through + * ia64_sn_console_putb (what sal_puts_raw below actually does). + * + */ +static void puts_raw_fixed(const char *s, int count) +{ + const char *s1; + struct sn_cons_port *port = &sal_console_port; + + /* Output '\r' before each '\n' */ + while ((s1 = memchr(s, '\n', count)) != NULL) { + port->sc_ops->sal_puts_raw(s, s1 - s); + port->sc_ops->sal_puts_raw("\r\n", 2); + count -= s1 + 1 - s; + s = s1 + 1; + } + port->sc_ops->sal_puts_raw(s, count); +} + +/** + * sn_sal_console_write - Print statements before serial core available + * @console: Console to operate on - we ignore since we have just one + * @s: String to send + * @count: length + * + * This is referenced in the console struct. It is used for early + * console printing before we register with serial core and for things + * such as kdb. The console_lock must be held when we get here. + * + * This function has some code for trying to print output even if the lock + * is held. We try to cover the case where a lock holder could have died. + * We don't use this special case code if we're not registered with serial + * core yet. After we're registered with serial core, the only time this + * function would be used is for high level kernel output like magic sys req, + * kdb, and printk's. + */ +static void +sn_sal_console_write(struct console *co, const char *s, unsigned count) +{ + unsigned long flags = 0; + struct sn_cons_port *port = &sal_console_port; +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) + static int stole_lock = 0; +#endif + + BUG_ON(!port->sc_is_asynch); + + /* We can't look at the xmit buffer if we're not registered with serial core + * yet. So only do the fancy recovery after registering + */ + if (port->sc_port.info) { + + /* somebody really wants this output, might be an + * oops, kdb, panic, etc. make sure they get it. */ +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) + if (spin_is_locked(&port->sc_port.lock)) { + int lhead = port->sc_port.info->xmit.head; + int ltail = port->sc_port.info->xmit.tail; + int counter, got_lock = 0; + + /* + * We attempt to determine if someone has died with the + * lock. We wait ~20 secs after the head and tail ptrs + * stop moving and assume the lock holder is not functional + * and plow ahead. If the lock is freed within the time out + * period we re-get the lock and go ahead normally. We also + * remember if we have plowed ahead so that we don't have + * to wait out the time out period again - the asumption + * is that we will time out again. + */ + + for (counter = 0; counter < 150; mdelay(125), counter++) { + if (!spin_is_locked(&port->sc_port.lock) || stole_lock) { + if (!stole_lock) { + spin_lock_irqsave(&port->sc_port.lock, flags); + got_lock = 1; + } + break; + } + else { + /* still locked */ + if ((lhead != port->sc_port.info->xmit.head) || (ltail != port->sc_port.info->xmit.tail)) { + lhead = port->sc_port.info->xmit.head; + ltail = port->sc_port.info->xmit.tail; + counter = 0; + } + } + } + /* flush anything in the serial core xmit buffer, raw */ + sn_transmit_chars(port, 1); + if (got_lock) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + stole_lock = 0; + } + else { + /* fell thru */ + stole_lock = 1; + } + puts_raw_fixed(s, count); + } + else { + stole_lock = 0; +#endif + spin_lock_irqsave(&port->sc_port.lock, flags); + sn_transmit_chars(port, 1); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + + puts_raw_fixed(s, count); + } + } + else { + /* Not yet registered with serial core - simple case */ + puts_raw_fixed(s, count); + } +} + + +/** + * sn_sal_console_setup - Set up console for early printing + * @co: Console to work with + * @options: Options to set + * + * Altix console doesn't do anything with baud rates, etc, anyway. + * + * This isn't required since not providing the setup function in the + * console struct is ok. However, other patches like KDB plop something + * here so providing it is easier. + * + */ +static int __init +sn_sal_console_setup(struct console *co, char *options) +{ + return 0; +} + +/** + * sn_sal_console_write_early - simple early output routine + * @co - console struct + * @s - string to print + * @count - count + * + * Simple function to provide early output, before even + * sn_sal_serial_console_init is called. Referenced in the + * console struct registerd in sn_serial_console_early_setup. + * + */ +static void __init +sn_sal_console_write_early(struct console *co, const char *s, unsigned count) +{ + sal_console_port.sc_ops->sal_puts(s, count); +} + +/* Used for very early console printing - again, before + * sn_sal_serial_console_init is run */ +static struct console sal_console_early __initdata = { + .name = "sn_sal", + .write = sn_sal_console_write_early, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/** + * sn_serial_console_early_setup - Sets up early console output support + * + * Register a console early on... This is for output before even + * sn_sal_serial_cosnole_init is called. This function is called from + * setup.c. This allows us to do really early polled writes. When + * sn_sal_serial_console_init is called, this console is unregistered + * and a new one registered. + */ +int __init +sn_serial_console_early_setup(void) +{ + if (!ia64_platform_is("sn2")) + return -1; + + if (IS_RUNNING_ON_SIMULATOR()) + sal_console_port.sc_ops = &sim_ops; + else + sal_console_port.sc_ops = &poll_ops; + + early_sn_setup(); /* Find SAL entry points */ + register_console(&sal_console_early); + + return 0; +} + + +/** + * sn_sal_serial_console_init - Early console output - set up for register + * + * This function is called when regular console init happens. Because we + * support even earlier console output with sn_serial_console_early_setup + * (called from setup.c directly), this function unregisters the really + * early console. + * + * Note: Even if setup.c doesn't register sal_console_early, unregistering + * it here doesn't hurt anything. + * + */ +static int __init +sn_sal_serial_console_init(void) +{ + if (ia64_platform_is("sn2")) { + sn_sal_switch_to_asynch(&sal_console_port); + DPRINTF ("sn_sal_serial_console_init : register console\n"); + register_console(&sal_console); + unregister_console(&sal_console_early); + } + return 0; +} + +console_initcall(sn_sal_serial_console_init); + +#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ --- linux-2.6.8-rc1/drivers/serial/sunsu.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/serial/sunsu.c 2004-07-13 17:09:22.000000000 -0700 @@ -98,7 +98,7 @@ struct uart_sunsu_port { unsigned int irq; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPI static int sunsu_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int lsr; @@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct seri static int sunsu_serio_open(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int ret; @@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio static void sunsu_serio_close(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunsu_serio_lock, flags); @@ -1284,54 +1284,58 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(void) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { - struct uart_sunsu_port *up; - int i; + struct serio *serio; - for (i = 0, up = sunsu_ports; i < 2; i++, up++) { - up->port.line = i; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + up->port.line = channel; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - else - up->cflag = B4800 | CS8 | CLOCAL | CREAD; + if (up->su_type == SU_PORT_KBD) + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + else + up->cflag = B4800 | CS8 | CLOCAL | CREAD; - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - continue; + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", - i, - up->port.membase, __irq_itoa(up->irq), - sunsu_type(&up->port)); + printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + channel, + up->port.membase, __irq_itoa(up->irq), + sunsu_type(&up->port)); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(serio)); - up->serio.driver = up; + serio->port_data = up; - up->serio.type = SERIO_RS232; + serio->type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "sukbd"; + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "sums"; + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "sums", sizeof(serio->name)); } - up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1"); + strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); - up->serio.write = sunsu_serio_write; - up->serio.open = sunsu_serio_open; - up->serio.close = sunsu_serio_close; + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "su%d: not enough memory for serio port\n", + channel); + } #endif - sunsu_startup(&up->port); - } + sunsu_startup(&up->port); return 0; } @@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void) if (scan.msx != -1 && scan.kbx != -1) { sunsu_ports[0].su_type = SU_PORT_MS; sunsu_ports[0].port_node = scan.msnode; + sunsu_kbd_ms_init(&sunsu_ports[0], 0); + sunsu_ports[1].su_type = SU_PORT_KBD; sunsu_ports[1].port_node = scan.kbnode; + sunsu_kbd_ms_init(&sunsu_ports[1], 1); - sunsu_kbd_ms_init(); return 0; } @@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void) if (up->su_type == SU_PORT_MS || up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } #endif } else if (up->port.type != PORT_UNKNOWN) { uart_remove_one_port(&sunsu_reg, &up->port); --- linux-2.6.8-rc1/drivers/serial/sunzilog.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/serial/sunzilog.c 2004-07-13 17:09:22.000000000 -0700 @@ -107,7 +107,7 @@ struct uart_sunzilog_port { unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = static int sunzilog_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct s static int sunzilog_serio_open(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; int ret; @@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct se static void sunzilog_serio_close(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1529,6 +1529,7 @@ static void __init sunzilog_prepare(void static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) { int baud, brg; + struct serio *serio; if (channel == KEYBOARD_LINE) { up->flags |= SUNZILOG_FLAG_CONS_KEYB; @@ -1547,26 +1548,34 @@ static void __init sunzilog_init_kbdms(s sunzilog_convert_to_zs(up, up->cflag, 0, brg); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { - up->serio.driver = up; + memset(serio, 0, sizeof(serio)); - up->serio.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "zskbd"; - } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "zsms"; - } - up->serio.phys = (channel == KEYBOARD_LINE ? - "zs/serio0" : "zs/serio1"); + serio->port_data = up; - up->serio.write = sunzilog_serio_write; - up->serio.open = sunzilog_serio_open; - up->serio.close = sunzilog_serio_close; + serio->type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); + + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "zs%d: not enough memory for serio port\n", + channel); + } #endif sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1732,10 +1741,15 @@ static void __exit sunzilog_exit(void) for (i = 0; i < NUM_CHANNELS; i++) { struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; - - uart_remove_one_port(&sunzilog_reg, &up->port); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } uart_unregister_driver(&sunzilog_reg); --- linux-2.6.8-rc1/drivers/usb/class/usblp.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/class/usblp.c 2004-07-13 17:09:55.000000000 -0700 @@ -221,7 +221,7 @@ static int usblp_set_protocol(struct usb static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ -extern struct usb_driver usblp_driver; +static struct usb_driver usblp_driver; /* * Functions for usblp control messages. --- linux-2.6.8-rc1/drivers/usb/class/usb-midi.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/usb/class/usb-midi.c 2004-07-13 17:09:13.000000000 -0700 @@ -951,7 +951,7 @@ static int usb_midi_release(struct inode if ( m->open_mode & FMODE_READ ) { unsigned long int flagsep; spin_lock_irqsave( &m->min.ep->lock, flagsep ); - m->min.ep->cables[m->min.cableId] = 0; // discard cable + m->min.ep->cables[m->min.cableId] = NULL; // discard cable m->min.ep->readers -= 1; m->open_mode &= ~FMODE_READ; if ( m->min.ep->readers == 0 && @@ -967,7 +967,7 @@ static int usb_midi_release(struct inode up(&open_sem); wake_up(&open_wait); - file->private_data = 0; + file->private_data = NULL; return 0; } @@ -1294,7 +1294,7 @@ static struct usb_midi_device *parse_des unsigned char jack2string[256]; #endif - u = 0; + u = NULL; /* find audiocontrol interface */ p1 = find_csinterface_descriptor( buffer, bufSize, NULL, MS_HEADER, ifnum, altSetting); @@ -1314,7 +1314,7 @@ static struct usb_midi_device *parse_des if ( !u ) { return NULL; } - u->deviceName = 0; + u->deviceName = NULL; u->idVendor = d->descriptor.idVendor; u->idProduct = d->descriptor.idProduct; u->interface = ifnum; @@ -1388,7 +1388,7 @@ static struct usb_midi_device *parse_des if (quirks==0) { /* MIDISTREAM */ - p2 = 0; + p2 = NULL; for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, ifnum, altSetting ); p1; p1 = next ) { next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, @@ -1397,7 +1397,7 @@ static struct usb_midi_device *parse_des ifnum, altSetting ); if ( p2 && next && ( p2 > next ) ) - p2 = 0; + p2 = NULL; if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue; @@ -1940,8 +1940,8 @@ static int detect_by_hand(struct usb_dev if ( ucable < 0 || ucable > 15 ) ucable = 0; - u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name - from device. */ + u.deviceName = NULL; /* A flag for alloc_usb_midi_device to get device + name from device. */ u.idVendor = uvendor; u.idProduct = uproduct; u.interface = uinterface; --- linux-2.6.8-rc1/drivers/usb/core/devices.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/devices.c 2004-07-13 17:09:24.000000000 -0700 @@ -283,9 +283,8 @@ static char *usb_dump_interface( /* TBD: * 0. TBDs - * 1. marking active config and ifaces (code lists all, but should mark + * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) - * 2. add status to each endpoint line */ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) @@ -452,7 +451,7 @@ static char *usb_dump_string(char *start * nbytes - the maximum number of bytes to write * skip_bytes - the number of bytes to skip before writing anything * file_offset - the offset into the devices file on completion - * The caller must own the usbdev->serialize semaphore. + * The caller must have locked the device. */ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) @@ -556,10 +555,10 @@ static ssize_t usb_device_dump(char __us struct usb_device *childdev = usbdev->children[chix]; if (childdev) { - down(&childdev->serialize); + usb_lock_device(childdev); ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev, bus, level + 1, chix, ++cnt); - up(&childdev->serialize); + usb_unlock_device(childdev); if (ret == -EFAULT) return total_written; total_written += ret; @@ -591,9 +590,9 @@ static ssize_t usb_device_read(struct fi /* recurse through all children of the root hub */ if (!bus->root_hub) continue; - down(&bus->root_hub->serialize); + usb_lock_device(bus->root_hub); ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); - up(&bus->root_hub->serialize); + usb_unlock_device(bus->root_hub); if (ret < 0) { up(&usb_bus_list_lock); return ret; --- linux-2.6.8-rc1/drivers/usb/core/devio.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/devio.c 2004-07-13 17:09:24.000000000 -0700 @@ -111,7 +111,7 @@ static ssize_t usbdev_read(struct file * int i; pos = *ppos; - down(&dev->serialize); + usb_lock_device(dev); if (!connected(dev)) { ret = -ENODEV; goto err; @@ -173,7 +173,7 @@ static ssize_t usbdev_read(struct file * } err: - up(&dev->serialize); + usb_unlock_device(dev); return ret; } @@ -269,7 +269,7 @@ static void async_completed(struct urb * sinfo.si_signo = as->signr; sinfo.si_errno = as->urb->status; sinfo.si_code = SI_ASYNCIO; - sinfo.si_addr = (void *)as->userurb; + sinfo.si_addr = as->userurb; send_sig_info(as->signr, &sinfo, as->task); } wake_up(&ps->wait); @@ -514,7 +514,7 @@ static int usbdev_release(struct inode * struct usb_device *dev = ps->dev; unsigned int ifnum; - down(&dev->serialize); + usb_lock_device(dev); list_del_init(&ps->list); if (connected(dev)) { @@ -523,7 +523,7 @@ static int usbdev_release(struct inode * releaseintf(ps, ifnum); destroy_all_async(ps); } - up(&dev->serialize); + usb_unlock_device(dev); usb_put_dev(dev); ps->dev = NULL; kfree(ps); @@ -722,7 +722,7 @@ static int proc_connectinfo(struct dev_s static int proc_resetdevice(struct dev_state *ps) { - return __usb_reset_device(ps->dev); + return usb_reset_device(ps->dev); } @@ -1012,9 +1012,9 @@ static int proc_reapurb(struct dev_state break; if (signal_pending(current)) break; - up(&dev->serialize); + usb_unlock_device(dev); schedule(); - down(&dev->serialize); + usb_lock_device(dev); } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); @@ -1137,7 +1137,11 @@ static int proc_ioctl (struct dev_state /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: + usb_unlock_device(ps->dev); + usb_lock_all_devices(); bus_rescan_devices(intf->dev.bus); + usb_unlock_all_devices(); + usb_lock_device(ps->dev); break; /* talk directly to the interface's driver */ @@ -1180,9 +1184,9 @@ static int usbdev_ioctl(struct inode *in if (!(file->f_mode & FMODE_WRITE)) return -EPERM; - down(&dev->serialize); + usb_lock_device(dev); if (!connected(dev)) { - up(&dev->serialize); + usb_unlock_device(dev); return -ENODEV; } @@ -1282,7 +1286,7 @@ static int usbdev_ioctl(struct inode *in ret = proc_ioctl(ps, p); break; } - up(&dev->serialize); + usb_unlock_device(dev); if (ret >= 0) inode->i_atime = CURRENT_TIME; return ret; --- linux-2.6.8-rc1/drivers/usb/core/file.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/drivers/usb/core/file.c 2004-07-13 17:09:24.000000000 -0700 @@ -79,14 +79,25 @@ static struct class usb_class = { int usb_major_init(void) { - if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) { + int error; + + error = register_chrdev(USB_MAJOR, "usb", &usb_fops); + if (error) { err("unable to get major %d for usb devices", USB_MAJOR); - return -EBUSY; + goto out; + } + + error = class_register(&usb_class); + if (error) { + err("class_register failed for usb devices"); + unregister_chrdev(USB_MAJOR, "usb"); + goto out; } devfs_mk_dir("usb"); - class_register(&usb_class); - return 0; + +out: + return error; } void usb_major_cleanup(void) --- linux-2.6.8-rc1/drivers/usb/core/hcd.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/hcd.c 2004-07-13 17:09:24.000000000 -0700 @@ -102,6 +102,9 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used when updating hcd data */ static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; +/* wait queue for synchronous unlinks */ +DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); + /*-------------------------------------------------------------------------*/ /* @@ -569,7 +572,7 @@ static int rh_urb_enqueue (struct usb_hc /*-------------------------------------------------------------------------*/ -void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) +int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) { unsigned long flags; @@ -581,6 +584,7 @@ void usb_rh_status_dequeue (struct usb_h urb->hcpriv = NULL; usb_hcd_giveback_urb (hcd, urb, NULL); local_irq_restore (flags); + return 0; } /*-------------------------------------------------------------------------*/ @@ -791,9 +795,9 @@ int usb_register_root_hub (struct usb_de return (retval < 0) ? retval : -EMSGSIZE; } - down (&usb_dev->serialize); + usb_lock_device (usb_dev); retval = usb_new_device (usb_dev); - up (&usb_dev->serialize); + usb_unlock_device (usb_dev); if (retval) { usb_dev->bus->root_hub = NULL; dev_err (parent_dev, "can't register root hub for %s, %d\n", @@ -1029,7 +1033,6 @@ static int hcd_alloc_dev (struct usb_dev static void urb_unlink (struct urb *urb) { unsigned long flags; - struct usb_device *dev; /* Release any periodic transfer bandwidth */ if (urb->bandwidth) @@ -1040,9 +1043,8 @@ static void urb_unlink (struct urb *urb) spin_lock_irqsave (&hcd_data_lock, flags); list_del_init (&urb->urb_list); - dev = urb->dev; spin_unlock_irqrestore (&hcd_data_lock, flags); - usb_put_dev (dev); + usb_put_dev (urb->dev); } @@ -1079,23 +1081,28 @@ static int hcd_submit_urb (struct urb *u // FIXME: verify that quiescing hc works right (RH cleans up) spin_lock_irqsave (&hcd_data_lock, flags); - if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { + if (unlikely (urb->reject)) + status = -EPERM; + else if (HCD_IS_RUNNING (hcd->state) && + hcd->state != USB_STATE_QUIESCING) { usb_get_dev (urb->dev); list_add_tail (&urb->urb_list, &dev->urb_list); status = 0; - } else { - INIT_LIST_HEAD (&urb->urb_list); + } else status = -ESHUTDOWN; - } spin_unlock_irqrestore (&hcd_data_lock, flags); - if (status) + if (status) { + INIT_LIST_HEAD (&urb->urb_list); return status; + } /* increment urb's reference count as part of giving it to the HCD * (which now controls it). HCD guarantees that it either returns * an error or calls giveback(), but not both. */ urb = usb_get_urb (urb); + atomic_inc (&urb->use_count); + if (urb->dev == hcd->self.root_hub) { /* NOTE: requirement on hub callers (usbfs and the hub * driver, for now) that URBs' urb->transfer_buffer be @@ -1132,9 +1139,12 @@ static int hcd_submit_urb (struct urb *u status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); done: - if (status) { - usb_put_urb (urb); + if (unlikely (status)) { urb_unlink (urb); + atomic_dec (&urb->use_count); + if (urb->reject) + wake_up (&usb_kill_urb_queue); + usb_put_urb (urb); } return status; } @@ -1157,60 +1167,39 @@ static int hcd_get_frame_number (struct * soon as practical. we've already set up the urb's return status, * but we can't know if the callback completed already. */ -static void +static int unlink1 (struct usb_hcd *hcd, struct urb *urb) { + int value; + if (urb == (struct urb *) hcd->rh_timer.data) - usb_rh_status_dequeue (hcd, urb); + value = usb_rh_status_dequeue (hcd, urb); else { - int value; - /* failures "should" be harmless */ + /* The only reason an HCD might fail this call is if + * it has not yet fully queued the urb to begin with. + * Such failures should be harmless. */ value = hcd->driver->urb_dequeue (hcd, urb); - if (value != 0) - dev_dbg (hcd->self.controller, - "dequeue %p --> %d\n", - urb, value); } -} - -struct completion_splice { // modified urb context: - /* did we complete? */ - struct completion done; - - /* original urb data */ - usb_complete_t complete; - void *context; -}; - -static void unlink_complete (struct urb *urb, struct pt_regs *regs) -{ - struct completion_splice *splice; - - splice = (struct completion_splice *) urb->context; - /* issue original completion call */ - urb->complete = splice->complete; - urb->context = splice->context; - urb->complete (urb, regs); - - /* then let the synchronous unlink call complete */ - complete (&splice->done); + if (value != 0) + dev_dbg (hcd->self.controller, "dequeue %p --> %d\n", + urb, value); + return value; } /* - * called in any context; note ASYNC_UNLINK restrictions + * called in any context * * caller guarantees urb won't be recycled till both unlink() * and the urb's completion function return */ -static int hcd_unlink_urb (struct urb *urb) +static int hcd_unlink_urb (struct urb *urb, int status) { struct hcd_dev *dev; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; - struct completion_splice splice; struct list_head *tmp; int retval; @@ -1262,8 +1251,6 @@ static int hcd_unlink_urb (struct urb *u /* Any status except -EINPROGRESS means something already started to * unlink this URB from the hardware. So there's no more work to do. - * - * FIXME use better explicit urb state */ if (urb->status != -EINPROGRESS) { retval = -EBUSY; @@ -1281,62 +1268,19 @@ static int hcd_unlink_urb (struct urb *u hcd->saw_irq = 1; } - /* maybe set up to block until the urb's completion fires. the - * lower level hcd code is always async, locking on urb->status - * updates; an intercepted completion unblocks us. - */ - if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { - if (in_interrupt ()) { - dev_dbg (hcd->self.controller, - "non-async unlink in_interrupt"); - retval = -EWOULDBLOCK; - goto done; - } - /* synchronous unlink: block till we see the completion */ - init_completion (&splice.done); - splice.complete = urb->complete; - splice.context = urb->context; - urb->complete = unlink_complete; - urb->context = &splice; - urb->status = -ENOENT; - } else { - /* asynchronous unlink */ - urb->status = -ECONNRESET; - } + urb->status = status; + spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); - // FIXME remove splicing, so this becomes unlink1 (hcd, urb); - if (urb == (struct urb *) hcd->rh_timer.data) { - usb_rh_status_dequeue (hcd, urb); - retval = 0; - } else { - retval = hcd->driver->urb_dequeue (hcd, urb); - - /* hcds shouldn't really fail these calls, but... */ - if (retval) { - dev_dbg (sys, "dequeue %p --> %d\n", urb, retval); - if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { - spin_lock_irqsave (&urb->lock, flags); - urb->complete = splice.complete; - urb->context = splice.context; - spin_unlock_irqrestore (&urb->lock, flags); - } - goto bye; - } - } - - /* block till giveback, if needed */ - if (urb->transfer_flags & URB_ASYNC_UNLINK) - return -EINPROGRESS; - - wait_for_completion (&splice.done); - return 0; + retval = unlink1 (hcd, urb); + if (retval == 0) + retval = -EINPROGRESS; + return retval; done: spin_unlock (&hcd_data_lock); spin_unlock_irqrestore (&urb->lock, flags); -bye: if (retval != -EIDRM && sys && sys->driver) dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval); return retval; @@ -1367,13 +1311,10 @@ static void hcd_endpoint_disable (struct rescan: /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) { - usb_endpoint_halt (udev, epnum, 0); + if (endpoint & USB_DIR_IN) udev->epmaxpacketin [epnum] = 0; - } else { - usb_endpoint_halt (udev, epnum, 1); + else udev->epmaxpacketout [epnum] = 0; - } /* then kill any current requests */ spin_lock (&hcd_data_lock); @@ -1536,6 +1477,9 @@ void usb_hcd_giveback_urb (struct usb_hc /* pass ownership to the completion handler */ urb->complete (urb, regs); + atomic_dec (&urb->use_count); + if (unlikely (urb->reject)) + wake_up (&usb_kill_urb_queue); usb_put_urb (urb); } EXPORT_SYMBOL (usb_hcd_giveback_urb); @@ -1579,13 +1523,13 @@ static void hcd_panic (void *_hcd) unsigned i; /* hc's root hub is removed later removed in hcd->stop() */ - down (&hub->serialize); usb_set_device_state(hub, USB_STATE_NOTATTACHED); + usb_lock_device (hub); for (i = 0; i < hub->maxchild; i++) { if (hub->children [i]) usb_disconnect (&hub->children [i]); } - up (&hub->serialize); + usb_unlock_device (hub); } /** --- linux-2.6.8-rc1/drivers/usb/core/hcd.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/hcd.h 2004-07-13 17:09:24.000000000 -0700 @@ -142,7 +142,7 @@ struct usb_operations { int (*deallocate)(struct usb_device *); int (*get_frame_number) (struct usb_device *usb_dev); int (*submit_urb) (struct urb *urb, int mem_flags); - int (*unlink_urb) (struct urb *urb); + int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, @@ -207,7 +207,7 @@ struct hc_driver { extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); extern void usb_bus_init (struct usb_bus *bus); -extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb); +extern int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb); #ifdef CONFIG_PCI struct pci_dev; @@ -359,6 +359,7 @@ static inline int hcd_register_root (str extern struct list_head usb_bus_list; extern struct semaphore usb_bus_list_lock; +extern wait_queue_head_t usb_kill_urb_queue; extern struct usb_bus *usb_bus_get (struct usb_bus *bus); extern void usb_bus_put (struct usb_bus *bus); @@ -366,8 +367,6 @@ extern void usb_bus_put (struct usb_bus extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); -#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) - #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) /* --- linux-2.6.8-rc1/drivers/usb/core/hub.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/hub.c 2004-07-13 17:09:24.000000000 -0700 @@ -53,6 +53,8 @@ static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); +static int hub_port_disable(struct usb_device *hdev, int port); + #ifdef DEBUG static inline char *portspeed (int portstatus) @@ -138,7 +140,7 @@ static void set_port_led( static void led_work (void *__hub) { struct usb_hub *hub = __hub; - struct usb_device *hdev = interface_to_usbdev (hub->intf); + struct usb_device *hdev = hub->hdev; unsigned i; unsigned changed = 0; int cursor = -1; @@ -234,18 +236,11 @@ static void hub_irq(struct urb *urb, str int i; unsigned long bits; - spin_lock(&hub_event_lock); - hub->urb_active = 0; - if (hub->urb_complete) { /* disconnect or rmmod */ - complete(hub->urb_complete); - goto done; - } - switch (urb->status) { case -ENOENT: /* synchronous unlink */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware going away */ - goto done; + return; default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ @@ -268,20 +263,17 @@ static void hub_irq(struct urb *urb, str hub->nerrors = 0; /* Something happened, let khubd figure it out */ + spin_lock(&hub_event_lock); if (list_empty(&hub->event_list)) { list_add_tail(&hub->event_list, &hub_event_list); wake_up(&khubd_wait); } + spin_unlock(&hub_event_lock); resubmit: if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 - /* ENODEV means we raced disconnect() */ - && status != -ENODEV) + && status != -ENODEV && status != -EPERM) dev_err (&hub->intf->dev, "resubmit --> %d\n", status); - if (status == 0) - hub->urb_active = 1; -done: - spin_unlock(&hub_event_lock); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -308,7 +300,7 @@ static void hub_tt_kevent (void *arg) while (!list_empty (&hub->tt.clear_list)) { struct list_head *temp; struct usb_tt_clear *clear; - struct usb_device *hdev; + struct usb_device *hdev = hub->hdev; int status; temp = hub->tt.clear_list.next; @@ -317,7 +309,6 @@ static void hub_tt_kevent (void *arg) /* drop lock so HCD can concurrently report other TT errors */ spin_unlock_irqrestore (&hub->tt.lock, flags); - hdev = interface_to_usbdev (hub->intf); status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); spin_lock_irqsave (&hub->tt.lock, flags); @@ -378,15 +369,14 @@ void usb_hub_tt_clear_buffer (struct usb static void hub_power_on(struct usb_hub *hub) { - struct usb_device *hdev; int i; /* if hub supports power switching, enable power on each port */ if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { dev_dbg(&hub->intf->dev, "enabling power on all ports\n"); - hdev = interface_to_usbdev(hub->intf); for (i = 0; i < hub->descriptor->bNbrPorts; i++) - set_port_feature(hdev, i + 1, USB_PORT_FEAT_POWER); + set_port_feature(hub->hdev, i + 1, + USB_PORT_FEAT_POWER); } /* Wait for power to be enabled */ @@ -396,10 +386,9 @@ static void hub_power_on(struct usb_hub static int hub_hub_status(struct usb_hub *hub, u16 *status, u16 *change) { - struct usb_device *hdev = interface_to_usbdev (hub->intf); int ret; - ret = get_hub_status(hdev, &hub->status->hub); + ret = get_hub_status(hub->hdev, &hub->status->hub); if (ret < 0) dev_err (&hub->intf->dev, "%s failed (err = %d)\n", __FUNCTION__, ret); @@ -414,7 +403,7 @@ static int hub_hub_status(struct usb_hub static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { - struct usb_device *hdev = interface_to_usbdev (hub->intf); + struct usb_device *hdev = hub->hdev; struct device *hub_dev = &hub->intf->dev; u16 hubstatus, hubchange; unsigned int pipe; @@ -612,7 +601,6 @@ static int hub_configure(struct usb_hub message = "couldn't submit status urb"; goto fail; } - hub->urb_active = 1; /* Wake up khubd */ wake_up(&khubd_wait); @@ -635,26 +623,48 @@ fail: return ret; } +static void hub_remove_children_work(void *__hub) +{ + struct usb_hub *hub = __hub; + struct usb_device *hdev = hub->hdev; + int i; + + kfree(hub); + + usb_lock_device(hdev); + for (i = 0; i < hdev->maxchild; ++i) { + if (hdev->children[i]) + usb_disconnect(&hdev->children[i]); + } + usb_unlock_device(hdev); + usb_put_dev(hdev); +} + static unsigned highspeed_hubs; static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); - DECLARE_COMPLETION(urb_complete); + struct usb_device *hdev; + int i, n; if (!hub) return; + hdev = hub->hdev; - if (interface_to_usbdev(intf)->speed == USB_SPEED_HIGH) + if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs--; usb_set_intfdata (intf, NULL); - spin_lock_irq(&hub_event_lock); - hub->urb_complete = &urb_complete; - /* Delete it and then reset it */ - list_del_init(&hub->event_list); + if (hub->urb) { + usb_kill_urb(hub->urb); + usb_free_urb(hub->urb); + hub->urb = NULL; + } + spin_lock_irq(&hub_event_lock); + list_del_init(&hub->event_list); spin_unlock_irq(&hub_event_lock); /* assuming we used keventd, it must quiesce too */ @@ -663,14 +673,6 @@ static void hub_disconnect(struct usb_in if (hub->has_indicators || hub->tt.hub) flush_scheduled_work (); - if (hub->urb) { - usb_unlink_urb(hub->urb); - if (hub->urb_active) - wait_for_completion(&urb_complete); - usb_free_urb(hub->urb); - hub->urb = NULL; - } - if (hub->descriptor) { kfree(hub->descriptor); hub->descriptor = NULL; @@ -682,14 +684,32 @@ static void hub_disconnect(struct usb_in } if (hub->buffer) { - usb_buffer_free(interface_to_usbdev(intf), - sizeof(*hub->buffer), hub->buffer, + usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer, hub->buffer_dma); hub->buffer = NULL; } - /* Free the memory */ - kfree(hub); + /* If there are any children then this is unbind only, not a + * physical disconnection. The active ports must be disabled + * and later on we must call usb_disconnect(). We can't call + * it here because we already own the usb bus writelock. + */ + n = 0; + for (i = 0; i < hdev->maxchild; ++i) { + if (hdev->children[i]) { + ++n; + hub_port_disable(hdev, i); + } + } + + if (n == 0) + kfree(hub); + else { + /* Reuse hub->leds to disconnect the children */ + INIT_WORK(&hub->leds, hub_remove_children_work, hub); + schedule_work(&hub->leds); + usb_get_dev(hdev); + } } static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -741,6 +761,7 @@ descriptor_error: INIT_LIST_HEAD(&hub->event_list); hub->intf = intf; + hub->hdev = hdev; INIT_WORK(&hub->leds, led_work, hub); usb_set_intfdata (intf, hub); @@ -792,7 +813,7 @@ hub_ioctl(struct usb_interface *intf, un static int hub_reset(struct usb_hub *hub) { - struct usb_device *hdev = interface_to_usbdev(hub->intf); + struct usb_device *hdev = hub->hdev; int i; /* Disconnect any attached devices */ @@ -803,7 +824,7 @@ static int hub_reset(struct usb_hub *hub /* Attempt to reset the hub */ if (hub->urb) - usb_unlink_urb(hub->urb); + usb_kill_urb(hub->urb); else return -1; @@ -855,7 +876,7 @@ static void recursively_mark_NOTATTACHED * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the udev->serialize semaphore. This + * udev->state is _not_ protected by the device lock. This * is so that devices can be marked as disconnected as soon as possible, * without having to wait for the semaphore to be released. Instead, * changes to the state must be protected by the device_state_lock spinlock. @@ -946,7 +967,7 @@ void usb_disconnect(struct usb_device ** /* lock the bus list on behalf of HCDs unregistering their root hubs */ if (!udev->parent) down(&usb_bus_list_lock); - down(&udev->serialize); + usb_lock_device(udev); dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum); @@ -975,7 +996,7 @@ void usb_disconnect(struct usb_device ** *pdev = NULL; spin_unlock_irq(&device_state_lock); - up(&udev->serialize); + usb_unlock_device(udev); if (!udev->parent) up(&usb_bus_list_lock); @@ -1467,8 +1488,6 @@ hub_port_init (struct usb_device *hdev, != udev->descriptor.bMaxPacketSize0)) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - usb_endpoint_running(udev, 0, 1); - usb_endpoint_running(udev, 0, 0); udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0; udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0; } @@ -1514,8 +1533,9 @@ check_highspeed (struct usb_hub *hub, st } static unsigned -hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev) +hub_power_remaining (struct usb_hub *hub) { + struct usb_device *hdev = hub->hdev; int remaining; unsigned i; @@ -1556,7 +1576,7 @@ hub_power_remaining (struct usb_hub *hub static void hub_port_connect_change(struct usb_hub *hub, int port, u16 portstatus, u16 portchange) { - struct usb_device *hdev = interface_to_usbdev(hub->intf); + struct usb_device *hdev = hub->hdev; struct device *hub_dev = &hub->intf->dev; int status, i; @@ -1673,7 +1693,7 @@ static void hub_port_connect_change(stru * udev becomes globally accessible, although presumably * no one will look at it until hdev is unlocked. */ - down (&udev->serialize); + usb_lock_device (udev); status = 0; /* We mustn't add new devices if the parent hub has @@ -1697,11 +1717,11 @@ static void hub_port_connect_change(stru } } - up (&udev->serialize); + usb_unlock_device (udev); if (status) goto loop; - status = hub_power_remaining(hub, hdev); + status = hub_power_remaining(hub); if (status) dev_dbg(hub_dev, "%dmA power budget left\n", @@ -1755,7 +1775,7 @@ static void hub_events(void) list_del_init(tmp); hub = list_entry(tmp, struct usb_hub, event_list); - hdev = interface_to_usbdev(hub->intf); + hdev = hub->hdev; hub_dev = &hub->intf->dev; usb_get_dev(hdev); @@ -1763,7 +1783,7 @@ static void hub_events(void) /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ - down(&hdev->serialize); + usb_lock_device(hdev); if (hdev->state != USB_STATE_CONFIGURED || !hdev->actconfig || hub != usb_get_intfdata( @@ -1879,7 +1899,7 @@ static void hub_events(void) } loop: - up(&hdev->serialize); + usb_unlock_device(hdev); usb_put_dev(hdev); } /* end while (1) */ @@ -2030,8 +2050,10 @@ static int config_descriptors_changed(st * * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. + * For calls that might not occur during probe(), drivers should lock + * the device using usb_lock_device_for_reset(). */ -int __usb_reset_device(struct usb_device *udev) +int usb_reset_device(struct usb_device *udev) { struct usb_device *parent = udev->parent; struct usb_device_descriptor descriptor = udev->descriptor; @@ -2067,6 +2089,11 @@ int __usb_reset_device(struct usb_device return -ENOENT; } + /* ep0 maxpacket size may change; let the HCD know about it. + * Other endpoints will be handled by re-enumeration. */ + usb_disable_endpoint(udev, 0); + usb_disable_endpoint(udev, 0 + USB_DIR_IN); + ret = hub_port_init(parent, udev, port); if (ret < 0) goto re_enumerate; @@ -2098,7 +2125,7 @@ int __usb_reset_device(struct usb_device struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle and halt status even + /* set_interface resets host side toggle even * for altsetting zero. the interface may have no driver. */ desc = &intf->cur_altsetting->desc; @@ -2131,15 +2158,3 @@ re_enumerate: return -ENODEV; } -EXPORT_SYMBOL(__usb_reset_device); - -int usb_reset_device(struct usb_device *udev) -{ - int r; - - down(&udev->serialize); - r = __usb_reset_device(udev); - up(&udev->serialize); - - return r; -} --- linux-2.6.8-rc1/drivers/usb/core/hub.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/hub.h 2004-07-13 17:09:24.000000000 -0700 @@ -187,9 +187,8 @@ extern void usb_hub_tt_clear_buffer (str struct usb_hub { struct usb_interface *intf; /* the "real" device */ + struct usb_device *hdev; struct urb *urb; /* for interrupt polling pipe */ - struct completion *urb_complete; /* wait for urb to end */ - unsigned int urb_active:1; /* buffer for urb ... 1 bit each for hub and children, rounded up */ char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8]; --- linux-2.6.8-rc1/drivers/usb/core/inode.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/core/inode.c 2004-07-13 17:09:24.000000000 -0700 @@ -48,6 +48,7 @@ static struct vfsmount *usbdevfs_mount; static struct vfsmount *usbfs_mount; static int usbdevfs_mount_count; /* = 0 */ static int usbfs_mount_count; /* = 0 */ +static int ignore_mount = 0; static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; @@ -88,6 +89,17 @@ static int parse_options(struct super_bl char *p; int option; + /* (re)set to defaults. */ + devuid = 0; + busuid = 0; + listuid = 0; + devgid = 0; + busgid = 0; + listgid = 0; + devmode = S_IWUSR | S_IRUGO; + busmode = S_IXUGO | S_IRUGO; + listmode = S_IRUGO; + while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; @@ -151,6 +163,89 @@ static int parse_options(struct super_bl return 0; } +static void update_special(struct dentry *special) +{ + special->d_inode->i_uid = listuid; + special->d_inode->i_gid = listgid; + special->d_inode->i_mode = S_IFREG | listmode; +} + +static void update_dev(struct dentry *dev) +{ + dev->d_inode->i_uid = devuid; + dev->d_inode->i_gid = devgid; + dev->d_inode->i_mode = S_IFREG | devmode; +} + +static void update_bus(struct dentry *bus) +{ + struct dentry *dev = NULL; + + bus->d_inode->i_uid = busuid; + bus->d_inode->i_gid = busgid; + bus->d_inode->i_mode = S_IFDIR | busmode; + + down(&bus->d_inode->i_sem); + + list_for_each_entry(dev, &bus->d_subdirs, d_child) + if (dev->d_inode) + update_dev(dev); + + up(&bus->d_inode->i_sem); +} + +static void update_sb(struct super_block *sb) +{ + struct dentry *root = sb->s_root; + struct dentry *bus = NULL; + + if (!root) + return; + + down(&root->d_inode->i_sem); + + list_for_each_entry(bus, &root->d_subdirs, d_child) { + if (bus->d_inode) { + switch (S_IFMT & bus->d_inode->i_mode) { + case S_IFDIR: + update_bus(bus); + break; + case S_IFREG: + update_special(bus); + break; + default: + warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode); + break; + } + } + } + + up(&root->d_inode->i_sem); +} + +static int remount(struct super_block *sb, int *flags, char *data) +{ + /* If this is not a real mount, + * i.e. it's a simple_pin_fs from create_special_files, + * then ignore it. + */ + if (ignore_mount) + return 0; + + if (parse_options(sb, data)) { + warn("usbfs: mount parameter error:"); + return -EINVAL; + } + + if (usbfs_mount && usbfs_mount->mnt_sb) + update_sb(usbfs_mount->mnt_sb); + + if (usbdevfs_mount && usbdevfs_mount->mnt_sb) + update_sb(usbdevfs_mount->mnt_sb); + + return 0; +} + static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev) { struct inode *inode = new_inode(sb); @@ -349,6 +444,7 @@ static struct inode_operations usbfs_dir static struct super_operations usbfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .remount_fs = remount, }; static int usbfs_fill_super(struct super_block *sb, void *data, int silent) @@ -356,11 +452,6 @@ static int usbfs_fill_super(struct super struct inode *inode; struct dentry *root; - if (parse_options(sb, data)) { - warn("usbfs: mount parameter error:"); - return -EINVAL; - } - sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = USBDEVICE_SUPER_MAGIC; @@ -523,6 +614,11 @@ static int create_special_files (void) struct dentry *parent; int retval; + /* the simple_pin_fs calls will call remount with no options + * without this flag that would overwrite the real mount options (if any) + */ + ignore_mount = 1; + /* create the devices special file */ retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count); if (retval) { @@ -536,6 +632,8 @@ static int create_special_files (void) goto error_clean_usbdevfs_mount; } + ignore_mount = 0; + parent = usbfs_mount->mnt_sb->s_root; devices_usbfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent, --- linux-2.6.8-rc1/drivers/usb/core/message.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/message.c 2004-07-13 17:09:24.000000000 -0700 @@ -605,12 +605,128 @@ int usb_get_descriptor(struct usb_device * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size) +int usb_get_string(struct usb_device *dev, unsigned short langid, + unsigned char index, void *buf, int size) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (USB_DT_STRING << 8) + index, langid, buf, size, - HZ * USB_CTRL_GET_TIMEOUT); + int i; + int result; + + for (i = 0; i < 3; ++i) { + /* retry on length 0 or stall; some devices are flakey */ + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, buf, size, + HZ * USB_CTRL_GET_TIMEOUT); + if (!(result == 0 || result == -EPIPE)) + break; + } + return result; +} + +static int usb_string_sub(struct usb_device *dev, unsigned int langid, + unsigned int index, unsigned char *buf) +{ + int rc; + + /* Try to read the string descriptor by asking for the maximum + * possible number of bytes */ + rc = usb_get_string(dev, langid, index, buf, 255); + + /* If that failed try to read the descriptor length, then + * ask for just that many bytes */ + if (rc < 0) { + rc = usb_get_string(dev, langid, index, buf, 2); + if (rc == 2) + rc = usb_get_string(dev, langid, index, buf, buf[0]); + } + + if (rc >= 0) { + /* There might be extra junk at the end of the descriptor */ + if (buf[0] < rc) + rc = buf[0]; + if (rc < 2) + rc = -EINVAL; + } + return rc; +} + +/** + * usb_string - returns ISO 8859-1 version of a string descriptor + * @dev: the device whose string descriptor is being retrieved + * @index: the number of the descriptor + * @buf: where to put the string + * @size: how big is "buf"? + * Context: !in_interrupt () + * + * This converts the UTF-16LE encoded strings returned by devices, from + * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones + * that are more usable in most kernel contexts. Note that all characters + * in the chosen descriptor that can't be encoded using ISO-8859-1 + * are converted to the question mark ("?") character, and this function + * chooses strings in the first language supported by the device. + * + * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit + * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode, + * and is appropriate for use many uses of English and several other + * Western European languages. (But it doesn't include the "Euro" symbol.) + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Returns length of the string (>= 0) or usb_control_msg status (< 0). + */ +int usb_string(struct usb_device *dev, int index, char *buf, size_t size) +{ + unsigned char *tbuf; + int err; + unsigned int u, idx; + + if (size <= 0 || !buf || !index) + return -EINVAL; + buf[0] = 0; + tbuf = kmalloc(256, GFP_KERNEL); + if (!tbuf) + return -ENOMEM; + + /* get langid for strings if it's not yet known */ + if (!dev->have_langid) { + err = usb_string_sub(dev, 0, 0, tbuf); + if (err < 0) { + dev_err (&dev->dev, + "string descriptor 0 read error: %d\n", + err); + goto errout; + } else if (err < 4) { + dev_err (&dev->dev, "string descriptor 0 too short\n"); + err = -EINVAL; + goto errout; + } else { + dev->have_langid = -1; + dev->string_langid = tbuf[2] | (tbuf[3]<< 8); + /* always use the first langid listed */ + dev_dbg (&dev->dev, "default language 0x%04x\n", + dev->string_langid); + } + } + + err = usb_string_sub(dev, dev->string_langid, index, tbuf); + if (err < 0) + goto errout; + + size--; /* leave room for trailing NULL char in output buffer */ + for (idx = 0, u = 2; u < err; u += 2) { + if (idx >= size) + break; + if (tbuf[u+1]) /* high byte */ + buf[idx++] = '?'; /* non ISO-8859-1 character */ + else + buf[idx++] = tbuf[u]; + } + buf[idx] = 0; + err = idx; + + errout: + kfree(tbuf); + return err; } /** @@ -738,9 +854,8 @@ int usb_clear_halt(struct usb_device *de * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear, then ep was reactivated */ + /* toggle was reset by the clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0; } @@ -754,9 +869,8 @@ int usb_clear_halt(struct usb_device *de * Deallocates hcd/hardware state for this endpoint ... and nukes all * pending urbs. * - * If the HCD hasn't registered a disable() function, this marks the - * endpoint as halted and sets its maxpacket size to 0 to prevent - * further submissions. + * If the HCD hasn't registered a disable() function, this sets the + * endpoint's maxpacket size to 0 to prevent further submissions. */ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) { @@ -765,13 +879,10 @@ void usb_disable_endpoint(struct usb_dev else { unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - if (usb_endpoint_out(epaddr)) { - usb_endpoint_halt(dev, epnum, 1); + if (usb_endpoint_out(epaddr)) dev->epmaxpacketout[epnum] = 0; - } else { - usb_endpoint_halt(dev, epnum, 0); + else dev->epmaxpacketin[epnum] = 0; - } } } @@ -814,7 +925,6 @@ void usb_disable_device(struct usb_devic usb_disable_endpoint(dev, i + USB_DIR_IN); } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -850,9 +960,8 @@ void usb_disable_device(struct usb_devic * @dev: the device whose interface is being enabled * @epd: pointer to the endpoint descriptor * - * Marks the endpoint as running, resets its toggle, and stores - * its maxpacket value. For control endpoints, both the input - * and output sides are handled. + * Resets the endpoint toggle and stores its maxpacket value. + * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *epd) @@ -864,12 +973,10 @@ void usb_enable_endpoint(struct usb_devi USB_ENDPOINT_XFER_CONTROL); if (usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 1); usb_settoggle(dev, epnum, 1, 0); dev->epmaxpacketout[epnum] = maxsize; } if (!usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 0); usb_settoggle(dev, epnum, 0, 0); dev->epmaxpacketin[epnum] = maxsize; } @@ -932,6 +1039,9 @@ int usb_set_interface(struct usb_device int ret; int manual = 0; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + iface = usb_ifnum_to_if(dev, interface); if (!iface) { dev_dbg(&dev->dev, "selecting invalid interface %d\n", @@ -1022,6 +1132,8 @@ int usb_set_interface(struct usb_device * use usb_set_interface() on the interfaces it claims. Resetting the whole * configuration would affect other drivers' interfaces. * + * The caller must have locked the device. + * * Returns zero on success, else a negative error code. */ int usb_reset_configuration(struct usb_device *dev) @@ -1029,8 +1141,11 @@ int usb_reset_configuration(struct usb_d int i, retval; struct usb_host_config *config; - /* caller must own dev->serialize (config won't change) - * and the usb bus readlock (so driver bindings are stable); + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + + /* caller must have locked the device and must own + * the usb bus readlock (so driver bindings are stable); * so calls during probe() are fine */ @@ -1050,7 +1165,6 @@ int usb_reset_configuration(struct usb_d } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { @@ -1087,7 +1201,7 @@ static void release_interface(struct dev * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. - * Context: !in_interrupt(), caller holds dev->serialize + * Context: !in_interrupt(), caller has locked the device * * This is used to enable non-default device modes. Not all devices * use this kind of configurability; many devices only have one @@ -1108,8 +1222,8 @@ static void release_interface(struct dev * usb_set_interface(). * * This call is synchronous. The calling context must be able to sleep, - * and must not hold the driver model lock for USB; usb device driver - * probe() methods may not use this routine. + * must have locked the device, and must not hold the driver model lock + * for USB; usb device driver probe() methods cannot use this routine. * * Returns zero on success, or else the status code returned by the * underlying call that failed. On succesful completion, each interface @@ -1124,8 +1238,6 @@ int usb_set_configuration(struct usb_dev struct usb_interface **new_interfaces = NULL; int n, nintf; - /* dev->serialize guards all config changes */ - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { cp = &dev->config[i]; @@ -1142,6 +1254,9 @@ int usb_set_configuration(struct usb_dev if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; @@ -1257,102 +1372,6 @@ free_interfaces: return ret; } -/** - * usb_string - returns ISO 8859-1 version of a string descriptor - * @dev: the device whose string descriptor is being retrieved - * @index: the number of the descriptor - * @buf: where to put the string - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * This converts the UTF-16LE encoded strings returned by devices, from - * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones - * that are more usable in most kernel contexts. Note that all characters - * in the chosen descriptor that can't be encoded using ISO-8859-1 - * are converted to the question mark ("?") character, and this function - * chooses strings in the first language supported by the device. - * - * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit - * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode, - * and is appropriate for use many uses of English and several other - * Western European languages. (But it doesn't include the "Euro" symbol.) - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns length of the string (>= 0) or usb_control_msg status (< 0). - */ -int usb_string(struct usb_device *dev, int index, char *buf, size_t size) -{ - unsigned char *tbuf; - int err, len; - unsigned int u, idx; - - if (size <= 0 || !buf || !index) - return -EINVAL; - buf[0] = 0; - tbuf = kmalloc(256, GFP_KERNEL); - if (!tbuf) - return -ENOMEM; - - /* get langid for strings if it's not yet known */ - if (!dev->have_langid) { - err = usb_get_descriptor(dev, USB_DT_STRING, 0, tbuf, 4); - if (err < 0) { - dev_err (&dev->dev, - "string descriptor 0 read error: %d\n", - err); - goto errout; - } else if (err < 4 || tbuf[0] < 4) { - dev_err (&dev->dev, "string descriptor 0 too short\n"); - err = -EINVAL; - goto errout; - } else { - dev->have_langid = -1; - dev->string_langid = tbuf[2] | (tbuf[3]<< 8); - /* always use the first langid listed */ - dev_dbg (&dev->dev, "default language 0x%04x\n", - dev->string_langid); - } - } - - /* - * ask for the length of the string - */ - - err = usb_get_string(dev, dev->string_langid, index, tbuf, 2); - if (err == -EPIPE || err == 0) { - dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, 2); - err = usb_get_string(dev, dev->string_langid, index, tbuf, 2); - } - if(err<2) - goto errout; - len=tbuf[0]; - - err = usb_get_string(dev, dev->string_langid, index, tbuf, len); - if (err == -EPIPE || err == 0) { - dev_dbg(&dev->dev, "RETRY string %d read/%d\n", index, len); - err = usb_get_string(dev, dev->string_langid, index, tbuf, len); - } - if (err < 0) - goto errout; - - size--; /* leave room for trailing NULL char in output buffer */ - for (idx = 0, u = 2; u < err; u += 2) { - if (idx >= size) - break; - if (tbuf[u+1]) /* high byte */ - buf[idx++] = '?'; /* non ISO-8859-1 character */ - else - buf[idx++] = tbuf[u]; - } - buf[idx] = 0; - err = idx; - - errout: - kfree(tbuf); - return err; -} - // synchronous request completion model EXPORT_SYMBOL(usb_control_msg); EXPORT_SYMBOL(usb_bulk_msg); --- linux-2.6.8-rc1/drivers/usb/core/sysfs.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/sysfs.c 2004-07-13 17:09:24.000000000 -0700 @@ -55,9 +55,9 @@ set_bConfigurationValue (struct device * if (sscanf (buf, "%u", &config) != 1 || config > 255) return -EINVAL; - down(&udev->serialize); + usb_lock_device(udev); value = usb_set_configuration (udev, config); - up(&udev->serialize); + usb_unlock_device(udev); return (value < 0) ? value : count; } --- linux-2.6.8-rc1/drivers/usb/core/urb.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/core/urb.c 2004-07-13 17:09:24.000000000 -0700 @@ -77,7 +77,7 @@ struct urb *usb_alloc_urb(int iso_packet /** * usb_free_urb - frees the memory used by a urb when all users of it are finished - * @urb: pointer to the urb to free + * @urb: pointer to the urb to free, may be NULL * * Must be called when a user of a urb is finished with it. When the last user * of the urb calls this function, the memory of the urb is freed. @@ -93,7 +93,7 @@ void usb_free_urb(struct urb *urb) /** * usb_get_urb - increments the reference count of the urb - * @urb: pointer to the urb to modify + * @urb: pointer to the urb to modify, may be NULL * * This must be called whenever a urb is transferred from a device driver to a * host controller driver. This allows proper reference counting to happen @@ -256,13 +256,6 @@ int usb_submit_urb(struct urb *urb, int if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* (actually HCDs may need to duplicate this, endpoint might yet - * stall due to queued bulk/intr transactions that complete after - * we check) - */ - if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) - return -EPIPE; - /* FIXME there should be a sharable lock protecting us against * config/altsetting changes and disconnects, kicking in here. * (here == before maxpacket, and eventually endpoint type, @@ -398,7 +391,8 @@ int usb_submit_urb(struct urb *urb, int /** * usb_unlink_urb - abort/cancel a transfer request for an endpoint - * @urb: pointer to urb describing a previously submitted request + * @urb: pointer to urb describing a previously submitted request, + * may be NULL * * This routine cancels an in-progress request. URBs complete only * once per submission, and may be canceled only once per submission. @@ -407,26 +401,25 @@ int usb_submit_urb(struct urb *urb, int * canceled (rather than any other code) and will quickly be removed * from host controller data structures. * - * When the URB_ASYNC_UNLINK transfer flag for the URB is clear, this - * request is synchronous. Success is indicated by returning zero, - * at which time the urb will have been unlinked and its completion - * handler will have been called with urb->status == -ENOENT. Failure is - * indicated by any other return value. - * - * The synchronous cancelation mode may not be used - * when unlinking an urb from an interrupt context, such as a bottom - * half or a completion handler; or when holding a spinlock; or in - * other cases when the caller can't schedule(). + * In the past, clearing the URB_ASYNC_UNLINK transfer flag for the + * URB indicated that the request was synchronous. This usage is now + * deprecated; if the flag is clear the call will be forwarded to + * usb_kill_urb() and the return value will be 0. In the future, drivers + * should call usb_kill_urb() directly for synchronous unlinking. * * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this * request is asynchronous. Success is indicated by returning -EINPROGRESS, - * at which time the urb will normally not have been unlinked. - * The completion function will see urb->status == -ECONNRESET. Failure - * is indicated by any other return value. + * at which time the URB will normally have been unlinked but not yet + * given back to the device driver. When it is called, the completion + * function will see urb->status == -ECONNRESET. Failure is indicated + * by any other return value. Unlinking will fail when the URB is not + * currently "linked" (i.e., it was never submitted, or it was unlinked + * before, or the hardware is already finished with it), even if the + * completion handler has not yet run. * * Unlinking and Endpoint Queues: * - * Host Controller Driver (HCDs) place all the URBs for a particular + * Host Controller Drivers (HCDs) place all the URBs for a particular * endpoint in a queue. Normally the queue advances as the controller * hardware processes each request. But when an URB terminates with any * fault (such as an error, or being unlinked) its queue stops, at least @@ -449,16 +442,57 @@ int usb_submit_urb(struct urb *urb, int * An unlinked URB may leave a gap in the stream of packets. It is undefined * whether such gaps can be filled in. * - * When control URBs terminates with an error, it is likely that the + * When a control URB terminates with an error, it is likely that the * status stage of the transfer will not take place, even if it is merely * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set. */ int usb_unlink_urb(struct urb *urb) { - if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) - return urb->dev->bus->op->unlink_urb(urb); - else + if (!urb) + return -EINVAL; + if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { + usb_kill_urb(urb); + return 0; + } + if (!(urb->dev && urb->dev->bus && urb->dev->bus->op)) return -ENODEV; + return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET); +} + +/** + * usb_kill_urb - cancel a transfer request and wait for it to finish + * @urb: pointer to URB describing a previously submitted request, + * may be NULL + * + * This routine cancels an in-progress request. It is guaranteed that + * upon return all completion handlers will have finished and the URB + * will be totally idle and available for reuse. These features make + * this an ideal way to stop I/O in a disconnect() callback or close() + * function. If the request has not already finished or been unlinked + * the completion handler will see urb->status == -ENOENT. + * + * While the routine is running, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * This routine may not be used in an interrupt context (such as a bottom + * half or a completion handler), or when holding a spinlock, or in other + * situations where the caller can't schedule(). + */ +void usb_kill_urb(struct urb *urb) +{ + if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op)) + return; + spin_lock_irq(&urb->lock); + ++urb->reject; + spin_unlock_irq(&urb->lock); + + urb->dev->bus->op->unlink_urb(urb, -ENOENT); + wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); + + spin_lock_irq(&urb->lock); + --urb->reject; + spin_unlock_irq(&urb->lock); } EXPORT_SYMBOL(usb_init_urb); @@ -467,4 +501,5 @@ EXPORT_SYMBOL(usb_free_urb); EXPORT_SYMBOL(usb_get_urb); EXPORT_SYMBOL(usb_submit_urb); EXPORT_SYMBOL(usb_unlink_urb); +EXPORT_SYMBOL(usb_kill_urb); --- linux-2.6.8-rc1/drivers/usb/core/usb.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/usb.c 2004-07-13 17:09:24.000000000 -0700 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,8 @@ const char *usbcore_name = "usbcore"; int nousb; /* Disable USB when built into kernel image */ /* Not honored on modular build */ +static DECLARE_RWSEM(usb_all_devices_rwsem); + static int generic_probe (struct device *dev) { @@ -93,11 +96,16 @@ int usb_probe_interface(struct device *d if (!driver->probe) return error; + if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); + intf->condition = USB_INTERFACE_BINDING; error = driver->probe (intf, id); + intf->condition = error ? USB_INTERFACE_UNBOUND : + USB_INTERFACE_BOUND; } return error; @@ -109,6 +117,8 @@ int usb_unbind_interface(struct device * struct usb_interface *intf = to_usb_interface(dev); struct usb_driver *driver = to_usb_driver(intf->dev.driver); + intf->condition = USB_INTERFACE_UNBINDING; + /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -120,6 +130,7 @@ int usb_unbind_interface(struct device * intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); + intf->condition = USB_INTERFACE_UNBOUND; return 0; } @@ -149,7 +160,9 @@ int usb_register(struct usb_driver *new_ new_driver->driver.probe = usb_probe_interface; new_driver->driver.remove = usb_unbind_interface; + usb_lock_all_devices(); retval = driver_register(&new_driver->driver); + usb_unlock_all_devices(); if (!retval) { pr_info("%s: registered new driver %s\n", @@ -178,7 +191,9 @@ void usb_deregister(struct usb_driver *d { pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); + usb_lock_all_devices(); driver_unregister (&driver->driver); + usb_unlock_all_devices(); usbfs_update_special(); } @@ -200,7 +215,7 @@ void usb_deregister(struct usb_driver *d * alternate settings available for this interfaces. * * Don't call this function unless you are bound to one of the interfaces - * on this device or you own the dev->serialize semaphore! + * on this device or you have locked the device! */ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) { @@ -233,7 +248,7 @@ struct usb_interface *usb_ifnum_to_if(st * drivers avoid such mistakes. * * Don't call this function unless you are bound to the intf interface - * or you own the device's ->serialize semaphore! + * or you have locked the device! */ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, unsigned int altnum) @@ -301,9 +316,9 @@ usb_epnum_to_ep_desc(struct usb_device * * way to bind to an interface is to return the private data from * the driver's probe() method. * - * Callers must own the driver model's usb bus writelock. So driver - * probe() entries don't need extra locking, but other call contexts - * may need to explicitly claim that lock. + * Callers must lock the device and own the driver model's usb bus writelock. + * So driver probe() entries don't need extra locking, but other call contexts + * may need to explicitly claim those locks. */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) { @@ -314,6 +329,7 @@ int usb_driver_claim_interface(struct us dev->driver = &driver->driver; usb_set_intfdata(iface, priv); + iface->condition = USB_INTERFACE_BOUND; /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -334,8 +350,8 @@ int usb_driver_claim_interface(struct us * also causes the driver disconnect() method to be called. * * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the usb_device serialize semaphore and the driver model's - * usb bus writelock. So driver disconnect() entries don't need extra locking, + * Callers must lock the device and own the driver model's usb bus writelock. + * So driver disconnect() entries don't need extra locking, * but other call contexts may need to explicitly claim those locks. */ void usb_driver_release_interface(struct usb_driver *driver, @@ -353,6 +369,7 @@ void usb_driver_release_interface(struct dev->driver = NULL; usb_set_intfdata(iface, NULL); + iface->condition = USB_INTERFACE_UNBOUND; } /** @@ -828,6 +845,116 @@ void usb_put_intf(struct usb_interface * put_device(&intf->dev); } +/** + * usb_lock_device - acquire the lock for a usb device structure + * @udev: device that's being locked + * + * Use this routine rather than manipulating udev->serialize directly. + * This is necessary for proper interaction with usb_lock_all_devices(). + */ +void usb_lock_device(struct usb_device *udev) +{ + down_read(&usb_all_devices_rwsem); + down(&udev->serialize); +} + +/** + * usb_trylock_device - attempt to acquire the lock for a usb device structure + * @udev: device that's being locked + * + * Use this routine rather than manipulating udev->serialize directly. + * This is necessary for proper interaction with usb_lock_all_devices(). + * + * Returns 1 if successful, 0 if contention. + */ +int usb_trylock_device(struct usb_device *udev) +{ + if (!down_read_trylock(&usb_all_devices_rwsem)) + return 0; + if (down_trylock(&udev->serialize)) { + up_read(&usb_all_devices_rwsem); + return 0; + } + return 1; +} + +/** + * usb_lock_device_for_reset - cautiously acquire the lock for a + * usb device structure + * @udev: device that's being locked + * @iface: interface bound to the driver making the request (optional) + * + * Attempts to acquire the device lock, but fails if the device is + * NOTATTACHED or SUSPENDED, or if iface is specified and the interface + * is neither BINDING nor BOUND. Rather than sleeping to wait for the + * lock, the routine polls repeatedly. This is to prevent deadlock with + * disconnect; in some drivers (such as usb-storage) the disconnect() + * callback will block waiting for a device reset to complete. + * + * Returns a negative error code for failure, otherwise 1 or 0 to indicate + * that the device will or will not have to be unlocked. (0 can be + * returned when an interface is given and is BINDING, because in that + * case the driver already owns the device lock.) + */ +int usb_lock_device_for_reset(struct usb_device *udev, + struct usb_interface *iface) +{ + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; + if (iface) { + switch (iface->condition) { + case USB_INTERFACE_BINDING: + return 0; + case USB_INTERFACE_BOUND: + break; + default: + return -EINTR; + } + } + + while (!usb_trylock_device(udev)) { + msleep(15); + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; + if (iface && iface->condition != USB_INTERFACE_BOUND) + return -EINTR; + } + return 1; +} + +/** + * usb_unlock_device - release the lock for a usb device structure + * @udev: device that's being unlocked + * + * Use this routine rather than manipulating udev->serialize directly. + * This is necessary for proper interaction with usb_lock_all_devices(). + */ +void usb_unlock_device(struct usb_device *udev) +{ + up(&udev->serialize); + up_read(&usb_all_devices_rwsem); +} + +/** + * usb_lock_all_devices - acquire the lock for all usb device structures + * + * This is necessary when registering a new driver or probing a bus, + * since the driver-model core may try to use any usb_device. + */ +void usb_lock_all_devices(void) +{ + down_write(&usb_all_devices_rwsem); +} + +/** + * usb_unlock_all_devices - release the lock for all usb device structures + */ +void usb_unlock_all_devices(void) +{ + up_write(&usb_all_devices_rwsem); +} + + static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) { @@ -849,8 +976,10 @@ static struct usb_device *match_device(s /* look through all of the children of this device */ for (child = 0; child < dev->maxchild; ++child) { if (dev->children[child]) { + usb_lock_device(dev->children[child]); ret_dev = match_device(dev->children[child], vendor_id, product_id); + usb_unlock_device(dev->children[child]); if (ret_dev) goto exit; } @@ -885,7 +1014,9 @@ struct usb_device *usb_find_device(u16 v bus = container_of(buslist, struct usb_bus, bus_list); if (!bus->root_hub) continue; + usb_lock_device(bus->root_hub); dev = match_device(bus->root_hub, vendor_id, product_id); + usb_unlock_device(bus->root_hub); if (dev) goto exit; } @@ -1363,6 +1494,11 @@ EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); EXPORT_SYMBOL(usb_hub_tt_clear_buffer); +EXPORT_SYMBOL(usb_lock_device); +EXPORT_SYMBOL(usb_trylock_device); +EXPORT_SYMBOL(usb_lock_device_for_reset); +EXPORT_SYMBOL(usb_unlock_device); + EXPORT_SYMBOL(usb_driver_claim_interface); EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_match_id); --- linux-2.6.8-rc1/drivers/usb/core/usb.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/core/usb.h 2004-07-13 17:09:24.000000000 -0700 @@ -24,5 +24,8 @@ extern int usb_set_configuration(struct extern void usb_set_device_state(struct usb_device *udev, enum usb_device_state new_state); +extern void usb_lock_all_devices(void); +extern void usb_unlock_all_devices(void); + /* for labeling diagnostics */ extern const char *usbcore_name; --- linux-2.6.8-rc1/drivers/usb/gadget/epautoconf.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/gadget/epautoconf.c 2004-07-13 17:09:13.000000000 -0700 @@ -192,7 +192,7 @@ find_ep (struct usb_gadget *gadget, cons if (0 == strcmp (ep->name, name)) return ep; } - return 0; + return NULL; } /** @@ -280,7 +280,7 @@ struct usb_ep * __init usb_ep_autoconfig } /* Fail */ - return 0; + return NULL; } /** @@ -297,7 +297,7 @@ void __init usb_ep_autoconfig_reset (str struct usb_ep *ep; list_for_each_entry (ep, &gadget->ep_list, ep_list) { - ep->driver_data = 0; + ep->driver_data = NULL; } #ifdef MANY_ENDPOINTS in_epnum = 0; --- linux-2.6.8-rc1/drivers/usb/gadget/ether.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/ether.c 2004-07-13 17:09:24.000000000 -0700 @@ -338,6 +338,9 @@ module_param (qmult, uint, S_IRUGO|S_IWU * * NOTE: Controllers like superh_udc should probably be able to use * an RNDIS-only configuration. + * + * FIXME define some higher-powered configurations to make it easier + * to recharge batteries ... */ #define DEV_CONFIG_VALUE 1 /* cdc or subset */ @@ -361,6 +364,14 @@ device_desc = { .bNumConfigurations = 1, }; +static struct usb_otg_descriptor +otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + static struct usb_config_descriptor eth_config = { .bLength = sizeof eth_config, @@ -375,7 +386,7 @@ eth_config = { }; #ifdef CONFIG_USB_ETH_RNDIS -static const struct usb_config_descriptor +static struct usb_config_descriptor rndis_config = { .bLength = sizeof rndis_config, .bDescriptorType = USB_DT_CONFIG, @@ -671,7 +682,8 @@ fs_sink_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static const struct usb_descriptor_header *fs_eth_function [10] = { +static const struct usb_descriptor_header *fs_eth_function [11] = { + (struct usb_descriptor_header *) &otg_descriptor, #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, @@ -685,7 +697,7 @@ static const struct usb_descriptor_heade (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, - 0, + NULL, #endif /* DEV_CONFIG_CDC */ }; @@ -695,14 +707,16 @@ static inline void __init fs_subset_desc fs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; fs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; fs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[3] = 0; + fs_eth_function[3] = NULL; #else - fs_eth_function[0] = 0; + fs_eth_function[0] = NULL; + fs_eth_function[1] = 0; #endif } #ifdef CONFIG_USB_ETH_RNDIS static const struct usb_descriptor_header *fs_rndis_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -714,7 +728,7 @@ static const struct usb_descriptor_heade (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, - 0, + NULL, }; #endif @@ -766,7 +780,8 @@ dev_qualifier = { .bNumConfigurations = 1, }; -static const struct usb_descriptor_header *hs_eth_function [10] = { +static const struct usb_descriptor_header *hs_eth_function [11] = { + (struct usb_descriptor_header *) &otg_descriptor, #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, @@ -780,7 +795,7 @@ static const struct usb_descriptor_heade (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, #endif /* DEV_CONFIG_CDC */ }; @@ -790,14 +805,16 @@ static inline void __init hs_subset_desc hs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; hs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; hs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[3] = 0; + hs_eth_function[3] = NULL; #else - hs_eth_function[0] = 0; + hs_eth_function[0] = NULL; + hs_eth_function[1] = 0; #endif } #ifdef CONFIG_USB_ETH_RNDIS static const struct usb_descriptor_header *hs_rndis_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -809,7 +826,7 @@ static const struct usb_descriptor_heade (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; #endif @@ -870,18 +887,20 @@ static struct usb_gadget_strings stringt * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) -{ - int len; +config_buf (enum usb_device_speed speed, + u8 *buf, u8 type, + unsigned index, int is_otg) +{ + int len; + const struct usb_config_descriptor *config; + const struct usb_descriptor_header **function; #ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#define which_config(t) (hs ? & t ## _config : & t ## _config) #define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) #else -#define which_config(t) (& t ## _config) #define which_fn(t) (& fs_ ## t ## _function) #endif @@ -892,15 +911,23 @@ config_buf (enum usb_device_speed speed, /* list the RNDIS config first, to make Microsoft's drivers * happy. DOCSIS 1.0 needs this too. */ - if (device_desc.bNumConfigurations == 2 && index == 0) - len = usb_gadget_config_buf (which_config (rndis), buf, - USB_BUFSIZ, (const struct usb_descriptor_header **) - which_fn (rndis)); - else + if (device_desc.bNumConfigurations == 2 && index == 0) { + config = &rndis_config; + function = (const struct usb_descriptor_header **) + which_fn (rndis); + } else #endif - len = usb_gadget_config_buf (which_config (eth), buf, - USB_BUFSIZ, (const struct usb_descriptor_header **) - which_fn (eth)); + { + config = ð_config; + function = (const struct usb_descriptor_header **) + which_fn (eth); + } + + /* for now, don't advertise srp-only devices */ + if (!is_otg) + function++; + + len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; @@ -1051,8 +1078,8 @@ set_ether_config (struct eth_dev *dev, i if (dev->status_ep) (void) usb_ep_disable (dev->status_ep); #endif - dev->status_ep = 0; - dev->status = 0; + dev->status_ep = NULL; + dev->status = NULL; #if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) if (dev->rndis || !dev->cdc) { if (dev->in_ep) @@ -1061,10 +1088,10 @@ set_ether_config (struct eth_dev *dev, i (void) usb_ep_disable (dev->out_ep); } #endif - dev->in_ep = 0; - dev->in = 0; - dev->out_ep = 0; - dev->out = 0; + dev->in_ep = NULL; + dev->in = NULL; + dev->out_ep = NULL; + dev->out = NULL; } else /* activate non-CDC configs right away @@ -1111,7 +1138,7 @@ static void eth_reset_config (struct eth list_del (&req->list); usb_ep_free_request (dev->in_ep, req); } - dev->in_ep = 0; + dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); @@ -1121,12 +1148,12 @@ static void eth_reset_config (struct eth list_del (&req->list); usb_ep_free_request (dev->out_ep, req); } - dev->out_ep = 0; + dev->out_ep = NULL; } if (dev->status_ep) { usb_ep_disable (dev->status_ep); - dev->status_ep = 0; + dev->status_ep = NULL; } dev->config = 0; } @@ -1387,6 +1414,7 @@ eth_setup (struct usb_gadget *gadget, co /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. */ + req->complete = eth_setup_complete; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -1414,7 +1442,8 @@ eth_setup (struct usb_gadget *gadget, co case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, ctrl->wValue >> 8, - ctrl->wValue & 0xff); + ctrl->wValue & 0xff, + gadget->is_otg); if (value >= 0) value = min (ctrl->wLength, (u16) value); break; @@ -1431,6 +1460,10 @@ eth_setup (struct usb_gadget *gadget, co case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; + if (gadget->a_hnp_support) + DEBUG (dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DEBUG (dev, "HNP needs a different root port\n"); spin_lock (&dev->lock); value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); @@ -1724,9 +1757,10 @@ rx_submit (struct eth_dev *dev, struct u /* Padding up to RX_EXTRA handles minor disagreements with host. * Normally we use the USB "terminate on short read" convention; - * so allow up to (N*maxpacket)-1, since that memory is normally - * already allocated. Major loss of synch means -EOVERFLOW; any - * obviously corrupted packets will automatically be discarded. + * so allow up to (N*maxpacket), since that memory is normally + * already allocated. Some hardware doesn't deal well with short + * reads (e.g. DMA must be N*maxpacket), so for now don't trim a + * byte off the end (to force hardware errors on overflow). * * RNDIS uses internal framing, and explicitly allows senders to * pad to end-of-packet. That's potentially nice for speed, @@ -1739,10 +1773,6 @@ rx_submit (struct eth_dev *dev, struct u size += sizeof (struct rndis_packet_msg_type); #endif size -= size % dev->out_ep->maxpacket; -#ifdef CONFIG_USB_ETH_RNDIS - if (!dev->rndis) -#endif - size--; if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); @@ -1800,7 +1830,7 @@ static void rx_complete (struct usb_ep * * use skb buffers. */ status = netif_rx (skb); - skb = 0; + skb = NULL; break; /* software-driven interface shutdown */ @@ -1834,7 +1864,7 @@ quiesce: clean: /* nobody reading rx_reqs, so no dev->lock */ list_add (&req->list, &dev->rx_reqs); - req = 0; + req = NULL; } if (req) rx_submit (dev, req, GFP_ATOMIC); @@ -1969,7 +1999,7 @@ static int eth_start_xmit (struct sk_buf struct eth_dev *dev = (struct eth_dev *) net->priv; int length = skb->len; int retval; - struct usb_request *req = 0; + struct usb_request *req = NULL; unsigned long flags; /* FIXME check dev->cdc_filter to decide whether to send this, @@ -2212,7 +2242,7 @@ eth_unbind (struct usb_gadget *gadget) dev->req->buf, dev->req->dma, USB_BUFSIZ); usb_ep_free_request (gadget->ep0, dev->req); - dev->req = 0; + dev->req = NULL; } unregister_netdev (dev->net); @@ -2220,7 +2250,7 @@ eth_unbind (struct usb_gadget *gadget) /* assuming we used keventd, it must quiesce too */ flush_scheduled_work (); - set_gadget_data (gadget, 0); + set_gadget_data (gadget, NULL); } static u8 __init nibble (unsigned char c) @@ -2430,6 +2460,14 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered (gadget); + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +#ifdef CONFIG_USB_ETH_RNDIS + rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +#endif + } + net = alloc_etherdev (sizeof *dev); if (!net) return status; --- linux-2.6.8-rc1/drivers/usb/gadget/file_storage.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/file_storage.c 2004-07-13 17:09:13.000000000 -0700 @@ -3673,7 +3673,7 @@ static void fsg_unbind(struct usb_gadget usb_ep_free_request(fsg->ep0, req); } - set_gadget_data(gadget, 0); + set_gadget_data(gadget, NULL); } --- linux-2.6.8-rc1/drivers/usb/gadget/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/inode.c 2004-07-13 17:09:24.000000000 -0700 @@ -171,7 +171,7 @@ static struct dev_data *dev_new (void) dev = kmalloc (sizeof *dev, GFP_KERNEL); if (!dev) - return 0; + return NULL; memset (dev, 0, sizeof *dev); dev->state = STATE_DEV_DISABLED; atomic_set (&dev->count, 1); @@ -253,6 +253,10 @@ static void put_ep (struct ep_data *data #define CHIP "goku_udc" #endif +#ifdef CONFIG_USB_GADGET_OMAP +#define CHIP "omap_udc" +#endif + #ifdef CONFIG_USB_GADGET_SA1100 #define CHIP "sa1100" #endif @@ -597,8 +601,8 @@ static void ep_aio_complete(struct usb_e /* lock against disconnect (and ideally, cancel) */ spin_lock(&epdata->dev->lock); - priv->req = 0; - priv->epdata = 0; + priv->req = NULL; + priv->epdata = NULL; if (NULL == iocb->ki_retry || unlikely(0 == req->actual) || unlikely(kiocbIsCancelled(iocb))) { @@ -737,7 +741,7 @@ static struct file_operations ep_io_oper * speed descriptor, then optional high speed descriptor. */ static ssize_t -ep_config (struct file *fd, const char *buf, size_t len, loff_t *ptr) +ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) { struct ep_data *data = fd->private_data; struct usb_ep *ep; @@ -944,7 +948,7 @@ static int setup_req (struct usb_ep *ep, } static ssize_t -ep0_read (struct file *fd, char *buf, size_t len, loff_t *ptr) +ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) { struct dev_data *dev = fd->private_data; ssize_t retval; @@ -1125,7 +1129,7 @@ next_event (struct dev_data *dev, enum u } static ssize_t -ep0_write (struct file *fd, const char *buf, size_t len, loff_t *ptr) +ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) { struct dev_data *dev = fd->private_data; ssize_t retval = -ESRCH; @@ -1204,7 +1208,7 @@ dev_release (struct inode *inode, struct fasync_helper (-1, fd, 0, &dev->fasync); kfree (dev->buf); - dev->buf = 0; + dev->buf = NULL; put_dev (dev); /* other endpoints were all decoupled from this device */ @@ -1356,7 +1360,7 @@ gadgetfs_setup (struct usb_gadget *gadge req->buf = dev->rbuf; req->dma = DMA_ADDR_INVALID; - req->context = 0; + req->context = NULL; value = -EOPNOTSUPP; switch (ctrl->bRequest) { @@ -1524,7 +1528,7 @@ restart: ep = list_entry (entry, struct ep_data, epfiles); list_del_init (&ep->epfiles); dentry = ep->dentry; - ep->dentry = 0; + ep->dentry = NULL; parent = dentry->d_parent->d_inode; /* break link to controller */ @@ -1532,7 +1536,7 @@ restart: (void) usb_ep_disable (ep->ep); ep->state = STATE_EP_UNBOUND; usb_ep_free_request (ep->ep, ep->req); - ep->ep = 0; + ep->ep = NULL; wake_up (&ep->wait); put_ep (ep); @@ -1612,8 +1616,8 @@ gadgetfs_unbind (struct usb_gadget *gadg spin_unlock_irq (&dev->lock); destroy_ep_files (dev); - gadget->ep0->driver_data = 0; - set_gadget_data (gadget, 0); + gadget->ep0->driver_data = NULL; + set_gadget_data (gadget, NULL); /* we've already been disconnected ... no i/o is active */ if (dev->req) @@ -1646,7 +1650,7 @@ gadgetfs_bind (struct usb_gadget *gadget dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); if (!dev->req) goto enomem; - dev->req->context = 0; + dev->req->context = NULL; dev->req->complete = epio_complete; if (activate_ep_files (dev) < 0) @@ -1763,7 +1767,7 @@ static int is_valid_config (struct usb_c } static ssize_t -dev_config (struct file *fd, const char *buf, size_t len, loff_t *ptr) +dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) { struct dev_data *dev = fd->private_data; ssize_t value = len, length = len; @@ -1835,7 +1839,7 @@ dev_config (struct file *fd, const char value = usb_gadget_register_driver (&gadgetfs_driver); if (value != 0) { kfree (dev->buf); - dev->buf = 0; + dev->buf = NULL; } else { /* at this point "good" hardware has for the first time * let the USB the host see us. alternatively, if users @@ -1855,7 +1859,7 @@ fail: spin_unlock_irq (&dev->lock); pr_debug ("%s: %s fail %Zd, %p\n", shortname, __FUNCTION__, value, dev); kfree (dev->buf); - dev->buf = 0; + dev->buf = NULL; return value; } @@ -1944,13 +1948,13 @@ gadgetfs_create_file (struct super_block qname.hash = full_name_hash (qname.name, qname.len); dentry = d_alloc (sb->s_root, &qname); if (!dentry) - return 0; + return NULL; inode = gadgetfs_make_inode (sb, data, fops, S_IFREG | (default_perm & S_IRWXUGO)); if (!inode) { dput(dentry); - return 0; + return NULL; } d_add (dentry, inode); *dentry_p = dentry; @@ -1980,7 +1984,7 @@ gadgetfs_fill_super (struct super_block /* root inode */ inode = gadgetfs_make_inode (sb, - 0, &simple_dir_operations, + NULL, &simple_dir_operations, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) return -ENOMEM; @@ -2027,7 +2031,7 @@ gadgetfs_kill_sb (struct super_block *sb kill_litter_super (sb); if (the_device) { put_dev (the_device); - the_device = 0; + the_device = NULL; } } --- linux-2.6.8-rc1/drivers/usb/gadget/Kconfig 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/gadget/Kconfig 2004-07-13 17:09:24.000000000 -0700 @@ -208,6 +208,16 @@ config USB_ZERO Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_zero". +config USB_ZERO_HNPTEST + boolean "HNP Test Device" + depends on USB_ZERO && USB_OTG + help + You can configure this device to enumerate using the device + identifiers of the USB-OTG test device. That means that when + this gadget connects to another OTG device, with this one using + the "B-Peripheral" role, that device will use HNP to let this + one serve as the USB host instead (in the "B-Host" role). + config USB_ETH tristate "Ethernet Gadget" depends on NET --- linux-2.6.8-rc1/drivers/usb/gadget/net2280.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/net2280.c 2004-07-13 17:09:13.000000000 -0700 @@ -182,7 +182,7 @@ net2280_enable (struct usb_ep *_ep, cons if (ep->dma && (max % 4) != 0 && use_dma_chaining) { DEBUG (ep->dev, "%s, no dma for maxpacket %d\n", ep->ep.name, ep->ep.maxpacket); - ep->dma = 0; + ep->dma = NULL; } /* set type, direction, address; reset fifo counters */ @@ -280,7 +280,7 @@ static void ep_reset (struct net2280_reg { u32 tmp; - ep->desc = 0; + ep->desc = NULL; INIT_LIST_HEAD (&ep->queue); ep->ep.maxpacket = ~0; @@ -374,12 +374,12 @@ net2280_alloc_request (struct usb_ep *_e struct net2280_request *req; if (!_ep) - return 0; + return NULL; ep = container_of (_ep, struct net2280_ep, ep); req = kmalloc (sizeof *req, gfp_flags); if (!req) - return 0; + return NULL; memset (req, 0, sizeof *req); req->req.dma = DMA_ADDR_INVALID; @@ -393,7 +393,7 @@ net2280_alloc_request (struct usb_ep *_e &req->td_dma); if (!td) { kfree (req); - return 0; + return NULL; } td->dmacount = 0; /* not VALID */ td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID); @@ -463,7 +463,7 @@ net2280_alloc_buffer ( ep = container_of (_ep, struct net2280_ep, ep); if (!_ep) - return 0; + return NULL; *dma = DMA_ADDR_INVALID; #if defined(USE_KMALLOC) @@ -530,7 +530,7 @@ write_fifo (struct net2280_ep *ep, struc total = req->length - req->actual; } else { total = 0; - buf = 0; + buf = NULL; } /* write just one packet at a time */ @@ -966,7 +966,7 @@ net2280_queue (struct usb_ep *_ep, struc if (ep->num == 0) allow_status (ep); /* don't queue it */ - req = 0; + req = NULL; } else s = readl (&ep->regs->ep_stat); } @@ -1095,7 +1095,7 @@ static void restart_dma (struct net2280_ * OUT: was "usb-short", we must restart. */ if (ep->is_in && !req->valid) { - struct net2280_request *entry, *prev = 0; + struct net2280_request *entry, *prev = NULL; int reqmode, done = 0; DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); @@ -1220,7 +1220,7 @@ static int net2280_dequeue (struct usb_e DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name); done (ep, req, -ECONNRESET); } - req = 0; + req = NULL; /* patch up hardware chaining data */ } else if (ep->dma && use_dma_chaining) { @@ -1957,15 +1957,15 @@ int usb_gadget_register_driver (struct u dev->ep [i].irqs = 0; /* hook up the driver ... */ - driver->driver.bus = 0; + driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; retval = driver->bind (&dev->gadget); if (retval) { DEBUG (dev, "bind to driver %s --> %d\n", driver->driver.name, retval); - dev->driver = 0; - dev->gadget.dev.driver = 0; + dev->driver = NULL; + dev->gadget.dev.driver = NULL; return retval; } @@ -1995,7 +1995,7 @@ stop_activity (struct net2280 *dev, stru /* don't disconnect if it's not connected */ if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = 0; + driver = NULL; /* stop hardware; prevent new request submissions; * and kill any outstanding requests. @@ -2029,8 +2029,8 @@ int usb_gadget_unregister_driver (struct spin_unlock_irqrestore (&dev->lock, flags); driver->unbind (&dev->gadget); - dev->gadget.dev.driver = 0; - dev->driver = 0; + dev->gadget.dev.driver = NULL; + dev->driver = NULL; net2280_led_active (dev, 0); device_remove_file (&dev->pdev->dev, &dev_attr_function); @@ -2059,7 +2059,7 @@ static void handle_ep_small (struct net2 req = list_entry (ep->queue.next, struct net2280_request, queue); else - req = 0; + req = NULL; /* ack all, and handle what we care about */ t = readl (&ep->regs->ep_stat); @@ -2098,7 +2098,7 @@ static void handle_ep_small (struct net2 set_halt (ep); mode = 2; } else if (!req && ep->stopped) - write_fifo (ep, 0); + write_fifo (ep, NULL); } } else { /* status; stop NAKing */ @@ -2118,7 +2118,7 @@ static void handle_ep_small (struct net2 ep->stopped = 1; if (req) done (ep, req, -EOVERFLOW); - req = 0; + req = NULL; } } } @@ -2145,7 +2145,7 @@ static void handle_ep_small (struct net2 scan_dma_completions (ep); if (unlikely (list_empty (&ep->queue) || ep->out_overflow)) { - req = 0; + req = NULL; break; } req = list_entry (ep->queue.next, @@ -2159,7 +2159,7 @@ static void handle_ep_small (struct net2 count &= DMA_BYTE_COUNT_MASK; if (readl (&ep->dma->dmadesc) != req->td_dma) - req = 0; + req = NULL; break; } udelay(1); @@ -2212,7 +2212,7 @@ static void handle_ep_small (struct net2 if (ep->num == 0) { /* wait for control status */ if (mode != 2) - req = 0; + req = NULL; } else if (!req->req.zero || len != ep->ep.maxpacket) mode = 2; } @@ -2234,13 +2234,13 @@ static void handle_ep_small (struct net2 */ if (!ep->stopped) allow_status (ep); - req = 0; + req = NULL; } else { if (!list_empty (&ep->queue) && !ep->stopped) req = list_entry (ep->queue.next, struct net2280_request, queue); else - req = 0; + req = NULL; if (req && !ep->is_in) stop_out_naking (ep); } @@ -2275,7 +2275,7 @@ get_ep_by_addr (struct net2280 *dev, u16 if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) return ep; } - return 0; + return NULL; } static void handle_stat0_irqs (struct net2280 *dev, u32 stat) @@ -2707,11 +2707,11 @@ static void net2280_remove (struct pci_d pci_disable_device (pdev); device_unregister (&dev->gadget.dev); device_remove_file (&pdev->dev, &dev_attr_registers); - pci_set_drvdata (pdev, 0); + pci_set_drvdata (pdev, NULL); INFO (dev, "unbind\n"); - the_controller = 0; + the_controller = NULL; } /* wrap this driver around the specified device, but @@ -2722,7 +2722,7 @@ static int net2280_probe (struct pci_dev { struct net2280 *dev; unsigned long resource, len; - void *base = 0; + void *base = NULL; int retval, i; char buf [8], *bufp; --- linux-2.6.8-rc1/drivers/usb/gadget/serial.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/serial.c 2004-07-13 17:09:24.000000000 -0700 @@ -249,6 +249,20 @@ static const char EP_IN_NAME[] = "ep1in- #define hw_optimize(g) do {} while (0) #endif +#ifdef CONFIG_USB_GADGET_OMAP +#define CHIP "omap" +#define EP0_MAXPACKET 64 +static const char EP_OUT_NAME [] = "ep2out-bulk"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME [] = "ep1in-bulk"; +#define EP_IN_NUM 1 +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* supports remote wakeup, but this driver doesn't */ + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0) +#endif + /* * SA-1100 UDC: widely used in first gen Linux-capable PDAs. --- linux-2.6.8-rc1/drivers/usb/gadget/zero.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/gadget/zero.c 2004-07-13 17:09:24.000000000 -0700 @@ -194,8 +194,13 @@ module_param (loopdefault, bool, S_IRUGO * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ +#ifndef CONFIG_USB_ZERO_HNPTEST #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ +#else +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ +#define DRIVER_PRODUCT_NUM 0xbadd +#endif /*-------------------------------------------------------------------------*/ @@ -259,6 +264,14 @@ loopback_config = { .bMaxPower = 1, /* self-powered */ }; +static struct usb_otg_descriptor +otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + /* one interface in each configuration */ static const struct usb_interface_descriptor @@ -302,17 +315,19 @@ fs_sink_desc = { }; static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, - 0, + NULL, }; static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, - 0, + NULL, }; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -356,17 +371,19 @@ dev_qualifier = { }; static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; /* maxpacket and other transfer characteristics vary by speed. */ @@ -444,6 +461,10 @@ config_buf (struct usb_gadget *gadget, ? fs_source_sink_function : fs_loopback_function; + /* for now, don't advertise srp-only devices */ + if (!gadget->is_otg) + function++; + len = usb_gadget_config_buf (is_source_sink ? &source_sink_config : &loopback_config, @@ -468,7 +489,7 @@ alloc_ep_req (struct usb_ep *ep, unsigne &req->dma, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); - req = 0; + req = NULL; } } return req; @@ -485,7 +506,7 @@ static void free_ep_req (struct usb_ep * /* optionally require specific source/sink data patterns */ -static inline int +static int check_read_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -519,7 +540,7 @@ check_read_data ( return 0; } -static inline void +static void reinit_write_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -599,7 +620,7 @@ source_sink_start_ep (struct usb_ep *ep, req = alloc_ep_req (ep, buflen); if (!req) - return 0; + return NULL; memset (req->buf, 0, req->length); req->complete = source_sink_complete; @@ -613,7 +634,7 @@ source_sink_start_ep (struct usb_ep *ep, ERROR (dev, "start %s --> %d\n", ep->name, status); free_ep_req (ep, req); - req = 0; + req = NULL; } return req; @@ -804,13 +825,14 @@ static void zero_reset_config (struct ze */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); - dev->in_ep = 0; + dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); - dev->out_ep = 0; + dev->out_ep = NULL; } dev->config = 0; + del_timer (&dev->resume); } /* change our operational config. this code must agree with the code @@ -902,6 +924,7 @@ zero_setup (struct usb_gadget *gadget, c /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ + req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -951,6 +974,12 @@ zero_setup (struct usb_gadget *gadget, c case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unknown; + if (gadget->a_hnp_support) + DBG (dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DBG (dev, "HNP needs a different root port\n"); + else + VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); @@ -1080,8 +1109,10 @@ zero_autoresume (unsigned long _dev) /* normally the host would be woken up for something * more significant than just a timer firing... */ - status = usb_gadget_wakeup (dev->gadget); - DBG (dev, "wakeup --> %d\n", status); + if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + status = usb_gadget_wakeup (dev->gadget); + DBG (dev, "wakeup --> %d\n", status); + } } /*-------------------------------------------------------------------------*/ @@ -1098,7 +1129,7 @@ zero_unbind (struct usb_gadget *gadget) free_ep_req (gadget->ep0, dev->req); del_timer_sync (&dev->resume); kfree (dev); - set_gadget_data (gadget, 0); + set_gadget_data (gadget, NULL); } static int @@ -1199,6 +1230,12 @@ autoconf_fail: hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + usb_gadget_set_selfpowered (gadget); init_timer (&dev->resume); --- linux-2.6.8-rc1/drivers/usb/host/ehci-dbg.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/host/ehci-dbg.c 2004-07-13 17:09:13.000000000 -0700 @@ -536,7 +536,7 @@ show_periodic (struct class_device *clas if (p.qh->qh_next.ptr) temp = scnprintf (next, size, " ..."); - p.ptr = 0; + p.ptr = NULL; break; } /* show more info the first time around */ --- linux-2.6.8-rc1/drivers/usb/host/ehci-hub.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ehci-hub.c 2004-07-13 17:09:24.000000000 -0700 @@ -81,7 +81,7 @@ static int ehci_hub_suspend (struct usb_ } -/* caller owns root->serialize, and should reset/reinit on error */ +/* caller has locked the root hub, and should reset/reinit on error */ static int ehci_hub_resume (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); --- linux-2.6.8-rc1/drivers/usb/host/ehci-q.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ehci-q.c 2004-07-13 17:09:24.000000000 -0700 @@ -153,17 +153,9 @@ static void qtd_copy_status ( usb_pipein (urb->pipe) ? "in" : "out", token, urb->status); - /* stall indicates some recovery action is needed */ - if (urb->status == -EPIPE) { - int pipe = urb->pipe; - - if (!usb_pipecontrol (pipe)) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (pipe), - usb_pipeout (pipe)); - /* if async CSPLIT failed, try cleaning out the TT buffer */ - } else if (urb->dev->tt && !usb_pipeint (urb->pipe) + if (urb->status != -EPIPE + && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_ARC(ehci) --- linux-2.6.8-rc1/drivers/usb/host/ehci-sched.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ehci-sched.c 2004-07-13 17:09:13.000000000 -0700 @@ -1499,7 +1499,7 @@ sitd_urb_transaction ( list_del (&sitd->sitd_list); sitd_dma = sitd->sitd_dma; } else - sitd = 0; + sitd = NULL; if (!sitd) { spin_unlock_irqrestore (&ehci->lock, flags); @@ -1600,7 +1600,7 @@ sitd_link_urb ( hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs++; /* fill sITDs frame by frame */ - for (packet = 0, sitd = 0; + for (packet = 0, sitd = NULL; packet < urb->number_of_packets; packet++) { @@ -1626,7 +1626,7 @@ sitd_link_urb ( /* don't need that schedule data any more */ iso_sched_free (stream, sched); - urb->hcpriv = 0; + urb->hcpriv = NULL; timer_action (ehci, TIMER_IO_WATCHDOG); if (!ehci->periodic_sched++) @@ -1673,8 +1673,8 @@ sitd_complete ( } usb_put_urb (urb); - sitd->urb = 0; - sitd->stream = 0; + sitd->urb = NULL; + sitd->stream = NULL; list_move (&sitd->sitd_list, &stream->free_list); stream->depth -= stream->interval << 3; iso_stream_put (ehci, stream); @@ -1691,7 +1691,7 @@ sitd_complete ( /* give urb back to the driver */ dev = usb_get_dev (urb->dev); ehci_urb_done (ehci, urb, regs); - urb = 0; + urb = NULL; /* defer stopping schedule; completion can submit */ ehci->periodic_sched--; --- linux-2.6.8-rc1/drivers/usb/host/hc_simple.c 2003-06-14 12:18:52.000000000 -0700 +++ 25/drivers/usb/host/hc_simple.c 2004-07-13 17:09:24.000000000 -0700 @@ -146,11 +146,6 @@ static int hci_submit_urb (struct urb * if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL; - if (usb_endpoint_halted - (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) { - printk ("hci_submit_urb: endpoint_halted\n"); - return -EPIPE; - } hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ @@ -189,7 +184,7 @@ static int hci_submit_urb (struct urb * * * Return: 0 if success or error code **************************************************************************/ -static int hci_unlink_urb (struct urb * urb) +static int hci_unlink_urb (struct urb * urb, int status) { unsigned long flags; hci_t *hci; @@ -219,45 +214,21 @@ static int hci_unlink_urb (struct urb * if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) { /* URB active? */ - if (urb->transfer_flags & URB_ASYNC_UNLINK) { - /* asynchronous with callback */ - /* relink the urb to the del list */ - list_move (&urb->urb_list, &hci->del_list); - spin_unlock_irqrestore (&usb_urb_lock, flags); - } else { - /* synchronous without callback */ - - add_wait_queue (&hci->waitq, &wait); - - set_current_state (TASK_UNINTERRUPTIBLE); - comp = urb->complete; - urb->complete = NULL; - - /* relink the urb to the del list */ - list_move(&urb->urb_list, &hci->del_list); - - spin_unlock_irqrestore (&usb_urb_lock, flags); - - schedule_timeout (HZ / 50); - - if (!list_empty (&urb->urb_list)) - list_del (&urb->urb_list); - - urb->complete = comp; - urb->hcpriv = NULL; - remove_wait_queue (&hci->waitq, &wait); - } + /* asynchronous with callback */ + /* relink the urb to the del list */ + list_move (&urb->urb_list, &hci->del_list); + urb->status = status; + spin_unlock_irqrestore (&usb_urb_lock, flags); } else { /* hcd does not own URB but we keep the driver happy anyway */ spin_unlock_irqrestore (&usb_urb_lock, flags); - if (urb->complete && (urb->transfer_flags & URB_ASYNC_UNLINK)) { - urb->status = -ENOENT; + if (urb->complete) { + urb->status = status; urb->actual_length = 0; urb->complete (urb, NULL); - urb->status = 0; - } else { - urb->status = -ENOENT; + if (urb->reject) + wake_up (&usb_kill_urb_queue); } } --- linux-2.6.8-rc1/drivers/usb/host/ohci-dbg.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ohci-dbg.c 2004-07-13 17:09:13.000000000 -0700 @@ -266,11 +266,11 @@ static void ohci_dump (struct ohci_hcd * ohci_dbg (controller, "OHCI controller state\n"); // dumps some of the state we know about - ohci_dump_status (controller, NULL, 0); + ohci_dump_status (controller, NULL, NULL); if (controller->hcca) ohci_dbg (controller, "hcca frame #%04x\n", OHCI_FRAME_NO(controller->hcca)); - ohci_dump_roothub (controller, 1, NULL, 0); + ohci_dump_roothub (controller, 1, NULL, NULL); } static const char data0 [] = "DATA0"; @@ -574,7 +574,7 @@ show_periodic (struct class_device *clas } else { /* we've seen it and what's after */ temp = 0; - ed = 0; + ed = NULL; } } while (ed); --- linux-2.6.8-rc1/drivers/usb/host/ohci-hcd.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ohci-hcd.c 2004-07-13 17:09:24.000000000 -0700 @@ -229,7 +229,7 @@ static int ohci_urb_enqueue ( if (urb->status != -EINPROGRESS) { spin_unlock (&urb->lock); urb->hcpriv = urb_priv; - finish_urb (ohci, urb, 0); + finish_urb (ohci, urb, NULL); retval = 0; goto fail; } @@ -340,14 +340,18 @@ rescan: goto done; if (!HCD_IS_RUNNING (ohci->hcd.state)) { +sanitize: ed->state = ED_IDLE; - finish_unlinks (ohci, 0, 0); + finish_unlinks (ohci, 0, NULL); } switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ - WARN_ON (limit-- == 0); + if (limit-- == 0) { + ohci_warn (ohci, "IRQ INTR_SF lossage\n"); + goto sanitize; + } spin_unlock_irqrestore (&ohci->lock, flags); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (1); @@ -369,7 +373,7 @@ rescan: td_free (ohci, ed->dummy); break; } - dev->ep [epnum] = 0; + dev->ep [epnum] = NULL; done: spin_unlock_irqrestore (&ohci->lock, flags); return; @@ -671,6 +675,8 @@ static void ohci_stop (struct usb_hcd *h flush_scheduled_work(); if (HCD_IS_RUNNING(ohci->hcd.state)) hc_reset (ohci); + else + writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); ohci_mem_cleanup (ohci); @@ -728,7 +734,7 @@ static int hc_restart (struct ohci_hcd * ed_deschedule (ohci, ed); ed->ed_next = ohci->ed_rm_list; - ed->ed_prev = 0; + ed->ed_prev = NULL; ohci->ed_rm_list = ed; /* FALLTHROUGH */ case ED_UNLINK: @@ -742,7 +748,7 @@ static int hc_restart (struct ohci_hcd * urb->status = -ESHUTDOWN; spin_unlock (&urb->lock); } - finish_unlinks (ohci, 0, 0); + finish_unlinks (ohci, 0, NULL); spin_unlock_irq(&ohci->lock); /* paranoia, in case that didn't work: */ --- linux-2.6.8-rc1/drivers/usb/host/ohci-hub.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ohci-hub.c 2004-07-13 17:09:24.000000000 -0700 @@ -123,11 +123,11 @@ static int ohci_hub_suspend (struct usb_ if (ohci_readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) break; } - dl_done_list (ohci, 0); + dl_done_list (ohci, NULL); mdelay (7); } - dl_done_list (ohci, 0); - finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), 0); + dl_done_list (ohci, NULL); + finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), NULL); writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus); /* maybe resume can wake root hub */ @@ -165,7 +165,7 @@ static inline struct ed *find_head (stru static int hc_restart (struct ohci_hcd *ohci); -/* caller owns root->serialize */ +/* caller has locked the root hub */ static int ohci_hub_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -190,7 +190,7 @@ static int ohci_hub_resume (struct usb_h break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ - ohci_info (ohci, "remote wakeup\n"); + ohci_info (ohci, "wakeup\n"); break; case OHCI_USB_OPER: ohci_dbg (ohci, "odd resume\n"); @@ -301,9 +301,9 @@ static void ohci_rh_resume (void *_hcd) { struct usb_hcd *hcd = _hcd; - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); (void) ohci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); } #else @@ -381,12 +381,11 @@ ohci_hub_status_data (struct usb_hcd *hc && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) & ohci->hc_control) == OHCI_USB_OPER - && down_trylock (&hcd->self.root_hub->serialize) == 0 - ) { + && usb_trylock_device (hcd->self.root_hub)) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_hub_suspend (&ohci->hcd); ohci->hcd.state = USB_STATE_RUNNING; - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); } #endif @@ -515,7 +514,7 @@ static int ohci_hub_control ( #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ #endif - dbg_port (ohci, "GetStatus", wIndex + 1, temp); + dbg_port (ohci, "GetStatus", wIndex, temp); break; case SetHubFeature: switch (wValue) { --- linux-2.6.8-rc1/drivers/usb/host/ohci-mem.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/host/ohci-mem.c 2004-07-13 17:09:24.000000000 -0700 @@ -31,12 +31,13 @@ static struct usb_hcd *ohci_hcd_alloc (v if (ohci != 0) { memset (ohci, 0, sizeof (struct ohci_hcd)); ohci->hcd.product_desc = "OHCI Host Controller"; + ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); INIT_WORK (&ohci->rh_resume, ohci_rh_resume, &ohci->hcd); return &ohci->hcd; } - return 0; + return NULL; } static void ohci_hcd_free (struct usb_hcd *hcd) @@ -69,11 +70,11 @@ static void ohci_mem_cleanup (struct ohc { if (ohci->td_cache) { dma_pool_destroy (ohci->td_cache); - ohci->td_cache = 0; + ohci->td_cache = NULL; } if (ohci->ed_cache) { dma_pool_destroy (ohci->ed_cache); - ohci->ed_cache = 0; + ohci->ed_cache = NULL; } } --- linux-2.6.8-rc1/drivers/usb/host/ohci-omap.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ohci-omap.c 2004-07-13 17:09:13.000000000 -0700 @@ -17,7 +17,6 @@ */ #include -#include #include #include --- linux-2.6.8-rc1/drivers/usb/host/ohci-pci.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/host/ohci-pci.c 2004-07-13 17:09:24.000000000 -0700 @@ -127,9 +127,9 @@ static int ohci_pci_suspend (struct usb_ #ifdef CONFIG_USB_SUSPEND (void) usb_suspend_device (hcd->self.root_hub); #else - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); (void) ohci_hub_suspend (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); #endif /* let things settle down a bit */ @@ -175,9 +175,9 @@ static int ohci_pci_resume (struct usb_h /* get extra cleanup even if remote wakeup isn't in use */ retval = usb_resume_device (hcd->self.root_hub); #else - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); retval = ohci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); #endif if (retval == 0) { --- linux-2.6.8-rc1/drivers/usb/host/ohci-q.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/ohci-q.c 2004-07-13 17:09:24.000000000 -0700 @@ -174,8 +174,8 @@ static int ed_schedule (struct ohci_hcd return -EAGAIN; ed->state = ED_OPER; - ed->ed_prev = 0; - ed->ed_next = 0; + ed->ed_prev = NULL; + ed->ed_next = NULL; ed->hwNextED = 0; wmb (); @@ -333,7 +333,7 @@ static void ed_deschedule (struct ohci_h if (ohci->ed_controltail == ed) { ohci->ed_controltail = ed->ed_prev; if (ohci->ed_controltail) - ohci->ed_controltail->ed_next = 0; + ohci->ed_controltail->ed_next = NULL; } else if (ed->ed_next) { ed->ed_next->ed_prev = ed->ed_prev; } @@ -357,7 +357,7 @@ static void ed_deschedule (struct ohci_h if (ohci->ed_bulktail == ed) { ohci->ed_bulktail = ed->ed_prev; if (ohci->ed_bulktail) - ohci->ed_bulktail->ed_next = 0; + ohci->ed_bulktail->ed_next = NULL; } else if (ed->ed_next) { ed->ed_next->ed_prev = ed->ed_prev; } @@ -412,7 +412,7 @@ static struct ed *ed_get ( if (!td) { /* out of memory */ ed_free (ohci, ed); - ed = 0; + ed = NULL; goto done; } ed->dummy = td; @@ -474,7 +474,7 @@ static void start_ed_unlink (struct ohci /* rm_list is just singly linked, for simplicity */ ed->ed_next = ohci->ed_rm_list; - ed->ed_prev = 0; + ed->ed_prev = NULL; ohci->ed_rm_list = ed; /* enable SOF interrupt */ @@ -751,12 +751,6 @@ static void td_done (struct ohci_hcd *oh cc = TD_CC_GET (tdINFO); - /* control endpoints only have soft stalls */ - if (type != PIPE_CONTROL && cc == TD_CC_STALL) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) @@ -924,7 +918,7 @@ rescan_all: /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ - if (likely (HCD_IS_RUNNING(ohci->hcd.state))) { + if (likely (regs && HCD_IS_RUNNING(ohci->hcd.state))) { if (tick_before (tick, ed->tick)) { skip_ed: last = &ed->ed_next; @@ -950,7 +944,7 @@ skip_ed: * entries (which we'd ignore), but paranoia won't hurt. */ *last = ed->ed_next; - ed->ed_next = 0; + ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after --- linux-2.6.8-rc1/drivers/usb/host/uhci-hcd.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/host/uhci-hcd.c 2004-07-13 17:09:24.000000000 -0700 @@ -862,7 +862,7 @@ static int usb_control_retrigger_status( urbp->short_control_packet = 1; td = list_entry(urbp->td_list.prev, struct uhci_td, list); - urbp->qh->element = td->dma_handle; + urbp->qh->element = cpu_to_le32(td->dma_handle); return -EINPROGRESS; } @@ -1120,10 +1120,6 @@ static int uhci_result_common(struct uhc td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); - if (ret == -EPIPE) - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td))); err: /* --- linux-2.6.8-rc1/drivers/usb/image/mdc800.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/image/mdc800.c 2004-07-13 17:09:24.000000000 -0700 @@ -190,7 +190,7 @@ static struct usb_endpoint_descriptor md /* The Variable used by the driver */ -static struct mdc800_data* mdc800=0; +static struct mdc800_data* mdc800; /*************************************************************************** @@ -547,7 +547,7 @@ static void mdc800_usb_disconnect (struc usb_unlink_urb (mdc800->write_urb); usb_unlink_urb (mdc800->download_urb); - mdc800->dev=0; + mdc800->dev=NULL; usb_set_intfdata(intf, NULL); } info ("Mustek MDC800 disconnected from USB."); @@ -971,9 +971,9 @@ static struct usb_driver mdc800_usb_driv Init and Cleanup this driver (Main Functions) *************************************************************************/ -#define try(A) if ((A) == 0) goto cleanup_on_fail; -#define try_free_mem(A) if (A != 0) { kfree (A); A=0; } -#define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; } +#define try(A) if (!(A)) goto cleanup_on_fail; +#define try_free_mem(A) if (A) { kfree (A); A=NULL; } +#define try_free_urb(A) if (A) { usb_free_urb (A); A=NULL; } static int __init usb_mdc800_init (void) { @@ -982,7 +982,7 @@ static int __init usb_mdc800_init (void) try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL)); memset(mdc800, 0, sizeof(struct mdc800_data)); - mdc800->dev=0; + mdc800->dev=NULL; mdc800->open=0; mdc800->state=NOT_CONNECTED; init_MUTEX (&mdc800->io_lock); @@ -1020,17 +1020,17 @@ cleanup_on_fail: { err ("can't alloc memory!"); - try_free_mem (mdc800->download_urb_buffer); - try_free_mem (mdc800->write_urb_buffer); - try_free_mem (mdc800->irq_urb_buffer); - - try_free_urb (mdc800->write_urb); - try_free_urb (mdc800->download_urb); - try_free_urb (mdc800->irq_urb); + kfree(mdc800->download_urb_buffer); + kfree(mdc800->write_urb_buffer); + kfree(mdc800->irq_urb_buffer); + + usb_free_urb(mdc800->write_urb); + usb_free_urb(mdc800->download_urb); + usb_free_urb(mdc800->irq_urb); kfree (mdc800); } - mdc800=0; + mdc800 = NULL; return retval; } @@ -1048,7 +1048,7 @@ static void __exit usb_mdc800_cleanup (v kfree (mdc800->download_urb_buffer); kfree (mdc800); - mdc800=0; + mdc800 = NULL; } module_init (usb_mdc800_init); --- linux-2.6.8-rc1/drivers/usb/image/microtek.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/image/microtek.c 2004-07-13 17:09:24.000000000 -0700 @@ -214,8 +214,8 @@ static struct usb_driver mts_usb_driver #ifdef MTS_DO_DEBUG static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n", - (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n", + (int)desc, (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] ); MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", @@ -341,12 +341,18 @@ static int mts_scsi_abort (Scsi_Cmnd *sr static int mts_scsi_host_reset (Scsi_Cmnd *srb) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); + int result, rc; MTS_DEBUG_GOT_HERE(); mts_debug_dump(desc); - usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */ - return 0; /* RANT why here 0 and not SUCCESS */ + rc = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf); + if (rc < 0) + return FAILED; + result = usb_reset_device(desc->usb_dev);; + if (rc) + usb_unlock_device(desc->usb_dev); + return result ? FAILED : SUCCESS; } static @@ -534,7 +540,7 @@ mts_build_transfer_context( Scsi_Cmnd *s if (!srb->use_sg) { if ( !srb->bufflen ){ - desc->context.data = 0; + desc->context.data = NULL; desc->context.data_length = 0; return; } else { @@ -777,6 +783,7 @@ static int mts_usb_probe(struct usb_inte goto out_kfree; new_desc->usb_dev = dev; + new_desc->usb_intf = intf; init_MUTEX(&new_desc->lock); /* endpoints */ --- linux-2.6.8-rc1/drivers/usb/image/microtek.h 2003-06-14 12:18:01.000000000 -0700 +++ 25/drivers/usb/image/microtek.h 2004-07-13 17:09:24.000000000 -0700 @@ -31,6 +31,7 @@ struct mts_desc { struct mts_desc *prev; struct usb_device *usb_dev; + struct usb_interface *usb_intf; /* Endpoint addresses */ u8 ep_out; --- linux-2.6.8-rc1/drivers/usb/input/aiptek.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/input/aiptek.c 2004-07-13 17:09:13.000000000 -0700 @@ -1324,7 +1324,7 @@ store_tabletXtilt(struct device *dev, co if (strcmp(buf, "disable") == 0) { aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE; } else { - x = (int)simple_strtol(buf, 0, 10); + x = (int)simple_strtol(buf, NULL, 10); if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) { aiptek->newSetting.xTilt = x; } @@ -1366,7 +1366,7 @@ store_tabletYtilt(struct device *dev, co if (strcmp(buf, "disable") == 0) { aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE; } else { - y = (int)simple_strtol(buf, 0, 10); + y = (int)simple_strtol(buf, NULL, 10); if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) { aiptek->newSetting.yTilt = y; } @@ -1399,7 +1399,7 @@ store_tabletJitterDelay(struct device *d if (aiptek == NULL) return 0; - aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, 0, 10); + aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10); return count; } @@ -1430,7 +1430,7 @@ store_tabletProgrammableDelay(struct dev if (aiptek == NULL) return 0; - aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, 0, 10); + aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10); return count; } @@ -1805,7 +1805,7 @@ store_tabletWheel(struct device *dev, co if (aiptek == NULL) return 0; - aiptek->newSetting.wheel = (int)simple_strtol(buf, 0, 10); + aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); return count; } --- linux-2.6.8-rc1/drivers/usb/input/hid-core.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/input/hid-core.c 2004-07-13 17:09:24.000000000 -0700 @@ -807,7 +807,11 @@ static void hid_input_field(struct hid_d unsigned size = field->report_size; __s32 min = field->logical_minimum; __s32 max = field->logical_maximum; - __s32 value[count]; /* WARNING: gcc specific */ + __s32 *value; + + value = kmalloc(sizeof(__s32)*count, GFP_ATOMIC); + if (!value) + return; for (n = 0; n < count; n++) { @@ -817,7 +821,7 @@ static void hid_input_field(struct hid_d if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ && value[n] >= min && value[n] <= max && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - return; + goto exit; } for (n = 0; n < count; n++) { @@ -847,6 +851,8 @@ static void hid_input_field(struct hid_d } memcpy(field->value, value, count * sizeof(__s32)); +exit: + kfree(value); } static int hid_input_report(int type, struct urb *urb, struct pt_regs *regs) @@ -1425,11 +1431,19 @@ void hid_init_reports(struct hid_device #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 +#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 +#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 +#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 +#define USB_VENDOR_ID_CODEMERCS 0x07c0 +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 + + static struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1444,20 +1458,20 @@ static struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, @@ -1483,8 +1497,13 @@ static struct hid_blacklist { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, --- linux-2.6.8-rc1/drivers/usb/input/hiddev.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/input/hiddev.c 2004-07-13 17:09:22.000000000 -0700 @@ -223,16 +223,6 @@ static int hiddev_fasync(int fd, struct return retval < 0 ? retval : 0; } -/* - * De-allocate a hiddev structure - */ -static struct usb_class_driver hiddev_class; -static void hiddev_cleanup(struct hiddev *hiddev) -{ - hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); - kfree(hiddev); -} /* * release file op @@ -253,7 +243,7 @@ static int hiddev_release(struct inode * if (list->hiddev->exist) hid_close(list->hiddev->hid); else - hiddev_cleanup(list->hiddev); + kfree(list->hiddev); } kfree(list); @@ -636,16 +626,22 @@ static int hiddev_ioctl(struct inode *in goto inval; field = report->field[uref->field_index]; - if (uref->usage_index >= field->maxusage) - goto inval; - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi->num_values >= HID_MAX_USAGES || - uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi->num_values) >= field->maxusage) + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; + + else if ((cmd == HIDIOCGUSAGES || + cmd == HIDIOCSUSAGES) && + (uref->usage_index + uref_multi->num_values >= + field->report_count || + uref->usage_index + uref_multi->num_values < + uref->usage_index)) + goto inval; + } - } switch (cmd) { case HIDIOCGUSAGE: @@ -795,17 +791,21 @@ int hiddev_connect(struct hid_device *hi * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */ +static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; hiddev->exist = 0; + hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; + usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + if (hiddev->open) { hid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { - hiddev_cleanup(hiddev); + kfree(hiddev); } } --- linux-2.6.8-rc1/drivers/usb/input/powermate.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/input/powermate.c 2004-07-13 17:09:13.000000000 -0700 @@ -182,7 +182,7 @@ static void powermate_sync_state(struct pm->configcr->wLength = 0; usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), - (void *) pm->configcr, 0, 0, + (void *) pm->configcr, NULL, 0, powermate_config_complete, pm); pm->config->setup_dma = pm->configcr_dma; pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP; --- linux-2.6.8-rc1/drivers/usb/media/dabusb.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/dabusb.c 2004-07-13 17:09:53.000000000 -0700 @@ -61,7 +61,7 @@ static dabusb_t dabusb[NRDABUSB]; static int buffers = 256; -extern struct usb_driver dabusb_driver; +static struct usb_driver dabusb_driver; /*-------------------------------------------------------------------*/ --- linux-2.6.8-rc1/drivers/usb/media/Kconfig 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/media/Kconfig 2004-07-13 17:09:24.000000000 -0700 @@ -162,6 +162,21 @@ config USB_SE401 To compile this driver as a module, choose M here: the module will be called se401. +config USB_SN9C102 + tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)" + depends on USB && VIDEO_DEV && EXPERIMENTAL + ---help--- + Say Y here if you want support for cameras based on SN9C101 and + SN9C102 PC Camera Controllers. + + See for more informations. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as a module, choose M here: the + module will be called sn9c102. + config USB_STV680 tristate "USB STV680 (Pencam) Camera support" depends on USB && VIDEO_DEV @@ -181,7 +196,7 @@ config USB_STV680 config USB_W9968CF tristate "USB W996[87]CF JPEG Dual Mode Camera support" - depends on USB && VIDEO_DEV && I2C + depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP ---help--- Say Y here if you want support for cameras based on OV681 or Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. @@ -190,16 +205,13 @@ config USB_W9968CF separate module only (released under GPL). It allows to use higher resolutions and framerates, but cannot be included in the official Linux kernel for performance purposes. - At the moment the driver needs a third-party module for the CMOS - sensors, which is available on internet: it is recommended to read - for more informations and for - a list of supported cameras. - - This driver uses the Video For Linux and the I2C APIs. You must say - Y or M to both "Video For Linux" and "I2C Support" to use this - driver. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called w9968cf.o. If you want to compile it as a - module, say M here and read . + + See for more informations. + + This driver uses the Video For Linux and the I2C APIs. It needs the + OmniVision Camera Chip support as well. You must say Y or M to + "Video For Linux", "I2C Support" and "OmniVision Camera Chip + support" to use this driver. + + To compile this driver as a module, choose M here: the + module will be called w9968cf. --- linux-2.6.8-rc1/drivers/usb/media/Makefile 2004-01-09 00:04:32.000000000 -0800 +++ 25/drivers/usb/media/Makefile 2004-07-13 17:09:24.000000000 -0700 @@ -3,6 +3,7 @@ # pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o +sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o @@ -11,6 +12,7 @@ obj-$(CONFIG_USB_KONICAWC) += konicawc.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o +obj-$(CONFIG_USB_SN9C102) += sn9c102.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o --- linux-2.6.8-rc1/drivers/usb/media/ov511.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/ov511.c 2004-07-13 17:09:13.000000000 -0700 @@ -1900,7 +1900,7 @@ sensor_get_exposure(struct usb_ov511 *ov case SEN_KS0127: case SEN_KS0127B: case SEN_SAA7111A: - val = 0; + val = NULL; PDEBUG(3, "Unsupported with this sensor"); return -EPERM; default: --- linux-2.6.8-rc1/drivers/usb/media/pwc-ctrl.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/pwc-ctrl.c 2004-07-13 17:09:13.000000000 -0700 @@ -359,7 +359,7 @@ static inline int set_video_mode_Timon(s static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) { - struct Kiara_table_entry *pChoose = 0; + struct Kiara_table_entry *pChoose = NULL; int fps, ret; unsigned char buf[12]; struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; --- linux-2.6.8-rc1/drivers/usb/media/pwc-if.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/pwc-if.c 2004-07-13 17:09:13.000000000 -0700 @@ -593,7 +593,7 @@ static void pwc_isoc_handler(struct urb int i, fst, flen; int awake; struct pwc_frame_buf *fbuf; - unsigned char *fillptr = 0, *iso_buf = 0; + unsigned char *fillptr = NULL, *iso_buf = NULL; awake = 0; pdev = (struct pwc_device *)urb->context; --- linux-2.6.8-rc1/drivers/usb/media/se401.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/se401.c 2004-07-13 17:09:24.000000000 -0700 @@ -1295,7 +1295,7 @@ static int se401_init(struct usb_se401 * &se401->button, sizeof(se401->button), se401_button_irq, se401, - HZ/10 + 8 ); if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { info("int urb burned down"); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102_core.c 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,2439 @@ +/*************************************************************************** + * V4L2 driver for SN9C10[12] PC Camera Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sn9c102.h" + +/*****************************************************************************/ + +MODULE_DEVICE_TABLE(usb, sn9c102_id_table); + +MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); +MODULE_DESCRIPTION(SN9C102_MODULE_NAME); +MODULE_VERSION(SN9C102_MODULE_VERSION); +MODULE_LICENSE(SN9C102_MODULE_LICENSE); + +static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; +static unsigned int nv; +module_param_array(video_nr, short, nv, 0444); +MODULE_PARM_DESC(video_nr, + "\n<-1|n[,...]> Specify V4L2 minor mode number." + "\n -1 = use next available (default)" + "\n n = use minor number n (integer >= 0)" + "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) + " cameras this way." + "\nFor example:" + "\nvideo_nr=-1,2,-1 would assign minor number 2 to" + "\nthe second camera and use auto for the first" + "\none and for every other camera." + "\n"); + +#ifdef SN9C102_DEBUG +static unsigned short debug = SN9C102_DEBUG_LEVEL; +module_param(debug, ushort, 0644); +MODULE_PARM_DESC(debug, + "\n Debugging information level, from 0 to 3:" + "\n0 = none (use carefully)" + "\n1 = critical errors" + "\n2 = significant informations" + "\n3 = more verbose messages" + "\nLevel 3 is useful for testing only, when only " + "one device is used." + "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." + "\n"); +#endif + +/*****************************************************************************/ + +typedef char sn9c102_sof_header_t[7]; +typedef char sn9c102_eof_header_t[4]; + +static sn9c102_sof_header_t sn9c102_sof_header[] = { + {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00}, + {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, +}; + +/* Number of random bytes that complete the SOF above headers */ +#define SN9C102_SOFLEN 5 + +static sn9c102_eof_header_t sn9c102_eof_header[] = { + {0x00, 0x00, 0x00, 0x00}, + {0x40, 0x00, 0x00, 0x00}, + {0x80, 0x00, 0x00, 0x00}, + {0xc0, 0x00, 0x00, 0x00}, +}; + +/*****************************************************************************/ + +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); + ret = __pa(kva); + return ret; +} + + +static void* rvmalloc(size_t size) +{ + void* mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + + mem = vmalloc_32((unsigned long)size); + if (!mem) + return NULL; + + memset(mem, 0, size); + + adr = (unsigned long)mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + + +static void rvfree(void* mem, size_t size) +{ + unsigned long adr; + + if (!mem) + return; + + size = PAGE_ALIGN(size); + + adr = (unsigned long)mem; + while (size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vfree(mem); +} + + +static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count) +{ + struct v4l2_pix_format* p = &(cam->sensor->pix_format); + const size_t imagesize = (p->width * p->height * p->priv)/8; + void* buff = NULL; + u32 i; + + if (count > SN9C102_MAX_FRAMES) + count = SN9C102_MAX_FRAMES; + + cam->nbuffers = count; + while (cam->nbuffers > 0) { + if ((buff = rvmalloc(cam->nbuffers * imagesize))) + break; + cam->nbuffers--; + } + + for (i = 0; i < cam->nbuffers; i++) { + cam->frame[i].bufmem = buff + i*imagesize; + cam->frame[i].buf.index = i; + cam->frame[i].buf.m.offset = i*imagesize; + cam->frame[i].buf.length = imagesize; + cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->frame[i].buf.sequence = 0; + cam->frame[i].buf.field = V4L2_FIELD_NONE; + cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; + cam->frame[i].buf.flags = 0; + } + + return cam->nbuffers; +} + + +static void sn9c102_release_buffers(struct sn9c102_device* cam) +{ + if (cam->nbuffers) { + rvfree(cam->frame[0].bufmem, + cam->nbuffers * cam->frame[0].buf.length); + cam->nbuffers = 0; + } +} + + +static void sn9c102_empty_framequeues(struct sn9c102_device* cam) +{ + u32 i; + + INIT_LIST_HEAD(&cam->inqueue); + INIT_LIST_HEAD(&cam->outqueue); + + for (i = 0; i < SN9C102_MAX_FRAMES; i++) { + cam->frame[i].state = F_UNUSED; + cam->frame[i].buf.bytesused = 0; + } +} + + +static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) +{ + unsigned long lock_flags; + u32 i; + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].state == F_UNUSED) { + cam->frame[i].state = F_QUEUED; + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[i].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + } +} + +/*****************************************************************************/ + +int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) +{ + struct usb_device* udev = cam->usbdev; + u8* buff = cam->control_buffer; + int res; + + if (index == 0x18) + value = (value & 0xcf) | (cam->reg[0x18] & 0x30); + + *buff = value; + + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, + index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); + if (res < 0) { + DBG(3, "Failed to write a register (value 0x%02X, index " + "0x%02X, error %d)", value, index, res) + return -1; + } + + cam->reg[index] = value; + + return 0; +} + + +/* NOTE: reading some registers always returns 0 */ +static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) +{ + struct usb_device* udev = cam->usbdev; + u8* buff = cam->control_buffer; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); + if (res < 0) + DBG(3, "Failed to read a register (index 0x%02X, error %d)", + index, res) + + return (res >= 0) ? (int)(*buff) : -1; +} + + +int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) +{ + if (index > 0x1f) + return -EINVAL; + + return cam->reg[index]; +} + + +static int +sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) +{ + int i, r; + + for (i = 1; i <= 5; i++) { + r = sn9c102_read_reg(cam, 0x08); + if (r < 0) + return -EIO; + if (r & 0x04) + return 0; + if (sensor->frequency & SN9C102_I2C_400KHZ) + udelay(5*8); + else + udelay(16*8); + } + return -EBUSY; +} + + +static int +sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor) +{ + int r; + r = sn9c102_read_reg(cam, 0x08); + return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; +} + + +static int +sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor) +{ + int r; + r = sn9c102_read_reg(cam, 0x08); + return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; +} + + +int +sn9c102_i2c_try_read(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor, u8 address) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + /* Write cycle - address */ + data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | + ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; + data[1] = sensor->slave_write_id; + data[2] = address; + data[7] = 0x10; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, + 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += sn9c102_i2c_wait(cam, sensor); + + /* Read cycle - 1 byte */ + data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | + ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | + 0x10 | 0x02; + data[1] = sensor->slave_read_id; + data[7] = 0x10; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, + 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += sn9c102_i2c_wait(cam, sensor); + + /* The read byte will be placed in data[4] */ + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += sn9c102_i2c_detect_read_error(cam, sensor); + + if (err) + DBG(3, "I2C read failed for %s image sensor", sensor->name) + + PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[4]) + + return err ? -1 : (int)data[4]; +} + + +int +sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor, u8 n, u8 data0, + u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + /* Write cycle. It usually is address + value */ + data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | + ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) + | ((n - 1) << 4); + data[1] = data0; + data[2] = data1; + data[3] = data2; + data[4] = data3; + data[5] = data4; + data[6] = data5; + data[7] = 0x10; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, + 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += sn9c102_i2c_wait(cam, sensor); + err += sn9c102_i2c_detect_write_error(cam, sensor); + + if (err) + DBG(3, "I2C write failed for %s image sensor", sensor->name) + + PDBGG("I2C write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " + "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", + n, data0, data1, data2, data3, data4, data5) + + return err ? -1 : 0; +} + + +int +sn9c102_i2c_try_write(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor, u8 address, u8 value) +{ + return sn9c102_i2c_try_raw_write(cam, sensor, 3, + sensor->slave_write_id, address, + value, 0, 0, 0); +} + + +int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) +{ + if (!cam->sensor) + return -1; + + return sn9c102_i2c_try_read(cam, cam->sensor, address); +} + + +int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) +{ + if (!cam->sensor) + return -1; + + return sn9c102_i2c_try_write(cam, cam->sensor, address, value); +} + +/*****************************************************************************/ + +static void* sn9c102_find_sof_header(void* mem, size_t len) +{ + size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i; + u8 j, n = sizeof(sn9c102_sof_header) / soflen; + + for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++) + for (j = 0; j < n; j++) + if (!memcmp(mem + i, sn9c102_sof_header[j], soflen)) + /* Skips the header */ + return mem + i + soflen + SOFLEN; + + return NULL; +} + + +static void* sn9c102_find_eof_header(void* mem, size_t len) +{ + size_t eoflen = sizeof(sn9c102_eof_header_t), i; + unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; + + for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) + for (j = 0; j < n; j++) + if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) + return mem + i; + + return NULL; +} + + +static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) +{ + struct sn9c102_device* cam = urb->context; + struct sn9c102_frame_t** f; + unsigned long lock_flags; + u8 i; + int err = 0; + + if (urb->status == -ENOENT) + return; + + f = &cam->frame_current; + + if (cam->stream == STREAM_INTERRUPT) { + cam->stream = STREAM_OFF; + if ((*f)) + (*f)->state = F_QUEUED; + DBG(3, "Stream interrupted") + wake_up_interruptible(&cam->wait_stream); + } + + if ((cam->state & DEV_DISCONNECTED)||(cam->state & DEV_MISCONFIGURED)) + return; + + if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) + goto resubmit_urb; + + if (!(*f)) + (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, + frame); + + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int img, len, status; + void *pos, *sof, *eof; + + len = urb->iso_frame_desc[i].actual_length; + status = urb->iso_frame_desc[i].status; + pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; + + if (status) { + DBG(3, "Error in isochronous frame") + (*f)->state = F_ERROR; + continue; + } + + PDBGG("Isochrnous frame: length %u, #%u i", len, i) + + /* NOTE: It is probably correct to assume that SOF and EOF + headers do not occur between two consecutive packets, + but who knows..Whatever is the truth, this assumption + doesn't introduce bugs. */ + +redo: + sof = sn9c102_find_sof_header(pos, len); + if (!sof) { + eof = sn9c102_find_eof_header(pos, len); + if ((*f)->state == F_GRABBING) { +end_of_frame: + img = len; + + if (eof) + img = (eof > pos) ? eof - pos - 1 : 0; + + if ((*f)->buf.bytesused+img>(*f)->buf.length) { + u32 b = (*f)->buf.bytesused + img - + (*f)->buf.length; + img = (*f)->buf.length - + (*f)->buf.bytesused; + DBG(3, "Expected EOF not found: " + "video frame cut") + if (eof) + DBG(3, "Exceeded limit: +%u " + "bytes", (unsigned)(b)) + } + + memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, + img); + + if ((*f)->buf.bytesused == 0) + do_gettimeofday(&(*f)->buf.timestamp); + + (*f)->buf.bytesused += img; + + if ((*f)->buf.bytesused == (*f)->buf.length) { + u32 b = (*f)->buf.bytesused; + (*f)->state = F_DONE; + (*f)->buf.sequence= ++cam->frame_count; + spin_lock_irqsave(&cam->queue_lock, + lock_flags); + list_move_tail(&(*f)->frame, + &cam->outqueue); + if (!list_empty(&cam->inqueue)) + (*f) = list_entry( + cam->inqueue.next, + struct sn9c102_frame_t, + frame ); + else + (*f) = NULL; + spin_unlock_irqrestore(&cam->queue_lock + , lock_flags); + DBG(3, "Video frame captured: " + "%lu bytes", (unsigned long)(b)) + + if (!(*f)) + goto resubmit_urb; + + } else if (eof) { + (*f)->state = F_ERROR; + DBG(3, "Not expected EOF after %lu " + "bytes of image data", + (unsigned long)((*f)->buf.bytesused)) + } + + if (sof) /* (1) */ + goto start_of_frame; + + } else if (eof) { + DBG(3, "EOF without SOF") + continue; + + } else { + PDBGG("Ignoring pointless isochronous frame") + continue; + } + + } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { +start_of_frame: + (*f)->state = F_GRABBING; + (*f)->buf.bytesused = 0; + len -= (sof - pos); + pos = sof; + DBG(3, "SOF detected: new video frame") + if (len) + goto redo; + + } else if ((*f)->state == F_GRABBING) { + eof = sn9c102_find_eof_header(pos, len); + if (eof && eof < sof) + goto end_of_frame; /* (1) */ + else { + DBG(3, "SOF before expected EOF after %lu " + "bytes of image data", + (unsigned long)((*f)->buf.bytesused)) + goto start_of_frame; + } + } + } + +resubmit_urb: + urb->dev = cam->usbdev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0 && err != -EPERM) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "usb_submit_urb() failed") + } + + wake_up_interruptible(&cam->wait_frame); +} + + +static int sn9c102_start_transfer(struct sn9c102_device* cam) +{ + struct usb_device *udev = cam->usbdev; + struct urb* urb; + const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512, + 680, 800, 900, 1023}; + const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; + s8 i, j; + int err = 0; + + for (i = 0; i < SN9C102_URBS; i++) { + cam->transfer_buffer[i] = kmalloc(SN9C102_ISO_PACKETS * psz, + GFP_KERNEL); + if (!cam->transfer_buffer[i]) { + err = -ENOMEM; + DBG(1, "Not enough memory") + goto free_buffers; + } + } + + for (i = 0; i < SN9C102_URBS; i++) { + urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); + cam->urb[i] = urb; + if (!urb) { + err = -ENOMEM; + DBG(1, "usb_alloc_urb() failed") + goto free_urbs; + } + urb->dev = udev; + urb->context = cam; + urb->pipe = usb_rcvisocpipe(udev, 1); + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = SN9C102_ISO_PACKETS; + urb->complete = sn9c102_urb_complete; + urb->transfer_buffer = cam->transfer_buffer[i]; + urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; + urb->interval = 1; + for (j = 0; j < SN9C102_ISO_PACKETS; j++) { + urb->iso_frame_desc[j].offset = psz * j; + urb->iso_frame_desc[j].length = psz; + } + } + + /* Enable video */ + if (!(cam->reg[0x01] & 0x04)) { + err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); + if (err) { + err = -EIO; + DBG(1, "I/O hardware error") + goto free_urbs; + } + } + + err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); + if (err) { + DBG(1, "usb_set_interface() failed") + goto free_urbs; + } + + cam->frame_current = NULL; + + for (i = 0; i < SN9C102_URBS; i++) { + err = usb_submit_urb(cam->urb[i], GFP_KERNEL); + if (err) { + for (j = i-1; j >= 0; j--) + usb_kill_urb(cam->urb[j]); + DBG(1, "usb_submit_urb() failed, error %d", err) + goto free_urbs; + } + } + + return 0; + +free_urbs: + for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) + usb_free_urb(cam->urb[i]); + +free_buffers: + for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) + kfree(cam->transfer_buffer[i]); + + return err; +} + + +static int sn9c102_stop_transfer(struct sn9c102_device* cam) +{ + struct usb_device *udev = cam->usbdev; + s8 i; + int err = 0; + + if (cam->state & DEV_DISCONNECTED) + return 0; + + for (i = SN9C102_URBS-1; i >= 0; i--) { + usb_kill_urb(cam->urb[i]); + usb_free_urb(cam->urb[i]); + kfree(cam->transfer_buffer[i]); + } + + err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ + if (err) + DBG(3, "usb_set_interface() failed") + + return err; +} + +/*****************************************************************************/ + +static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) +{ + char str[5]; + char* endp; + unsigned long val; + + if (len < 4) { + strncpy(str, buff, len); + str[len+1] = '\0'; + } else { + strncpy(str, buff, 4); + str[4] = '\0'; + } + + val = simple_strtoul(str, &endp, 0); + + *count = 0; + if (val <= 0xff) + *count = (ssize_t)(endp - str); + if ((*count) && (len == *count+1) && (buff[*count] == '\n')) + *count += 1; + + return (u8)val; +} + +/* NOTE 1: being inside one of the following methods implies that the v4l + device exists for sure (see kobjects and reference counters) + NOTE 2: buffers are PAGE_SIZE long */ + +static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) +{ + struct sn9c102_device* cam; + ssize_t count; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + count = sprintf(buf, "%u\n", cam->sysfs.reg); + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t +sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) +{ + struct sn9c102_device* cam; + u8 index; + ssize_t count; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + index = sn9c102_strtou8(buf, len, &count); + if (index > 0x1f || !count) { + up(&sn9c102_sysfs_lock); + return -EINVAL; + } + + cam->sysfs.reg = index; + + DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg) + DBG(3, "Written bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) +{ + struct sn9c102_device* cam; + ssize_t count; + int val; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { + up(&sn9c102_sysfs_lock); + return -EIO; + } + + count = sprintf(buf, "%d\n", val); + + DBG(3, "Read bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t +sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) +{ + struct sn9c102_device* cam; + u8 value; + ssize_t count; + int err; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + value = sn9c102_strtou8(buf, len, &count); + if (!count) { + up(&sn9c102_sysfs_lock); + return -EINVAL; + } + + err = sn9c102_write_reg(cam, value, cam->sysfs.reg); + if (err) { + up(&sn9c102_sysfs_lock); + return -EIO; + } + + DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", + cam->sysfs.reg, value) + DBG(3, "Written bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) +{ + struct sn9c102_device* cam; + ssize_t count; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); + + DBG(3, "Read bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t +sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) +{ + struct sn9c102_device* cam; + u8 index; + ssize_t count; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + index = sn9c102_strtou8(buf, len, &count); + if (!count) { + up(&sn9c102_sysfs_lock); + return -EINVAL; + } + + cam->sysfs.i2c_reg = index; + + DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg) + DBG(3, "Written bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) +{ + struct sn9c102_device* cam; + ssize_t count; + int val; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { + up(&sn9c102_sysfs_lock); + return -EIO; + } + + count = sprintf(buf, "%d\n", val); + + DBG(3, "Read bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t +sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) +{ + struct sn9c102_device* cam; + u8 value; + ssize_t count; + int err; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + value = sn9c102_strtou8(buf, len, &count); + if (!count) { + up(&sn9c102_sysfs_lock); + return -EINVAL; + } + + err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); + if (err) { + up(&sn9c102_sysfs_lock); + return -EIO; + } + + DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", + cam->sysfs.i2c_reg, value) + DBG(3, "Written bytes: %zd", count) + + up(&sn9c102_sysfs_lock); + + return count; +} + + +static ssize_t +sn9c102_store_redblue(struct class_device* cd, const char* buf, size_t len) +{ + ssize_t res = 0; + u8 value; + ssize_t count; + + value = sn9c102_strtou8(buf, len, &count); + if (!count) + return -EINVAL; + + if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0) + res = sn9c102_store_val(cd, buf, len); + + return res; +} + + +static ssize_t +sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) +{ + ssize_t res = 0; + u8 value; + ssize_t count; + + value = sn9c102_strtou8(buf, len, &count); + if (!count || value > 0x0f) + return -EINVAL; + + if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, buf, len); + + return res; +} + + +static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, + sn9c102_show_reg, sn9c102_store_reg); +static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, + sn9c102_show_val, sn9c102_store_val); +static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); +static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, + sn9c102_show_i2c_val, sn9c102_store_i2c_val); +static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue); +static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); + + +static void sn9c102_create_sysfs(struct sn9c102_device* cam) +{ + struct video_device *v4ldev = cam->v4ldev; + + video_device_create_file(v4ldev, &class_device_attr_reg); + video_device_create_file(v4ldev, &class_device_attr_val); + video_device_create_file(v4ldev, &class_device_attr_redblue); + video_device_create_file(v4ldev, &class_device_attr_green); + if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { + video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + video_device_create_file(v4ldev, &class_device_attr_i2c_val); + } +} + +/*****************************************************************************/ + +static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) +{ + u8 r = 0; + int err = 0; + + if (scale == 1) + r = cam->reg[0x18] & 0xcf; + else if (scale == 2) { + r = cam->reg[0x18] & 0xcf; + r |= 0x10; + } else if (scale == 4) + r = cam->reg[0x18] | 0x20; + + err += sn9c102_write_reg(cam, r, 0x18); + if (err) + return -EIO; + + PDBGG("Scaling factor: %u", scale) + + return 0; +} + + +static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = cam->sensor; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), + v_start = (u8)(rect->top - s->cropcap.bounds.top), + h_size = (u8)(rect->width / 16), + v_size = (u8)(rect->height / 16), + ae_strx = 0x00, + ae_stry = 0x00, + ae_endx = h_size / 2, + ae_endy = v_size / 2; + int err = 0; + + /* These are a sort of stroboscopic signal for some sensors */ + err += sn9c102_write_reg(cam, h_size, 0x1a); + err += sn9c102_write_reg(cam, v_size, 0x1b); + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + err += sn9c102_write_reg(cam, h_size, 0x15); + err += sn9c102_write_reg(cam, v_size, 0x16); + err += sn9c102_write_reg(cam, ae_strx, 0x1c); + err += sn9c102_write_reg(cam, ae_stry, 0x1d); + err += sn9c102_write_reg(cam, ae_endx, 0x1e); + err += sn9c102_write_reg(cam, ae_endy, 0x1f); + if (err) + return -EIO; + + PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " + "%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size, + vo_size) + + return 0; +} + + +static int sn9c102_init(struct sn9c102_device* cam) +{ + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_control ctrl; + struct v4l2_queryctrl *qctrl; + struct v4l2_rect* rect; + u8 i = 0, n = 0; + int err = 0; + + if (!(cam->state & DEV_INITIALIZED)) { + init_waitqueue_head(&cam->open); + qctrl = s->qctrl; + rect = &(s->cropcap.defrect); + } else { /* use current values */ + qctrl = s->_qctrl; + rect = &(s->_rect); + } + + err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); + err += sn9c102_set_crop(cam, rect); + if (err) + return err; + + if (s->init) { + err = s->init(cam); + if (err) { + DBG(3, "Sensor initialization failed") + return err; + } + } + + if (s->set_crop) + if ((err = s->set_crop(cam, rect))) { + DBG(3, "set_crop() failed") + return err; + } + + if (s->set_ctrl) { + n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); + for (i = 0; i < n; i++) + if (s->qctrl[i].id != 0 && + !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl.id = s->qctrl[i].id; + ctrl.value = qctrl[i].default_value; + err = s->set_ctrl(cam, &ctrl); + if (err) { + DBG(3, "Set control failed") + return err; + } + } + } + + if (!(cam->state & DEV_INITIALIZED)) { + init_MUTEX(&cam->fileop_sem); + spin_lock_init(&cam->queue_lock); + init_waitqueue_head(&cam->wait_frame); + init_waitqueue_head(&cam->wait_stream); + memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); + memcpy(&(s->_rect), &(s->cropcap.defrect), + sizeof(struct v4l2_rect)); + cam->state |= DEV_INITIALIZED; + } + + DBG(2, "Initialization succeeded") + return 0; +} + + +static void sn9c102_release_resources(struct sn9c102_device* cam) +{ + down(&sn9c102_sysfs_lock); + + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor) + video_set_drvdata(cam->v4ldev, NULL); + video_unregister_device(cam->v4ldev); + + up(&sn9c102_sysfs_lock); + + kfree(cam->control_buffer); +} + +/*****************************************************************************/ + +static int sn9c102_open(struct inode* inode, struct file* filp) +{ + struct sn9c102_device* cam; + int err = 0; + + /* This the only safe way to prevent race conditions with disconnect */ + if (!down_read_trylock(&sn9c102_disconnect)) + return -ERESTARTSYS; + + cam = video_get_drvdata(video_devdata(filp)); + + if (down_interruptible(&cam->dev_sem)) { + up_read(&sn9c102_disconnect); + return -ERESTARTSYS; + } + + if (cam->users) { + DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor) + if ((filp->f_flags & O_NONBLOCK) || + (filp->f_flags & O_NDELAY)) { + err = -EWOULDBLOCK; + goto out; + } + up(&cam->dev_sem); + err = wait_event_interruptible_exclusive(cam->open, + cam->state & DEV_DISCONNECTED + || !cam->users); + if (err) { + up_read(&sn9c102_disconnect); + return err; + } + if (cam->state & DEV_DISCONNECTED) { + up_read(&sn9c102_disconnect); + return -ENODEV; + } + down(&cam->dev_sem); + } + + + if (cam->state & DEV_MISCONFIGURED) { + err = sn9c102_init(cam); + if (err) { + DBG(1, "Initialization failed again. " + "I will retry on next open().") + goto out; + } + cam->state &= ~DEV_MISCONFIGURED; + } + + if ((err = sn9c102_start_transfer(cam))) + goto out; + + filp->private_data = cam; + cam->users++; + cam->io = IO_NONE; + cam->stream = STREAM_OFF; + cam->nbuffers = 0; + cam->frame_count = 0; + sn9c102_empty_framequeues(cam); + + DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor) + +out: + up(&cam->dev_sem); + up_read(&sn9c102_disconnect); + return err; +} + + +static int sn9c102_release(struct inode* inode, struct file* filp) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + + down(&cam->dev_sem); /* prevent disconnect() to be called */ + + sn9c102_stop_transfer(cam); + + sn9c102_release_buffers(cam); + + if (cam->state & DEV_DISCONNECTED) { + sn9c102_release_resources(cam); + up(&cam->dev_sem); + kfree(cam); + return 0; + } + + cam->users--; + wake_up_interruptible_nr(&cam->open, 1); + + DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor) + + up(&cam->dev_sem); + + return 0; +} + + +static ssize_t +sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_frame_t* f, * i; + unsigned long lock_flags; + int err = 0; + + if (down_interruptible(&cam->fileop_sem)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present") + up(&cam->fileop_sem); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it again.") + up(&cam->fileop_sem); + return -EIO; + } + + if (cam->io == IO_MMAP) { + DBG(3, "Close and open the device again to choose " + "the read method") + up(&cam->fileop_sem); + return -EINVAL; + } + + if (cam->io == IO_NONE) { + if (!sn9c102_request_buffers(cam, 2)) { + DBG(1, "read() failed, not enough memory") + up(&cam->fileop_sem); + return -ENOMEM; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + sn9c102_queue_unusedframes(cam); + } + + if (!count) { + up(&cam->fileop_sem); + return 0; + } + + if (list_empty(&cam->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + up(&cam->fileop_sem); + return -EAGAIN; + } + err = wait_event_interruptible + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) ); + if (err) { + up(&cam->fileop_sem); + return err; + } + if (cam->state & DEV_DISCONNECTED) { + up(&cam->fileop_sem); + return -ENODEV; + } + } + + f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_for_each_entry(i, &cam->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + sn9c102_queue_unusedframes(cam); + + if (count > f->buf.length) + count = f->buf.length; + + if (copy_to_user(buf, f->bufmem, count)) { + up(&cam->fileop_sem); + return -EFAULT; + } + *f_pos += count; + + PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count) + + up(&cam->fileop_sem); + + return count; +} + + +static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + unsigned int mask = 0; + + if (down_interruptible(&cam->fileop_sem)) + return POLLERR; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present") + goto error; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it again.") + goto error; + } + + if (cam->io == IO_NONE) { + if (!sn9c102_request_buffers(cam, 2)) { + DBG(1, "poll() failed, not enough memory") + goto error; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + } + + if (cam->io == IO_READ) + sn9c102_queue_unusedframes(cam); + + poll_wait(filp, &cam->wait_frame, wait); + + if (!list_empty(&cam->outqueue)) + mask |= POLLIN | POLLRDNORM; + + up(&cam->fileop_sem); + + return mask; + +error: + up(&cam->fileop_sem); + return POLLERR; +} + + +static void sn9c102_vm_open(struct vm_area_struct* vma) +{ + struct sn9c102_frame_t* f = vma->vm_private_data; + f->vma_use_count++; +} + + +static void sn9c102_vm_close(struct vm_area_struct* vma) +{ + /* NOTE: buffers are not freed here */ + struct sn9c102_frame_t* f = vma->vm_private_data; + f->vma_use_count--; +} + + +static struct vm_operations_struct sn9c102_vm_ops = { + .open = sn9c102_vm_open, + .close = sn9c102_vm_close, +}; + + +static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start, + pos, + page; + u32 i; + + if (down_interruptible(&cam->fileop_sem)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present") + up(&cam->fileop_sem); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it again.") + up(&cam->fileop_sem); + return -EIO; + } + + if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + size != PAGE_ALIGN(cam->frame[0].buf.length)) { + up(&cam->fileop_sem); + return -EINVAL; + } + + for (i = 0; i < cam->nbuffers; i++) { + if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == cam->nbuffers) { + up(&cam->fileop_sem); + return -EINVAL; + } + + pos = (unsigned long)cam->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + page = kvirt_to_pa(pos); + if (remap_page_range(vma, start, page, PAGE_SIZE, + vma->vm_page_prot)) { + up(&cam->fileop_sem); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &sn9c102_vm_ops; + vma->vm_flags &= ~VM_IO; /* not I/O memory */ + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + vma->vm_private_data = &cam->frame[i]; + + sn9c102_vm_open(vma); + + up(&cam->fileop_sem); + + return 0; +} + + +static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, void __user * arg) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + + switch (cmd) { + + case VIDIOC_QUERYCAP: + { + struct v4l2_capability cap = { + .driver = "sn9c102", + .version = SN9C102_MODULE_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, + }; + + strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); + strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info)); + + if (copy_to_user(arg, &cap, sizeof(cap))) + return -EFAULT; + + return 0; + } + + case VIDIOC_ENUMINPUT: + { + struct v4l2_input i; + + if (copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + + if (i.index) + return -EINVAL; + + memset(&i, 0, sizeof(i)); + strcpy(i.name, "USB"); + + if (copy_to_user(arg, &i, sizeof(i))) + return -EFAULT; + + return 0; + } + + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + { + int index; + + if (copy_from_user(&index, arg, sizeof(index))) + return -EFAULT; + + if (index != 0) + return -EINVAL; + + return 0; + } + + case VIDIOC_QUERYCTRL: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_queryctrl qc; + u8 i, n; + + if (copy_from_user(&qc, arg, sizeof(qc))) + return -EFAULT; + + n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); + for (i = 0; i < n; i++) + if (qc.id && qc.id == s->qctrl[i].id) { + memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); + if (copy_to_user(arg, &qc, sizeof(qc))) + return -EFAULT; + return 0; + } + + return -EINVAL; + } + + case VIDIOC_G_CTRL: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_control ctrl; + int err = 0; + + if (!s->get_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + err = s->get_ctrl(cam, &ctrl); + + if (copy_to_user(arg, &ctrl, sizeof(ctrl))) + return -EFAULT; + + return err; + } + + case VIDIOC_S_CTRL: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_control ctrl; + u8 i, n; + int err = 0; + + if (!s->set_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + if ((err = s->set_ctrl(cam, &ctrl))) + return err; + + n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); + for (i = 0; i < n; i++) + if (ctrl.id == s->qctrl[i].id) { + s->_qctrl[i].default_value = ctrl.value; + break; + } + + return 0; + } + + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + + cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cc->pixelaspect.numerator = 1; + cc->pixelaspect.denominator = 1; + + if (copy_to_user(arg, cc, sizeof(*cc))) + return -EFAULT; + + return 0; + } + + case VIDIOC_G_CROP: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_crop crop = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + }; + + memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); + + if (copy_to_user(arg, &crop, sizeof(crop))) + return -EFAULT; + + return 0; + } + + case VIDIOC_S_CROP: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_crop crop; + struct v4l2_rect* rect; + struct v4l2_rect* bounds = &(s->cropcap.bounds); + struct v4l2_pix_format* pix_format = &(s->pix_format); + u8 scale; + const enum sn9c102_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&crop, arg, sizeof(crop))) + return -EFAULT; + + rect = &(crop.c); + + if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_CROP failed. " + "Unmap the buffers first.") + return -EINVAL; + } + + if (rect->width < 16) + rect->width = 16; + if (rect->height < 16) + rect->height = 16; + if (rect->width > bounds->width) + rect->width = bounds->width; + if (rect->height > bounds->height) + rect->height = bounds->height; + if (rect->left < bounds->left) + rect->left = bounds->left; + if (rect->top < bounds->top) + rect->top = bounds->top; + if (rect->left + rect->width > bounds->left + bounds->width) + rect->left = bounds->left+bounds->width - rect->width; + if (rect->top + rect->height > bounds->top + bounds->height) + rect->top = bounds->top+bounds->height - rect->height; + + rect->width &= ~15L; + rect->height &= ~15L; + + { /* calculate the scaling factor */ + u32 a, b; + a = rect->width * rect->height; + b = pix_format->width * pix_format->height; + scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : + ((a / b) > 4 ? 4 : (a / b)))) : 1; + } + + if (cam->stream == STREAM_ON) { + cam->stream = STREAM_INTERRUPT; + err = wait_event_interruptible + ( cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED) ); + if (err) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "The camera is misconfigured. To use " + "it, close and open /dev/video%d " + "again.", cam->v4ldev->minor) + return err; + } + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + } + + if (copy_to_user(arg, &crop, sizeof(crop))) { + cam->stream = stream; + return -EFAULT; + } + + sn9c102_release_buffers(cam); + + err = sn9c102_set_crop(cam, rect); + if (s->set_crop) + err += s->set_crop(cam, rect); + err += sn9c102_set_scale(cam, scale); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of hardware " + "problems. To use the camera, close and open " + "/dev/video%d again.", cam->v4ldev->minor) + return err; + } + + s->pix_format.width = rect->width/scale; + s->pix_format.height = rect->height/scale; + memcpy(&(s->_rect), rect, sizeof(*rect)); + + if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of not enough " + "memory. To use the camera, close and open " + "/dev/video%d again.", cam->v4ldev->minor) + return -ENOMEM; + } + + cam->stream = stream; + + return 0; + } + + case VIDIOC_ENUM_FMT: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_fmtdesc fmtd; + + if (copy_from_user(&fmtd, arg, sizeof(fmtd))) + return -EFAULT; + + if (fmtd.index != 0) + return -EINVAL; + + memset(&fmtd, 0, sizeof(fmtd)); + + fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmtd.description, "bayer rgb"); + fmtd.pixelformat = s->pix_format.pixelformat; + + if (copy_to_user(arg, &fmtd, sizeof(fmtd))) + return -EFAULT; + + return 0; + } + + case VIDIOC_G_FMT: + { + struct v4l2_format format; + struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + pfmt->bytesperline = (pfmt->width * pfmt->priv) / 8; + pfmt->sizeimage = pfmt->height * pfmt->bytesperline; + pfmt->field = V4L2_FIELD_NONE; + memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); + + if (copy_to_user(arg, &format, sizeof(format))) + return -EFAULT; + + return 0; + } + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + { + struct sn9c102_sensor* s = cam->sensor; + struct v4l2_format format; + struct v4l2_pix_format* pix; + struct v4l2_pix_format* pfmt = &(s->pix_format); + struct v4l2_rect* bounds = &(s->cropcap.bounds); + struct v4l2_rect rect; + u8 scale; + const enum sn9c102_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + pix = &(format.fmt.pix); + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memcpy(&rect, &(s->_rect), sizeof(rect)); + + { /* calculate the scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : + ((a / b) > 4 ? 4 : (a / b)))) : 1; + } + + rect.width = scale * pix->width; + rect.height = scale * pix->height; + + if (rect.width < 16) + rect.width = 16; + if (rect.height < 16) + rect.height = 16; + if (rect.width > bounds->left + bounds->width - rect.left) + rect.width = bounds->left+bounds->width - rect.left; + if (rect.height > bounds->top + bounds->height - rect.top) + rect.height = bounds->top + bounds->height - rect.top; + + rect.width &= ~15L; + rect.height &= ~15L; + + pix->width = rect.width / scale; + pix->height = rect.height / scale; + + pix->pixelformat = pfmt->pixelformat; + pix->priv = pfmt->priv; /* bpp */ + pix->colorspace = pfmt->colorspace; + pix->bytesperline = (pix->width * pix->priv) / 8; + pix->sizeimage = pix->height * pix->bytesperline; + pix->field = V4L2_FIELD_NONE; + + if (cmd == VIDIOC_TRY_FMT) + return 0; + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_FMT failed. " + "Unmap the buffers first.") + return -EINVAL; + } + + if (cam->stream == STREAM_ON) { + cam->stream = STREAM_INTERRUPT; + err = wait_event_interruptible + ( cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED) ); + if (err) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "The camera is misconfigured. To use " + "it, close and open /dev/video%d " + "again.", cam->v4ldev->minor) + return err; + } + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + } + + if (copy_to_user(arg, &format, sizeof(format))) { + cam->stream = stream; + return -EFAULT; + } + + sn9c102_release_buffers(cam); + + err = sn9c102_set_crop(cam, &rect); + if (s->set_crop) + err += s->set_crop(cam, &rect); + err += sn9c102_set_scale(cam, scale); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of hardware " + "problems. To use the camera, close and open " + "/dev/video%d again.", cam->v4ldev->minor) + return err; + } + + memcpy(pfmt, pix, sizeof(*pix)); + memcpy(&(s->_rect), &rect, sizeof(rect)); + + if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of not enough " + "memory. To use the camera, close and open " + "/dev/video%d again.", cam->v4ldev->minor) + return -ENOMEM; + } + + cam->stream = stream; + + return 0; + } + + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers rb; + u32 i; + int err; + + if (copy_from_user(&rb, arg, sizeof(rb))) + return -EFAULT; + + if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb.memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (cam->io == IO_READ) { + DBG(3, "Close and open the device again to choose " + "the mmap I/O method") + return -EINVAL; + } + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_REQBUFS failed. " + "Previous buffers are still mapped.") + return -EINVAL; + } + + if (cam->stream == STREAM_ON) { + cam->stream = STREAM_INTERRUPT; + err = wait_event_interruptible + ( cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED) ); + if (err) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "The camera is misconfigured. To use " + "it, close and open /dev/video%d " + "again.", cam->v4ldev->minor) + return err; + } + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + } + + sn9c102_empty_framequeues(cam); + + sn9c102_release_buffers(cam); + if (rb.count) + rb.count = sn9c102_request_buffers(cam, rb.count); + + if (copy_to_user(arg, &rb, sizeof(rb))) { + sn9c102_release_buffers(cam); + cam->io = IO_NONE; + return -EFAULT; + } + + cam->io = rb.count ? IO_MMAP : IO_NONE; + + return 0; + } + + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer b; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); + + if (cam->frame[b.index].vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (cam->frame[b.index].state == F_DONE) + b.flags |= V4L2_BUF_FLAG_DONE; + else if (cam->frame[b.index].state != F_UNUSED) + b.flags |= V4L2_BUF_FLAG_QUEUED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + + case VIDIOC_QBUF: + { + struct v4l2_buffer b; + unsigned long lock_flags; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->frame[b.index].state != F_UNUSED) + return -EINVAL; + + cam->frame[b.index].state = F_QUEUED; + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + PDBGG("Frame #%lu queued", (unsigned long)b.index) + + return 0; + } + + case VIDIOC_DQBUF: + { + struct v4l2_buffer b; + struct sn9c102_frame_t *f; + unsigned long lock_flags; + int err = 0; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) + return -EINVAL; + + if (list_empty(&cam->outqueue)) { + if (cam->stream == STREAM_OFF) + return -EINVAL; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + err = wait_event_interruptible + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) ); + if (err) + return err; + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + } + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, + frame); + list_del(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + f->state = F_UNUSED; + + memcpy(&b, &f->buf, sizeof(b)); + if (f->vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index) + + return 0; + } + + case VIDIOC_STREAMON: + { + int type; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&cam->inqueue)) + return -EINVAL; + + cam->stream = STREAM_ON; + + DBG(3, "Stream on") + + return 0; + } + + case VIDIOC_STREAMOFF: + { + int type, err; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->stream == STREAM_ON) { + cam->stream = STREAM_INTERRUPT; + err = wait_event_interruptible + ( cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED) ); + if (err) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "The camera is misconfigured. To use " + "it, close and open /dev/video%d " + "again.", cam->v4ldev->minor) + return err; + } + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + } + + sn9c102_empty_framequeues(cam); + + DBG(3, "Stream off") + + return 0; + } + + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_QUERYSTD: + case VIDIOC_ENUMSTD: + case VIDIOC_QUERYMENU: + case VIDIOC_G_PARM: + case VIDIOC_S_PARM: + return -EINVAL; + + default: + return -EINVAL; + + } +} + + +static int sn9c102_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, unsigned long arg) +{ + struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + int err = 0; + + if (down_interruptible(&cam->fileop_sem)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present") + up(&cam->fileop_sem); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it again.") + up(&cam->fileop_sem); + return -EIO; + } + + err = sn9c102_v4l2_ioctl(inode, filp, cmd, (void __user *)arg); + + up(&cam->fileop_sem); + + return err; +} + + +static struct file_operations sn9c102_fops = { + .owner = THIS_MODULE, + .open = sn9c102_open, + .release = sn9c102_release, + .ioctl = sn9c102_ioctl, + .read = sn9c102_read, + .poll = sn9c102_poll, + .mmap = sn9c102_mmap, + .llseek = no_llseek, +}; + +/*****************************************************************************/ + +/* It exists a single interface only. We do not need to validate anything. */ +static int +sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct sn9c102_device* cam; + static unsigned int dev_nr = 0; + unsigned int i, n; + int err = 0, r; + + n = sizeof(sn9c102_id_table)/sizeof(sn9c102_id_table[0]); + for (i = 0; i < n-1; i++) + if (udev->descriptor.idVendor==sn9c102_id_table[i].idVendor && + udev->descriptor.idProduct==sn9c102_id_table[i].idProduct) + break; + if (i == n-1) + return -ENODEV; + + if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) + return -ENOMEM; + memset(cam, 0, sizeof(*cam)); + + cam->usbdev = udev; + + memcpy(&cam->dev, &udev->dev, sizeof(struct device)); + + if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) { + DBG(1, "kmalloc() failed") + err = -ENOMEM; + goto fail; + } + memset(cam->control_buffer, 0, 8); + + if (!(cam->v4ldev = video_device_alloc())) { + DBG(1, "video_device_alloc() failed") + err = -ENOMEM; + goto fail; + } + + init_MUTEX(&cam->dev_sem); + + r = sn9c102_read_reg(cam, 0x00); + if (r < 0 || r != 0x10) { + DBG(1, "Sorry, this is not a SN9C10[12] based camera " + "(vid/pid 0x%04X/0x%04X)", + sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct) + err = -ENODEV; + goto fail; + } + + DBG(2, "SN9C10[12] PC Camera Controller detected " + "(vid/pid 0x%04X/0x%04X)", + sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct) + + for (i = 0; sn9c102_sensor_table[i]; i++) { + err = sn9c102_sensor_table[i](cam); + if (!err) + break; + } + + if (!err && cam->sensor) { + DBG(2, "%s image sensor detected", cam->sensor->name) + DBG(3, "Support for %s maintained by %s", + cam->sensor->name, cam->sensor->maintainer) + } else { + DBG(1, "No supported image sensor detected") + err = -ENODEV; + goto fail; + } + + if (sn9c102_init(cam)) { + DBG(1, "Initialization failed. I will retry on open().") + cam->state |= DEV_MISCONFIGURED; + } + + strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera"); + cam->v4ldev->owner = THIS_MODULE; + cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; + cam->v4ldev->hardware = VID_HARDWARE_SN9C102; + cam->v4ldev->fops = &sn9c102_fops; + cam->v4ldev->minor = video_nr[dev_nr]; + cam->v4ldev->release = video_device_release; + video_set_drvdata(cam->v4ldev, cam); + + down(&cam->dev_sem); + + err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, + video_nr[dev_nr]); + if (err) { + DBG(1, "V4L2 device registration failed") + if (err == -ENFILE && video_nr[dev_nr] == -1) + DBG(1, "Free /dev/videoX node not found") + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; + up(&cam->dev_sem); + goto fail; + } + + DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor) + + sn9c102_create_sysfs(cam); + + usb_set_intfdata(intf, cam); + + up(&cam->dev_sem); + + return 0; + +fail: + if (cam) { + kfree(cam->control_buffer); + if (cam->v4ldev) + video_device_release(cam->v4ldev); + kfree(cam); + } + return err; +} + + +static void sn9c102_usb_disconnect(struct usb_interface* intf) +{ + struct sn9c102_device* cam = usb_get_intfdata(intf); + + if (!cam) + return; + + down_write(&sn9c102_disconnect); + + down(&cam->dev_sem); + + DBG(2, "Disconnecting %s...", cam->v4ldev->name) + + wake_up_interruptible_all(&cam->open); + + if (cam->users) { + DBG(2, "Device /dev/video%d is open! Deregistration and " + "memory deallocation are deferred on close.", + cam->v4ldev->minor) + cam->state |= DEV_MISCONFIGURED; + sn9c102_stop_transfer(cam); + cam->state |= DEV_DISCONNECTED; + wake_up_interruptible(&cam->wait_frame); + wake_up_interruptible(&cam->wait_stream); + } else { + cam->state |= DEV_DISCONNECTED; + sn9c102_release_resources(cam); + } + + up(&cam->dev_sem); + + if (!cam->users) + kfree(cam); + + up_write(&sn9c102_disconnect); +} + + +static struct usb_driver sn9c102_usb_driver = { + .owner = THIS_MODULE, + .name = "sn9c102", + .id_table = sn9c102_id_table, + .probe = sn9c102_usb_probe, + .disconnect = sn9c102_usb_disconnect, +}; + +/*****************************************************************************/ + +static int __init sn9c102_module_init(void) +{ + int err = 0; + + KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION) + KDBG(3, SN9C102_MODULE_AUTHOR) + + if ((err = usb_register(&sn9c102_usb_driver))) + KDBG(1, "usb_register() failed") + + return err; +} + + +static void __exit sn9c102_module_exit(void) +{ + usb_deregister(&sn9c102_usb_driver); +} + + +module_init(sn9c102_module_init); +module_exit(sn9c102_module_exit); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102.h 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,181 @@ +/*************************************************************************** + * V4L2 driver for SN9C10[12] PC Camera Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _SN9C102_H_ +#define _SN9C102_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sn9c102_sensor.h" + +/*****************************************************************************/ + +#define SN9C102_DEBUG +#define SN9C102_DEBUG_LEVEL 2 +#define SN9C102_MAX_DEVICES 64 +#define SN9C102_MAX_FRAMES 32 +#define SN9C102_URBS 2 +#define SN9C102_ISO_PACKETS 7 +#define SN9C102_ALTERNATE_SETTING 8 +#define SN9C102_CTRL_TIMEOUT 10*HZ + +/*****************************************************************************/ + +#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10[12] PC Camera Controllers" +#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" +#define SN9C102_AUTHOR_EMAIL "" +#define SN9C102_MODULE_LICENSE "GPL" +#define SN9C102_MODULE_VERSION "1:1.01-beta" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) + +SN9C102_ID_TABLE; +SN9C102_SENSOR_TABLE; + +enum sn9c102_frame_state { + F_UNUSED, + F_QUEUED, + F_GRABBING, + F_DONE, + F_ERROR, +}; + +struct sn9c102_frame_t { + void* bufmem; + struct v4l2_buffer buf; + enum sn9c102_frame_state state; + struct list_head frame; + unsigned long vma_use_count; +}; + +enum sn9c102_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +enum sn9c102_io_method { + IO_NONE, + IO_READ, + IO_MMAP, +}; + +enum sn9c102_stream_state { + STREAM_OFF, + STREAM_INTERRUPT, + STREAM_ON, +}; + +struct sn9c102_sysfs_attr { + u8 reg, val, i2c_reg, i2c_val; +}; + +static DECLARE_MUTEX(sn9c102_sysfs_lock); +static DECLARE_RWSEM(sn9c102_disconnect); + +struct sn9c102_device { + struct device dev; + + struct video_device* v4ldev; + + struct sn9c102_sensor* sensor; + + struct usb_device* usbdev; + struct urb* urb[SN9C102_URBS]; + void* transfer_buffer[SN9C102_URBS]; + u8* control_buffer; + + struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; + struct list_head inqueue, outqueue; + u32 frame_count, nbuffers; + + enum sn9c102_io_method io; + enum sn9c102_stream_state stream; + + struct sn9c102_sysfs_attr sysfs; + u16 reg[32]; + + enum sn9c102_dev_state state; + u8 users; + + struct semaphore dev_sem, fileop_sem; + spinlock_t queue_lock; + wait_queue_head_t open, wait_frame, wait_stream; +}; + +/*****************************************************************************/ + +void +sn9c102_attach_sensor(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor) +{ + cam->sensor = sensor; + cam->sensor->dev = &cam->dev; + cam->sensor->usbdev = cam->usbdev; +} + +/*****************************************************************************/ + +#undef DBG +#undef KDBG +#ifdef SN9C102_DEBUG +# define DBG(level, fmt, args...) \ +{ \ + if (debug >= (level)) { \ + if ((level) == 1) \ + dev_err(&cam->dev, fmt "\n", ## args); \ + else if ((level) == 2) \ + dev_info(&cam->dev, fmt "\n", ## args); \ + else if ((level) >= 3) \ + dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args); \ + } \ +} +# define KDBG(level, fmt, args...) \ +{ \ + if (debug >= (level)) { \ + if ((level) == 1 || (level) == 2) \ + pr_info("sn9c102: " fmt "\n", ## args); \ + else if ((level) == 3) \ + pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ + __LINE__ , ## args); \ + } \ +} +#else +# define KDBG(level, fmt, args...) do {;} while(0); +# define DBG(level, fmt, args...) do {;} while(0); +#endif + +#undef PDBG +#define PDBG(fmt, args...) \ +dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); + +#undef PDBGG +#define PDBGG(fmt, args...) do {;} while(0); /* placeholder */ + +#endif /* _SN9C102_H_ */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102_pas106b.c 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,209 @@ +/*************************************************************************** + * Driver for PAS106B image sensor connected to the SN9C10[12] PC Camera * + * Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor pas106b; + + +static int pas106b_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + + err += sn9c102_i2c_write(cam, 0x02, 0x0c); + err += sn9c102_i2c_write(cam, 0x03, 0x12); + err += sn9c102_i2c_write(cam, 0x04, 0x05); + err += sn9c102_i2c_write(cam, 0x05, 0x22); + err += sn9c102_i2c_write(cam, 0x06, 0xac); + err += sn9c102_i2c_write(cam, 0x07, 0x00); + err += sn9c102_i2c_write(cam, 0x08, 0x01); + err += sn9c102_i2c_write(cam, 0x0a, 0x00); + err += sn9c102_i2c_write(cam, 0x0b, 0x00); + err += sn9c102_i2c_write(cam, 0x0d, 0x00); + err += sn9c102_i2c_write(cam, 0x10, 0x06); + err += sn9c102_i2c_write(cam, 0x11, 0x06); + err += sn9c102_i2c_write(cam, 0x12, 0x00); + err += sn9c102_i2c_write(cam, 0x14, 0x02); + err += sn9c102_i2c_write(cam, 0x13, 0x01); + + msleep(400); + + return err; +} + + +static int pas106b_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0; + case V4L2_CID_BLUE_BALANCE: + return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0; + case V4L2_CID_BRIGHTNESS: + return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0; + default: + return -EINVAL; + } +} + + +static int pas106b_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value & 0x1f); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); + break; + default: + return -EINVAL; + } + err += sn9c102_i2c_write(cam, 0x13, 0x01); + + return err; +} + + +static int pas106b_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &pas106b; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor pas106b = { + .name = "PAS106B", + .maintainer = "Luca Risolia ", + .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .slave_read_id = 0x40, + .slave_write_id = 0x40, + .init = &pas106b_init, + .qctrl = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x03, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x02, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x06, + .flags = 0, + }, + }, + .get_ctrl = &pas106b_get_ctrl, + .set_ctrl = &pas106b_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + }, + .set_crop = &pas106b_set_crop, + .pix_format = { + .width = 352, + .height = 288, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, /* we use this field as 'bits per pixel' */ + } +}; + + +int sn9c102_probe_pas106b(struct sn9c102_device* cam) +{ + int r0 = 0, r1 = 0, err = 0; + unsigned int pid = 0; + + /* Minimal initialization to enable the I2C communication + NOTE: do NOT change the values! */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ + err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */ + if (err) + return -EIO; + + r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); + r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); + + if (r0 < 0 || r1 < 0) + return -EIO; + + pid = (r0 << 11) | ((r1 & 0xf0) >> 4); + if (pid != 0x007) + return -ENODEV; + + sn9c102_attach_sensor(cam, &pas106b); + + return 0; +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102_sensor.h 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,270 @@ +/*************************************************************************** + * API for image sensors connected to the SN9C10[12] PC Camera Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _SN9C102_SENSOR_H_ +#define _SN9C102_SENSOR_H_ + +#include +#include +#include +#include +#include +#include + +struct sn9c102_device; +struct sn9c102_sensor; + +/*****************************************************************************/ + +/* OVERVIEW. + This is a small interface that allows you to add support for any CCD/CMOS + image sensors connected to the SN9C10X bridges. The entire API is documented + below. In the most general case, to support a sensor there are three steps + you have to follow: + 1) define the main "sn9c102_sensor" structure by setting the basic fields; + 2) write a probing function to be called by the core module when the USB + camera is recognized, then add both the USB ids and the name of that + function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see + below); + 3) implement the methods that you want/need (and fill the rest of the main + structure accordingly). + "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do + NOT need to touch the source code of the core module for the things to work + properly, unless you find bugs or flaws in it. Finally, do not forget to + read the V4L2 API for completeness. */ + +/*****************************************************************************/ + +/* Probing functions: on success, you must attach the sensor to the camera + by calling sn9c102_attach_sensor() provided below. + To enable the I2C communication, you might need to perform a really basic + initialization of the SN9C10X chip by using the write function declared + ahead. + Functions must return 0 on success, the appropriate error otherwise. */ +extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); +extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); +extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); + +/* Add the above entries to this table. Be sure to add the entry in the right + place, since, on failure, the next probing routine is called according to + the order of the list below, from top to bottom */ +#define SN9C102_SENSOR_TABLE \ +static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ + &sn9c102_probe_pas106b, /* strong detection based on SENSOR vid/pid */\ + &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ + &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ + NULL, \ +}; + +/* Attach a probed sensor to the camera. */ +extern void +sn9c102_attach_sensor(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor); + +/* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ +#define SN9C102_ID_TABLE \ +static const struct usb_device_id sn9c102_id_table[] = { \ + { USB_DEVICE(0xc45, 0x6001), }, \ + { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \ + { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \ + { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \ + { USB_DEVICE(0xc45, 0x6024), }, \ + { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B Maybe also TAS5110C1B */\ + { USB_DEVICE(0xc45, 0x6028), }, /* Maybe PAS202B */ \ + { USB_DEVICE(0xc45, 0x6029), }, \ + { USB_DEVICE(0xc45, 0x602a), }, /* Maybe HV7131[D|E1] */ \ + { USB_DEVICE(0xc45, 0x602c), }, /* Maybe OV7620 */ \ + { USB_DEVICE(0xc45, 0x6030), }, /* Maybe MI03 */ \ + { USB_DEVICE(0xc45, 0x8001), }, \ + { } \ +}; + +/*****************************************************************************/ + +/* Read/write routines: they always return -1 on error, 0 or the read value + otherwise. NOTE that a real read operation is not supported by the SN9C10X + chip for some of its registers. To work around this problem, a pseudo-read + call is provided instead: it returns the last successfully written value + on the register (0 if it has never been written), the usual -1 on error. */ + +/* The "try" I2C I/O versions are used when probing the sensor */ +extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, + u8 address, u8 value); +extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, + u8 address); + +/* This must be used if and only if the sensor doesn't implement the standard + I2C protocol, like the TASC sensors. There a number of good reasons why you + must use the single-byte versions of this function: do not abuse. It writes + n bytes, from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip) */ +extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, + struct sn9c102_sensor* sensor, u8 n, + u8 data0, u8 data1, u8 data2, u8 data3, + u8 data4, u8 data5); + +/* To be used after the sensor struct has been attached to the camera struct */ +extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); +extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); + +/* I/O on registers in the bridge. Could be used by the sensor methods too */ +extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); +extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); + +/* NOTE: there are no debugging functions here. To uniform the output you must + use the dev_info()/dev_warn()/dev_err() macros defined in device.h, already + included here, the argument being the struct device 'dev' of the sensor + structure. Do NOT use these macros before the sensor is attached or the + kernel will crash! However you should not need to notify the user about + common errors or other messages, since this is done by the master module. */ + +/*****************************************************************************/ + +enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ + SN9C102_I2C_100KHZ = 0x01, + SN9C102_I2C_400KHZ = 0x02, +}; + +enum sn9c102_i2c_interface { + SN9C102_I2C_2WIRES, + SN9C102_I2C_3WIRES, +}; + +struct sn9c102_sensor { + char name[32], /* sensor name */ + maintainer[64]; /* name of the mantainer */ + + /* These sensor capabilities must be provided if the SN9C10X controller + needs to communicate through the sensor serial interface by using + at least one of the i2c functions available */ + enum sn9c102_i2c_frequency frequency; + enum sn9c102_i2c_interface interface; + + /* These identifiers must be provided if the image sensor implements + the standard I2C protocol. TASC sensors don't, although they have a + serial interface: so this is a case where the "raw" I2C version + could be helpful. */ + u8 slave_read_id, slave_write_id; /* reg. 0x09 */ + + /* NOTE: Where not noted,most of the functions below are not mandatory. + Set to null if you do not implement them. If implemented, + they must return 0 on success, the proper error otherwise. */ + + int (*init)(struct sn9c102_device* cam); + /* This function is called after the sensor has been attached. + It should be used to initialize the sensor only, but may also + configure part of the SN9C10X chip if necessary. You don't need to + setup picture settings like brightness, contrast, etc.. here, if + the corrisponding controls are implemented (see below), since + they are adjusted in the core driver by calling the set_ctrl() + method after init(), where the arguments are the default values + specified in the v4l2_queryctrl list of supported controls; + Same suggestions apply for other settings, _if_ the corresponding + methods are present; if not, the initialization must configure the + sensor according to the default configuration structures below. */ + + struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + /* Optional list of default controls, defined as indicated in the + V4L2 API. Menu type controls are not handled by this interface. */ + + int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); + int (*set_ctrl)(struct sn9c102_device* cam, + const struct v4l2_control* ctrl); + /* You must implement at least the set_ctrl method if you have defined + the list above. The returned value must follow the V4L2 + specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER + are not supported by this driver, so do not implement them. Also, + passed values are NOT checked to see if they are out of bounds. */ + + struct v4l2_cropcap cropcap; + /* Think the image sensor as a grid of R,G,B monochromatic pixels + disposed according to a particular Bayer pattern, which describes + the complete array of pixels, from (0,0) to (xmax, ymax). We will + use this coordinate system from now on. It is assumed the sensor + chip can be programmed to capture/transmit a subsection of that + array of pixels: we will call this subsection "active window". + It is not always true that the largest achievable active window can + cover the whole array of pixels. The V4L2 API defines another + area called "source rectangle", which, in turn, is a subrectangle of + the active window. The SN9C10X chip is always programmed to read the + source rectangle. + The bounds of both the active window and the source rectangle are + specified in the cropcap substructures 'bounds' and 'defrect'. + By default, the source rectangle should cover the largest possible + area. Again, it is not always true that the largest source rectangle + can cover the entire active window, although it is a rare case for + the hardware we have. The bounds of the source rectangle _must_ be + multiple of 16 and must use the same coordinate system as indicated + before; their centers shall align initially. + If necessary, the sensor chip must be initialized during init() to + set the bounds of the active sensor window; however, by default, it + usually covers the largest achievable area (maxwidth x maxheight) + of pixels, so no particular initialization is needed, if you have + defined the correct default bounds in the structures. + See the V4L2 API for further details. + NOTE: once you have defined the bounds of the active window + (struct cropcap.bounds) you must not change them.anymore. + Only 'bounds' and 'defrect' fields are mandatory, other fields + will be ignored. */ + + int (*set_crop)(struct sn9c102_device* cam, + const struct v4l2_rect* rect); + /* To be called on VIDIOC_C_SETCROP. The core module always calls a + default routine which configures the appropriate SN9C10X regs (also + scaling), but you may need to override/adjust specific stuff. + 'rect' contains width and height values that are multiple of 16: in + case you override the default function, you always have to program + the chip to match those values; on error return the corresponding + error code without rolling back. + NOTE: in case, you must program the SN9C10X chip to get rid of + blank pixels or blank lines at the _start_ of each line or + frame after each HSYNC or VSYNC, so that the image starts with + real RGB data (see regs 0x12,0x13) (having set H_SIZE and, + V_SIZE you don't have to care about blank pixels or blank + lines at the end of each line or frame). */ + + struct v4l2_pix_format pix_format; + /* What you have to define here are: initial 'width' and 'height' of + the target rectangle, the bayer 'pixelformat' and 'priv' which we'll + be used to indicate the number of bits per pixel, 8 or 9. + Nothing more. + NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 + of cropcap.defrect.width and cropcap.defrect.height. I + suggest 1/1. + NOTE 2: as said above, you have to program the SN9C10X chip to get + rid of any blank pixels, so that the output of the sensor + matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). */ + + const struct device* dev; + /* This is the argument for dev_err(), dev_info() and dev_warn(). It + is used for debugging purposes. You must not access the struct + before the sensor is attached. */ + + const struct usb_device* usbdev; + /* Points to the usb_device struct after the sensor is attached. + Do not touch unless you know what you are doing. */ + + /* Do NOT write to the data below, it's READ ONLY. It is used by the + core module to store successfully updated values of the above + settings, for rollbacks..etc..in case of errors during atomic I/O */ + struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_rect _rect; +}; + +#endif /* _SN9C102_SENSOR_H_ */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102_tas5110c1b.c 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,98 @@ +/*************************************************************************** + * Driver for TAS5110C1B image sensor connected to the SN9C10[12] PC * + * Camera Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor tas5110c1b; + + +static int tas5110c1b_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x44, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x06, 0x18); + err += sn9c102_write_reg(cam, 0xcb, 0x19); + + return err; +} + + +static int tas5110c1b_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &tas5110c1b; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor tas5110c1b = { + .name = "TAS5110C1B", + .maintainer = "Luca Risolia ", + .init = &tas5110c1b_init, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 352, + .height = 288, + }, + }, + .set_crop = &tas5110c1b_set_crop, + .pix_format = { + .width = 352, + .height = 288, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + } +}; + + +int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) +{ + /* This sensor has no identifiers, so let's attach it anyway */ + sn9c102_attach_sensor(cam, &tas5110c1b); + + /* At the moment, only devices whose PID is 0x6005 have this sensor */ + if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005) + return -ENODEV; + + return 0; +} --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/sn9c102_tas5130d1b.c 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,120 @@ +/*************************************************************************** + * Driver for TAS5130D1B image sensor connected to the SN9C10[12] PC * + * Camera Controllers * + * * + * Copyright (C) 2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor tas5130d1b; + + +static int tas5130d1b_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x04, 0x01); + err += sn9c102_write_reg(cam, 0x01, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x07, 0x18); + err += sn9c102_write_reg(cam, 0x33, 0x19); + + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, + 0x47, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, + 0xa9, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, + 0x49, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, + 0x6c, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, + 0x08, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20, + 0x00, 0, 0); + + err += sn9c102_write_reg(cam, 0x63, 0x19); + + return err; +} + + +static int tas5130d1b_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &tas5130d1b; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor tas5130d1b = { + .name = "TAS5130D1B", + .maintainer = "Luca Risolia ", + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_3WIRES, + .init = &tas5130d1b_init, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &tas5130d1b_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + } +}; + + +int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) +{ + /* This sensor has no identifiers, so let's attach it anyway */ + sn9c102_attach_sensor(cam, &tas5130d1b); + + /* At the moment, only devices whose PID is 0x6025 have this sensor */ + if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025) + return -ENODEV; + + dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it " + "is disabled at the moment - needs further " + "testing -\n"); + + return -ENODEV; +} --- linux-2.6.8-rc1/drivers/usb/media/w9968cf.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/w9968cf.c 2004-07-13 17:09:24.000000000 -0700 @@ -5,7 +5,7 @@ * * * - Memory management code from bttv driver by Ralph Metzler, * * Marcus Metzler and Gerd Knorr. * - * - I2C interface to kernel, high-level CMOS sensor control routines and * + * - I2C interface to kernel, high-level image sensor control routines and * * some symbolic names from OV511 driver by Mark W. McClelland. * * - Low-level I2C fast write function by Piotr Czerczak. * * - Low-level I2C read function by Frederic Jouault. * @@ -27,21 +27,23 @@ #include #include -#include #include +#include #include #include #include #include #include #include -#include #include #include #include #include +#include #include #include +#include +#include #include "w9968cf.h" #include "w9968cf_decoder.h" @@ -49,14 +51,18 @@ /**************************************************************************** - * Module macros and paramaters * + * Module macros and parameters * ****************************************************************************/ +MODULE_DEVICE_TABLE(usb, winbond_id_table); + MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); -MODULE_DESCRIPTION(W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION); +MODULE_DESCRIPTION(W9968CF_MODULE_NAME); +MODULE_VERSION(W9968CF_MODULE_VERSION); MODULE_LICENSE(W9968CF_MODULE_LICENSE); MODULE_SUPPORTED_DEVICE("Video"); +static int ovmod_load = W9968CF_OVMOD_LOAD; static int vppmod_load = W9968CF_VPPMOD_LOAD; static unsigned short simcams = W9968CF_SIMCAMS; static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ @@ -100,8 +106,11 @@ static int specific_debug = W9968CF_SPEC static unsigned int param_nv[24]; /* number of values per parameter */ +#ifdef CONFIG_KMOD +module_param(ovmod_load, bool, 0644); module_param(vppmod_load, bool, 0444); -module_param(simcams, ushort, 0444); +#endif +module_param(simcams, ushort, 0644); module_param_array(video_nr, short, param_nv[0], 0444); module_param_array(packet_size, uint, param_nv[1], 0444); module_param_array(max_buffers, ushort, param_nv[2], 0444); @@ -127,21 +136,34 @@ module_param_array(colour, uint, param_n module_param_array(contrast, uint, param_nv[22], 0444); module_param_array(whiteness, uint, param_nv[23], 0444); #ifdef W9968CF_DEBUG -module_param(debug, ushort, 0444); -module_param(specific_debug, bool, 0444); +module_param(debug, ushort, 0644); +module_param(specific_debug, bool, 0644); #endif +#ifdef CONFIG_KMOD +MODULE_PARM_DESC(ovmod_load, + "\n<0|1> Automatic 'ovcamchip' module loading." + "\n0 disabled, 1 enabled." + "\nIf enabled,'insmod' searches for the required 'ovcamchip'" + "\nmodule in the system, according to its configuration, and" + "\nattempts to load that module automatically. This action is" + "\nperformed once as soon as the 'w9968cf' module is loaded" + "\ninto memory." + "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." + "\n"); MODULE_PARM_DESC(vppmod_load, "\n<0|1> Automatic 'w9968cf-vpp' module loading." - "\n0 disable, 1 enable." + "\n0 disabled, 1 enabled." "\nIf enabled, every time an application attempts to open a" "\ncamera, 'insmod' searches for the video post-processing" "\nmodule in the system and loads it automatically (if" - "\npresent). The 'w9968cf-vpp' module adds extra image" - "\nmanipulation functions to the 'w9968cf' module, like" - "\nsoftware up-scaling,colour conversions and video decoding." + "\npresent). The optional 'w9968cf-vpp' module adds extra" + "\n image manipulation functions to the 'w9968cf' module,like" + "\nsoftware up-scaling,colour conversions and video decoding" + "\nfor very high frame rates." "\nDefault value is "__MODULE_STRING(W9968CF_VPPMOD_LOAD)"." "\n"); +#endif MODULE_PARM_DESC(simcams, "\n Number of cameras allowed to stream simultaneously." "\nn may vary from 0 to " @@ -176,8 +198,8 @@ MODULE_PARM_DESC(double_buffer, "\n<0|1[,...]> " "Hardware double buffering: 0 disabled, 1 enabled." "\nIt should be enabled if you want smooth video output: if" - "\nyou obtain out of sync. video, disable it at all, or try" - "\nto decrease the 'clockdiv' module paramater value." + "\nyou obtain out of sync. video, disable it, or try to" + "\ndecrease the 'clockdiv' module parameter value." "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) " for every device." "\n"); @@ -193,7 +215,7 @@ MODULE_PARM_DESC(filter_type, "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) " for every device." "\nThe filter is used to reduce noise and aliasing artifacts" - "\nproduced by the CCD or CMOS sensor, and the scaling" + "\nproduced by the CCD or CMOS image sensor, and the scaling" " process." "\n"); MODULE_PARM_DESC(largeview, @@ -208,7 +230,7 @@ MODULE_PARM_DESC(upscaling, " enough memory." "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) " for every device." - "\nIf 'w9968cf-vpp' is not loaded, this paramater is" + "\nIf 'w9968cf-vpp' is not present, this parameter is" " set to 0." "\n"); MODULE_PARM_DESC(decompression, @@ -224,8 +246,8 @@ MODULE_PARM_DESC(decompression, "a multiple of 16." "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) " for every device." - "\nIf 'w9968cf-vpp' is not loaded, forcing decompression is " - "\nnot allowed; in this case this paramater is set to 2." + "\nIf 'w9968cf-vpp' is not present, forcing decompression is " + "\nnot allowed; in this case this parameter is set to 2." "\n"); MODULE_PARM_DESC(force_palette, "\n<0" @@ -255,11 +277,11 @@ MODULE_PARM_DESC(force_palette, "\n- RGB565 16 bpp - Software conversion from UYVY" "\n- RGB24 24 bpp - Software conversion from UYVY" "\n- RGB32 32 bpp - Software conversion from UYVY" - "\nWhen not 0, this paramater will override 'decompression'." + "\nWhen not 0, this parameter will override 'decompression'." "\nDefault value is 0 for every device." "\nInitial palette is " __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." - "\nIf 'w9968cf-vpp' is not loaded, this paramater is" + "\nIf 'w9968cf-vpp' is not present, this parameter is" " set to 9 (UYVY)." "\n"); MODULE_PARM_DESC(force_rgb, @@ -271,13 +293,13 @@ MODULE_PARM_DESC(force_rgb, " for every device." "\n"); MODULE_PARM_DESC(autobright, - "\n<0|1[,...]> CMOS sensor automatically changes brightness:" + "\n<0|1[,...]> Image sensor automatically changes brightness:" "\n 0 = no, 1 = yes" "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) " for every device." "\n"); MODULE_PARM_DESC(autoexp, - "\n<0|1[,...]> CMOS sensor automatically changes exposure:" + "\n<0|1[,...]> Image sensor automatically changes exposure:" "\n 0 = no, 1 = yes" "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) " for every device." @@ -304,7 +326,7 @@ MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value (for experts):" "\n n may vary from 0 to 127." "\n -1 for automatic value." - "\nSee also the 'double_buffer' module paramater." + "\nSee also the 'double_buffer' module parameter." "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) " for every device." "\n"); @@ -321,7 +343,7 @@ MODULE_PARM_DESC(mirror, " for every device." "\n"); MODULE_PARM_DESC(monochrome, - "\n<0|1[,...]> Use OV CMOS sensor as monochrome sensor:" + "\n<0|1[,...]> Use image sensor as monochrome sensor:" "\n 0 = no, 1 = yes" "\nNot all the sensors support monochrome color." "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) @@ -363,7 +385,7 @@ MODULE_PARM_DESC(debug, "\n4 = warnings" "\n5 = called functions" "\n6 = function internals" - "\nLevel 5 and 6 are useful for testing only, when just " + "\nLevel 5 and 6 are useful for testing only, when only " "one device is used." "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." "\n"); @@ -388,14 +410,14 @@ MODULE_PARM_DESC(specific_debug, static struct file_operations w9968cf_fops; static int w9968cf_open(struct inode*, struct file*); static int w9968cf_release(struct inode*, struct file*); -static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); static int w9968cf_mmap(struct file*, struct vm_area_struct*); static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); -static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, void*); +static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); +static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, + void __user *); /* USB-specific */ static int w9968cf_start_transfer(struct w9968cf_device*); -static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); static int w9968cf_stop_transfer(struct w9968cf_device*); static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); static int w9968cf_read_reg(struct w9968cf_device*, u16 index); @@ -403,6 +425,7 @@ static int w9968cf_write_fsb(struct w996 static int w9968cf_write_sb(struct w9968cf_device*, u16 value); static int w9968cf_read_sb(struct w9968cf_device*); static int w9968cf_upload_quantizationtables(struct w9968cf_device*); +static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); /* Low-level I2C (SMBus) I/O */ static int w9968cf_smbus_start(struct w9968cf_device*); @@ -439,12 +462,11 @@ static void* rvmalloc(unsigned long size static void rvfree(void *mem, unsigned long size); static void w9968cf_deallocate_memory(struct w9968cf_device*); static int w9968cf_allocate_memory(struct w9968cf_device*); -static inline unsigned long w9968cf_get_max_bufsize(struct w9968cf_device*); -/* High-level CMOS sensor control functions */ +/* High-level image sensor control functions */ static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); -static int w9968cf_sensor_cmd(struct w9968cf_device*, +static int w9968cf_sensor_cmd(struct w9968cf_device*, unsigned int cmd, void *arg); static int w9968cf_sensor_init(struct w9968cf_device*); static int w9968cf_sensor_update_settings(struct w9968cf_device*); @@ -456,12 +478,13 @@ static int w9968cf_sensor_update_picture static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, enum w9968cf_model_id, const unsigned short dev_nr); +static void w9968cf_adjust_configuration(struct w9968cf_device*); static int w9968cf_turn_on_led(struct w9968cf_device*); static int w9968cf_init_chip(struct w9968cf_device*); static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); static int w9968cf_set_window(struct w9968cf_device*, struct video_window); static inline u16 w9968cf_valid_palette(u16 palette); -static u16 w9968cf_valid_depth(u16 palette); +static inline u16 w9968cf_valid_depth(u16 palette); static inline u8 w9968cf_need_decompression(u16 palette); static int w9968cf_postprocess_frame(struct w9968cf_device*, struct w9968cf_frame_t*); @@ -472,18 +495,8 @@ static void w9968cf_pop_frame(struct w99 static void w9968cf_release_resources(struct w9968cf_device*); /* Intermodule communication */ -static int w9968cf_vppmod_detect(void); -static void w9968cf_vppmod_release(void); - -/* Pointers to registered video post-processing functions */ -static void (*w9968cf_vpp_init_decoder)(void); -static int (*w9968cf_vpp_check_headers)(const unsigned char*, - const unsigned long); -static int (*w9968cf_vpp_decode)(const char*, const unsigned, - const unsigned, const unsigned, char*); -static void (*w9968cf_vpp_swap_yuvbytes)(void*, unsigned long); -static void (*w9968cf_vpp_uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8); -static void (*w9968cf_vpp_scale_up)(u8*, u8*, u16, u16, u16, u16, u16); +static int w9968cf_vppmod_detect(struct w9968cf_device*); +static void w9968cf_vppmod_release(struct w9968cf_device*); @@ -518,12 +531,15 @@ static struct w9968cf_symbolic_list caml { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, /* Other cameras (having the same descriptors as Generic W996[87]CF) */ - { W9968CF_MOD_ADPA5R, "Aroma Digi Pen ADG-5000 Refurbished" }, - { W9986CF_MOD_AU, "AVerTV USB" }, + { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, + { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, - { W9968CF_MOD_DLLDK, "Die Lebon LDC-D35A Digital Kamera" }, + { W9968CF_MOD_LL, "Lebon LDC-035A" }, { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, + { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, + { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, + { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, { -1, NULL } }; @@ -649,17 +665,6 @@ static void rvfree(void* mem, unsigned l /*-------------------------------------------------------------------------- - Return the maximum size (in bytes) of a frame buffer. - --------------------------------------------------------------------------*/ -static inline unsigned long w9968cf_get_max_bufsize(struct w9968cf_device* cam) -{ - u8 bpp = (w9968cf_vppmod_present) ? 4 : 2; - return (cam->upscaling) ? W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp : - cam->maxwidth*cam->maxheight*bpp; -} - - -/*-------------------------------------------------------------------------- Deallocate previously allocated memory. --------------------------------------------------------------------------*/ static void w9968cf_deallocate_memory(struct w9968cf_device* cam) @@ -674,26 +679,25 @@ static void w9968cf_deallocate_memory(st /* Free temporary frame buffer */ if (cam->frame_tmp.buffer) { - rvfree(cam->frame_tmp.buffer, W9968CF_HW_BUF_SIZE); + rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); cam->frame_tmp.buffer = NULL; } /* Free helper buffer */ - if (cam->vpp_buffer) { - rvfree(cam->vpp_buffer, w9968cf_get_max_bufsize(cam)); - cam->vpp_buffer = NULL; + if (cam->frame_vpp.buffer) { + rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); + cam->frame_vpp.buffer = NULL; } - + /* Free video frame buffers */ if (cam->frame[0].buffer) { - rvfree(cam->frame[0].buffer, - cam->nbuffers * w9968cf_get_max_bufsize(cam)); + rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); cam->frame[0].buffer = NULL; } cam->nbuffers = 0; - DBG(5, "Memory successfully deallocated.") + DBG(5, "Memory successfully deallocated") } @@ -704,19 +708,30 @@ static void w9968cf_deallocate_memory(st --------------------------------------------------------------------------*/ static int w9968cf_allocate_memory(struct w9968cf_device* cam) { - const unsigned long bufsize = w9968cf_get_max_bufsize(cam); const u16 p_size = wMaxPacketSize[cam->altsetting-1]; void* buff = NULL; - u8 i; + unsigned long hw_bufsize, vpp_bufsize; + u8 i, bpp; /* NOTE: Deallocation is done elsewhere in case of error */ + /* Calculate the max amount of raw data per frame from the device */ + hw_bufsize = cam->maxwidth*cam->maxheight*2; + + /* Calculate the max buf. size needed for post-processing routines */ + bpp = (w9968cf_vpp) ? 4 : 2; + if (cam->upscaling) + vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, + cam->maxwidth*cam->maxheight*bpp); + else + vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; + /* Allocate memory for the isochronous transfer buffers */ for (i = 0; i < W9968CF_URBS; i++) { if (!(cam->transfer_buffer[i] = kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { DBG(1, "Couldn't allocate memory for the isochronous " - "transfer buffers (%d bytes).", + "transfer buffers (%u bytes)", p_size * W9968CF_ISO_PACKETS) return -ENOMEM; } @@ -724,44 +739,49 @@ static int w9968cf_allocate_memory(struc } /* Allocate memory for the temporary frame buffer */ - if (!(cam->frame_tmp.buffer = rvmalloc(W9968CF_HW_BUF_SIZE))) { + if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { DBG(1, "Couldn't allocate memory for the temporary " - "video frame buffer (%i bytes).", W9968CF_HW_BUF_SIZE) + "video frame buffer (%lu bytes)", hw_bufsize) return -ENOMEM; } + cam->frame_tmp.size = hw_bufsize; + cam->frame_tmp.number = -1; /* Allocate memory for the helper buffer */ - if (w9968cf_vppmod_present) { - if (!(cam->vpp_buffer = rvmalloc(bufsize))) { + if (w9968cf_vpp) { + if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { DBG(1, "Couldn't allocate memory for the helper buffer" - " (%li bytes).", bufsize) + " (%lu bytes)", vpp_bufsize) return -ENOMEM; } + cam->frame_vpp.size = vpp_bufsize; } else - cam->vpp_buffer = NULL; + cam->frame_vpp.buffer = NULL; - /* Allocate memory for video frame buffers */ + /* Allocate memory for video frame buffers */ cam->nbuffers = cam->max_buffers; while (cam->nbuffers >= 2) { - if ((buff = rvmalloc(cam->nbuffers * bufsize))) + if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) break; else cam->nbuffers--; } if (!buff) { - DBG(1, "Couldn't allocate memory for the video frame buffers.") + DBG(1, "Couldn't allocate memory for the video frame buffers") cam->nbuffers = 0; return -ENOMEM; } if (cam->nbuffers != cam->max_buffers) - DBG(2, "Couldn't allocate memory for %d video frame buffers. " - "Only memory for %d buffers has been allocated.", + DBG(2, "Couldn't allocate memory for %u video frame buffers. " + "Only memory for %u buffers has been allocated", cam->max_buffers, cam->nbuffers) for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].buffer = buff + i*bufsize; + cam->frame[i].buffer = buff + i*vpp_bufsize; + cam->frame[i].size = vpp_bufsize; + cam->frame[i].number = i; /* Circular list */ if (i != cam->nbuffers-1) cam->frame[i].next = &cam->frame[i+1]; @@ -770,7 +790,7 @@ static int w9968cf_allocate_memory(struc cam->frame[i].status = F_UNUSED; } - DBG(5, "Memory successfully allocated.") + DBG(5, "Memory successfully allocated") return 0; } @@ -794,20 +814,16 @@ static void w9968cf_urb_complete(struct { struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; struct w9968cf_frame_t** f; - unsigned long maxbufsize; unsigned int len, status; void* pos; u8 i; int err = 0; if ((!cam->streaming) || cam->disconnected) { - DBG(4, "Got interrupt, but not streaming.") + DBG(4, "Got interrupt, but not streaming") return; } - maxbufsize = min( (unsigned long)W9968CF_HW_BUF_SIZE, - w9968cf_get_max_bufsize(cam) ); - /* "(*f)" will be used instead of "cam->frame_current" */ f = &cam->frame_current; @@ -820,8 +836,8 @@ static void w9968cf_urb_complete(struct (*f)->length = cam->frame_tmp.length; memcpy((*f)->buffer, cam->frame_tmp.buffer, (*f)->length); - DBG(6, "Switched from temp. frame to frame #%zd", - (*f) - &cam->frame[0]) + DBG(6, "Switched from temp. frame to frame #%d", + (*f)->number) } } @@ -832,7 +848,7 @@ static void w9968cf_urb_complete(struct if (status && len != 0) { DBG(4, "URB failed, error in data packet " - "(error #%d, %s).", + "(error #%u, %s)", status, symbolic(urb_errlist, status)) (*f)->status = F_ERROR; continue; @@ -846,8 +862,8 @@ static void w9968cf_urb_complete(struct } /* Buffer overflows shouldn't happen, however...*/ - if ((*f)->length + len > maxbufsize) { - DBG(4, "Buffer overflow: bad data packets.") + if ((*f)->length + len > (*f)->size) { + DBG(4, "Buffer overflow: bad data packets") (*f)->status = F_ERROR; } @@ -858,11 +874,10 @@ static void w9968cf_urb_complete(struct } else if ((*f)->status == F_GRABBING) { /* end of frame */ - DBG(6, "Frame #%zd successfully grabbed.", - ((*f)==&cam->frame_tmp ? -1 : (*f)-&cam->frame[0])) + DBG(6, "Frame #%d successfully grabbed", (*f)->number) if (cam->vpp_flag & VPP_DECOMPRESSION) { - err=(*w9968cf_vpp_check_headers)((*f)->buffer, + err = w9968cf_vpp->check_headers((*f)->buffer, (*f)->length); if (err) { DBG(4, "Skip corrupted frame: %s", @@ -887,7 +902,7 @@ static void w9968cf_urb_complete(struct } else if ((*f)->status == F_ERROR) (*f)->status = F_UNUSED; /* grab it again */ - PDBGG("Frame length %li | pack.#%d | pack.len. %d | state %d", + PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", (unsigned long)(*f)->length, i, len, (*f)->status) } /* end for */ @@ -900,7 +915,7 @@ static void w9968cf_urb_complete(struct if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { cam->misconfigured = 1; DBG(1, "Couldn't resubmit the URB: error %d, %s", - err, symbolic(urb_errlist, err)); + err, symbolic(urb_errlist, err)) } spin_unlock(&cam->urb_lock); @@ -931,7 +946,7 @@ static int w9968cf_start_transfer(struct if (!urb) { for (j = 0; j < i; j++) usb_free_urb(cam->urb[j]); - DBG(1, "Couldn't allocate the URB structures.") + DBG(1, "Couldn't allocate the URB structures") return -ENOMEM; } @@ -976,7 +991,7 @@ static int w9968cf_start_transfer(struct if (err || (vidcapt < 0)) { for (i = 0; i < W9968CF_URBS; i++) usb_free_urb(cam->urb[i]); - DBG(1, "Couldn't tell the camera to start the data transfer.") + DBG(1, "Couldn't tell the camera to start the data transfer") return err; } @@ -988,26 +1003,29 @@ static int w9968cf_start_transfer(struct cam->frame_current = &cam->frame_tmp; if (!(cam->vpp_flag & VPP_DECOMPRESSION)) - DBG(5, "Isochronous transfer size: %li bytes/frame.", + DBG(5, "Isochronous transfer size: %lu bytes/frame", (unsigned long)t_size*2) DBG(5, "Starting the isochronous transfer...") + cam->streaming = 1; + /* Submit the URBs */ for (i = 0; i < W9968CF_URBS; i++) { err = usb_submit_urb(cam->urb[i], GFP_KERNEL); if (err) { - for (j = i-1; j >= 0; j--) - if (!usb_unlink_urb(cam->urb[j])) - usb_free_urb(cam->urb[j]); + cam->streaming = 0; + for (j = i-1; j >= 0; j--) { + usb_kill_urb(cam->urb[j]); + usb_free_urb(cam->urb[j]); + } DBG(1, "Couldn't send a transfer request to the " - "USB core (error #%d, %s).", err, + "USB core (error #%d, %s)", err, symbolic(urb_errlist, err)) + return err; } } - cam->streaming = 1; - return 0; } @@ -1023,6 +1041,9 @@ static int w9968cf_stop_transfer(struct int err = 0; s8 i; + if (!cam->streaming) + return 0; + /* This avoids race conditions with usb_submit_urb() in the URB completition handler */ spin_lock_irqsave(&cam->urb_lock, lock_flags); @@ -1031,10 +1052,9 @@ static int w9968cf_stop_transfer(struct for (i = W9968CF_URBS-1; i >= 0; i--) if (cam->urb[i]) { - if (!usb_unlink_urb(cam->urb[i])) { - usb_free_urb(cam->urb[i]); - cam->urb[i] = NULL; - } + usb_kill_urb(cam->urb[i]); + usb_free_urb(cam->urb[i]); + cam->urb[i] = NULL; } if (cam->disconnected) @@ -1052,7 +1072,7 @@ static int w9968cf_stop_transfer(struct } exit: - DBG(5, "Isochronous transfer stopped.") + DBG(5, "Isochronous transfer stopped") return 0; } @@ -1072,7 +1092,7 @@ static int w9968cf_write_reg(struct w996 if (res < 0) DBG(4, "Failed to write a register " - "(value 0x%04X, index 0x%02X, error #%d, %s).", + "(value 0x%04X, index 0x%02X, error #%d, %s)", value, index, res, symbolic(urb_errlist, res)) return (res >= 0) ? 0 : -1; @@ -1095,7 +1115,7 @@ static int w9968cf_read_reg(struct w9968 if (res < 0) DBG(4, "Failed to read a register " - "(index 0x%02X, error #%d, %s).", + "(index 0x%02X, error #%d, %s)", index, res, symbolic(urb_errlist, res)) return (res >= 0) ? (int)(*buff) : -1; @@ -1120,7 +1140,7 @@ static int w9968cf_write_fsb(struct w996 if (res < 0) DBG(4, "Failed to write the FSB registers " - "(error #%d, %s).", res, symbolic(urb_errlist, res)) + "(error #%d, %s)", res, symbolic(urb_errlist, res)) return (res >= 0) ? 0 : -1; } @@ -1270,7 +1290,7 @@ static int w9968cf_smbus_read_ack(struct if (sda < 0) err += sda; if (sda == 1) { - DBG(6, "Couldn't receive the ACK.") + DBG(6, "Couldn't receive the ACK") err += -1; } @@ -1353,11 +1373,11 @@ w9968cf_i2c_adap_fastwrite_byte_data(str if (!err) DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " - "value 0x%02X.", address, subaddress, value) + "value 0x%02X", address, subaddress, value) else DBG(5, "I2C write byte data failed, addr.0x%04X, " - "subaddr.0x%02X, value 0x%02X.", - address, subaddress, value) + "subaddr.0x%02X, value 0x%02X", + address, subaddress, value) return err; } @@ -1392,11 +1412,11 @@ w9968cf_i2c_adap_read_byte_data(struct w if (!err) DBG(5, "I2C read byte data done, addr.0x%04X, " - "subaddr.0x%02X, value 0x%02X.", + "subaddr.0x%02X, value 0x%02X", address, subaddress, *value) else DBG(5, "I2C read byte data failed, addr.0x%04X, " - "subaddr.0x%02X, wrong value 0x%02X.", + "subaddr.0x%02X, wrong value 0x%02X", address, subaddress, *value) return err; @@ -1424,11 +1444,11 @@ w9968cf_i2c_adap_read_byte(struct w9968c err += w9968cf_write_sb(cam, 0x0000); if (!err) - DBG(5, "I2C read byte done, addr.0x%04X." - "value 0x%02X.", address, *value) + DBG(5, "I2C read byte done, addr.0x%04X, " + "value 0x%02X", address, *value) else - DBG(5, "I2C read byte failed, addr.0x%04X." - "wrong value 0x%02X.", address, *value) + DBG(5, "I2C read byte failed, addr.0x%04X, " + "wrong value 0x%02X", address, *value) return err; } @@ -1439,7 +1459,7 @@ static int w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, u16 address, u8 value) { - DBG(4, "i2c_write_byte() is an unsupported transfer mode.") + DBG(4, "i2c_write_byte() is an unsupported transfer mode") return -EINVAL; } @@ -1546,9 +1566,8 @@ static int w9968cf_i2c_detach_inform(str struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); const char* clientname = i2c_clientname(client); - if (cam->sensor_client == client) { + if (cam->sensor_client == client) cam->sensor_client = NULL; - } DBG(5, "I2C detach client [%s]", clientname) @@ -1593,9 +1612,9 @@ static int w9968cf_i2c_init(struct w9968 err = i2c_add_adapter(&cam->i2c_adapter); if (err) - DBG(1, "Failed to register the I2C adapter.") + DBG(1, "Failed to register the I2C adapter") else - DBG(5, "I2C adapter registered.") + DBG(5, "I2C adapter registered") return err; } @@ -1622,9 +1641,9 @@ static int w9968cf_turn_on_led(struct w9 err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ if (err) - DBG(2, "Couldn't turn on the LED.") + DBG(2, "Couldn't turn on the LED") - DBG(5, "LED turned on.") + DBG(5, "LED turned on") return err; } @@ -1637,6 +1656,13 @@ static int w9968cf_turn_on_led(struct w9 --------------------------------------------------------------------------*/ static int w9968cf_init_chip(struct w9968cf_device* cam) { + unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, + y0 = 0x0000, + u0 = y0 + hw_bufsize/2, + v0 = u0 + hw_bufsize/4, + y1 = v0 + hw_bufsize/4, + u1 = y1 + hw_bufsize/2, + v1 = u1 + hw_bufsize/4; int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ @@ -1645,23 +1671,25 @@ static int w9968cf_init_chip(struct w996 err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ - err += w9968cf_write_reg(cam, 0x0000, 0x20); /* Y frame buf.0, low */ - err += w9968cf_write_reg(cam, 0x0000, 0x21); /* Y frame buf.0, high */ - err += w9968cf_write_reg(cam, 0xb000, 0x22); /* Y frame buf.1, low */ - err += w9968cf_write_reg(cam, 0x0004, 0x23); /* Y frame buf.1, high */ - err += w9968cf_write_reg(cam, 0x5800, 0x24); /* U frame buf.0, low */ - err += w9968cf_write_reg(cam, 0x0002, 0x25); /* U frame buf.0, high */ - err += w9968cf_write_reg(cam, 0x0800, 0x26); /* U frame buf.1, low */ - err += w9968cf_write_reg(cam, 0x0007, 0x27); /* U frame buf.1, high */ - err += w9968cf_write_reg(cam, 0x8400, 0x28); /* V frame buf.0, low */ - err += w9968cf_write_reg(cam, 0x0003, 0x29); /* V frame buf.0, high */ - err += w9968cf_write_reg(cam, 0x3400, 0x2a); /* V frame buf.1, low */ - err += w9968cf_write_reg(cam, 0x0008, 0x2b); /* V frame buf.1, high */ - - err += w9968cf_write_reg(cam, 0x6000, 0x32); /* JPEG bitstream buf 0 */ - err += w9968cf_write_reg(cam, 0x0009, 0x33); /* JPEG bitstream buf 0 */ - err += w9968cf_write_reg(cam, 0x2000, 0x34); /* JPEG bitstream buf 1 */ - err += w9968cf_write_reg(cam, 0x000d, 0x35); /* JPEG bitstream buf 1 */ + err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ + err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ + err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ + err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ + err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ + err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ + + err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ + err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ + err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ + err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ + err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ + err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ + + err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ + err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ + + err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ + err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ @@ -1672,9 +1700,9 @@ static int w9968cf_init_chip(struct w996 err += w9968cf_set_window(cam, cam->window); if (err) - DBG(1, "Chip initialization failed.") + DBG(1, "Chip initialization failed") else - DBG(5, "Chip successfully initialized.") + DBG(5, "Chip successfully initialized") return err; } @@ -1736,8 +1764,8 @@ w9968cf_set_picture(struct w9968cf_devic break; } - /* FIXME: 'hardware double buffer' doesn't work when compressed video - is enabled (corrupted frames). */ + /* NOTE: due to memory issues, it is better to disable the hardware + double buffering during compression */ if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) reg_v |= 0x0080; @@ -1761,16 +1789,15 @@ w9968cf_set_picture(struct w9968cf_devic cam->hw_palette = hw_palette; /* Settings changed, so we clear the frame buffers */ - memset(cam->frame[0].buffer, 0, - cam->nbuffers*w9968cf_get_max_bufsize(cam)); + memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); - DBG(4, "Palette is %s, depth is %d bpp.", + DBG(4, "Palette is %s, depth is %u bpp", symbolic(v4l1_plist, pict.palette), pict.depth) return 0; error: - DBG(1, "Failed to change picture settings.") + DBG(1, "Failed to change picture settings") return err; } @@ -1921,21 +1948,20 @@ w9968cf_set_window(struct w9968cf_device cam->hw_height = h; /* Settings changed, so we clear the frame buffers */ - memset(cam->frame[0].buffer, 0, - cam->nbuffers*w9968cf_get_max_bufsize(cam)); + memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); - DBG(4, "The capture area is %dx%d, Offset (x,y)=(%d,%d).", + DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", win.width, win.height, win.x, win.y) - PDBGG("x=%d ,y=%d, w=%d, h=%d, ax=%d, ay=%d, s_win.x=%d, s_win.y=%d, " - "cw=%d, ch=%d, win.x=%d ,win.y=%d, win.width=%d, win.height=%d", + PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " + "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, win.width, win.height) return 0; error: - DBG(1, "Failed to change the capture area size.") + DBG(1, "Failed to change the capture area size") return err; } @@ -1959,7 +1985,7 @@ static inline u16 w9968cf_valid_palette( Return the depth corresponding to the given palette. Palette _must_ be supported ! --------------------------------------------------------------------------*/ -static u16 w9968cf_valid_depth(u16 palette) +static inline u16 w9968cf_valid_depth(u16 palette) { u8 i=0; while (w9968cf_formatlist[i].palette != palette) @@ -1996,10 +2022,12 @@ w9968cf_adjust_window_size(struct w9968c if ((*width < cam->minwidth) || (*height < cam->minheight)) return -ERANGE; - maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) - && w9968cf_vppmod_present ? W9968CF_MAX_WIDTH : cam->maxwidth; - maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) - && w9968cf_vppmod_present ? W9968CF_MAX_HEIGHT : cam->maxheight; + maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && + w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) + : cam->maxwidth; + maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && + w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) + : cam->maxheight; if (*width > maxw) *width = maxw; @@ -2011,7 +2039,7 @@ w9968cf_adjust_window_size(struct w9968c *height &= ~15L; } - PDBGG("Window size adjusted w=%d, h=%d ", *width, *height) + PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) return 0; } @@ -2050,7 +2078,7 @@ static void w9968cf_push_frame(struct w9 spin_unlock_irqrestore(&cam->flist_lock, lock_flags); - DBG(6, "Frame #%d pushed into the FIFO list. Position %d.", f_num, f) + DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) } @@ -2074,7 +2102,7 @@ w9968cf_pop_frame(struct w9968cf_device* spin_unlock(&cam->flist_lock); - DBG(6,"Popped frame #%zd from the list.",*framep-&cam->frame[0]) + DBG(6,"Popped frame #%d from the list", (*framep)->number) } @@ -2086,7 +2114,7 @@ static int w9968cf_postprocess_frame(struct w9968cf_device* cam, struct w9968cf_frame_t* fr) { - void *pIn = fr->buffer, *pOut = cam->vpp_buffer, *tmp; + void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; u16 w = cam->window.width, h = cam->window.height, d = cam->picture.depth, @@ -2102,41 +2130,41 @@ w9968cf_postprocess_frame(struct w9968cf if (cam->vpp_flag & VPP_DECOMPRESSION) { memcpy(pOut, pIn, fr->length); _PSWAP(pIn, pOut) - err = (*w9968cf_vpp_decode)(pIn, fr->length, hw_w, hw_h, pOut); - PDBGG("Compressed frame length: %li",(unsigned long)fr->length) + err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); + PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) fr->length = (hw_w*hw_h*hw_d)/8; _PSWAP(pIn, pOut) if (err) { DBG(4, "An error occurred while decoding the frame: " - "%s.", symbolic(decoder_errlist, err)) + "%s", symbolic(decoder_errlist, err)) return err; } else DBG(6, "Frame decoded") } if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { - (*w9968cf_vpp_swap_yuvbytes)(pIn, fr->length); - DBG(6, "Original UYVY component ordering changed.") + w9968cf_vpp->swap_yuvbytes(pIn, fr->length); + DBG(6, "Original UYVY component ordering changed") } if (cam->vpp_flag & VPP_UPSCALE) { - (*w9968cf_vpp_scale_up)(pIn, pOut, hw_w, hw_h, hw_d, w, h); + w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); fr->length = (w*h*hw_d)/8; _PSWAP(pIn, pOut) - DBG(6, "Vertical up-scaling done: %d,%d,%dbpp->%d,%d", + DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", hw_w, hw_h, hw_d, w, h) } if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { - (*w9968cf_vpp_uyvy_to_rgbx)(pIn, fr->length, pOut, fmt, rgb); + w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); fr->length = (w*h*d)/8; _PSWAP(pIn, pOut) - DBG(6, "UYVY-16bit to %s conversion done.", + DBG(6, "UYVY-16bit to %s conversion done", symbolic(v4l1_plist, fmt)) } if (pOut == fr->buffer) - memcpy(fr->buffer, cam->vpp_buffer, fr->length); + memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); return 0; } @@ -2144,7 +2172,7 @@ w9968cf_postprocess_frame(struct w9968cf /**************************************************************************** - * CMOS sensor control routines * + * Image sensor control routines * ****************************************************************************/ static int @@ -2184,17 +2212,17 @@ w9968cf_sensor_cmd(struct w9968cf_device struct i2c_client* c = cam->sensor_client; int rc = 0; - if (c->driver->command) { - rc = c->driver->command(cam->sensor_client, cmd, arg); - /* The I2C driver returns -EPERM on non-supported controls */ - return (rc < 0 && rc != -EPERM) ? rc : 0; - } else - return -ENODEV; + if (!c || !c->driver || !c->driver->command) + return -EINVAL; + + rc = c->driver->command(c, cmd, arg); + /* The I2C driver returns -EPERM on non-supported controls */ + return (rc < 0 && rc != -EPERM) ? rc : 0; } /*-------------------------------------------------------------------------- - Update some settings of the CMOS sensor. + Update some settings of the image sensor. Returns: 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/ static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) @@ -2242,7 +2270,7 @@ static int w9968cf_sensor_update_setting /*-------------------------------------------------------------------------- - Get some current picture settings from the CMOS sensor and update the + Get some current picture settings from the image sensor and update the internal 'picture' structure of the camera. Returns: 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/ @@ -2270,10 +2298,10 @@ static int w9968cf_sensor_get_picture(st return err; cam->picture.hue = v; - DBG(5, "Got picture settings from the CMOS sensor.") + DBG(5, "Got picture settings from the image sensor") PDBGG("Brightness, contrast, hue, colour, whiteness are " - "%d,%d,%d,%d,%d.", cam->picture.brightness,cam->picture.contrast, + "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, cam->picture.hue, cam->picture.colour, cam->picture.whiteness) return 0; @@ -2281,7 +2309,7 @@ static int w9968cf_sensor_get_picture(st /*-------------------------------------------------------------------------- - Update picture settings of the CMOS sensor. + Update picture settings of the image sensor. Returns: 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/ static int @@ -2296,7 +2324,7 @@ w9968cf_sensor_update_picture(struct w99 pict.contrast); if (err) goto fail; - DBG(4, "Contrast changed from %d to %d.", + DBG(4, "Contrast changed from %u to %u", cam->picture.contrast, pict.contrast) cam->picture.contrast = pict.contrast; } @@ -2307,7 +2335,7 @@ w9968cf_sensor_update_picture(struct w99 pict.brightness); if (err) goto fail; - DBG(4, "Brightness changed from %d to %d.", + DBG(4, "Brightness changed from %u to %u", cam->picture.brightness, pict.brightness) cam->picture.brightness = pict.brightness; } @@ -2317,7 +2345,7 @@ w9968cf_sensor_update_picture(struct w99 pict.colour); if (err) goto fail; - DBG(4, "Colour changed from %d to %d.", + DBG(4, "Colour changed from %u to %u", cam->picture.colour, pict.colour) cam->picture.colour = pict.colour; } @@ -2327,7 +2355,7 @@ w9968cf_sensor_update_picture(struct w99 pict.hue); if (err) goto fail; - DBG(4, "Hue changed from %d to %d.", + DBG(4, "Hue changed from %u to %u", cam->picture.hue, pict.hue) cam->picture.hue = pict.hue; } @@ -2335,7 +2363,7 @@ w9968cf_sensor_update_picture(struct w99 return 0; fail: - DBG(4, "Failed to change sensor picture setting.") + DBG(4, "Failed to change sensor picture setting") return err; } @@ -2346,7 +2374,7 @@ fail: ****************************************************************************/ /*-------------------------------------------------------------------------- - This function is called when a supported CMOS sensor is detected. + This function is called when a supported image sensor is detected. Return 0 if the initialization succeeds, a negative number otherwise. --------------------------------------------------------------------------*/ static int w9968cf_sensor_init(struct w9968cf_device* cam) @@ -2376,7 +2404,7 @@ static int w9968cf_sensor_init(struct w9 cam->minheight = 48; break; default: - DBG(1, "Not supported CMOS sensor detected for %s.", + DBG(1, "Not supported image sensor detected for %s", symbolic(camlist, cam->id)) return -EINVAL; } @@ -2386,7 +2414,7 @@ static int w9968cf_sensor_init(struct w9 case CC_OV7620: cam->start_cropx = 287; cam->start_cropy = 35; - /* Seems to work around a bug in the CMOS sensor */ + /* Seems to work around a bug in the image sensor */ cam->vs_polarity = 1; cam->hs_polarity = 1; break; @@ -2405,14 +2433,14 @@ static int w9968cf_sensor_init(struct w9 cam->sensor_initialized = 1; - DBG(2, "%s CMOS sensor initialized.", symbolic(senlist, cam->sensor)) + DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) return 0; error: cam->sensor_initialized = 0; cam->sensor = CC_UNKNOWN; - DBG(1, "CMOS sensor initialization failed for %s (/dev/video%d). " - "Try to detach and attach this device again.", + DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " + "Try to detach and attach this device again", symbolic(camlist, cam->id), cam->v4ldev->minor) return err; } @@ -2436,7 +2464,6 @@ w9968cf_configure_camera(struct w9968cf_ cam->users = 0; cam->disconnected = 0; - cam->usbdev = udev; cam->id = mod_id; cam->sensor = CC_UNKNOWN; cam->sensor_initialized = 0; @@ -2521,6 +2548,7 @@ w9968cf_configure_camera(struct w9968cf_ else cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; } + cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; @@ -2533,105 +2561,120 @@ w9968cf_configure_camera(struct w9968cf_ cam->window.clipcount = 0; cam->window.flags = 0; - /* If the video post-processing module is not present, some paramaters - must be overridden: */ - if (!w9968cf_vppmod_present) { - if (cam->decompression == 1) - cam->decompression = 2; - cam->upscaling = 0; - if (cam->picture.palette != VIDEO_PALETTE_UYVY) - cam->force_palette = 0; - cam->picture.palette = VIDEO_PALETTE_UYVY; - } - - cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); - - DBG(3, "%s configured with settings #%d:", + DBG(3, "%s configured with settings #%u:", symbolic(camlist, cam->id), dev_nr) - DBG(3, "- Data packet size for USB isochrnous transfer: %d bytes.", + DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", wMaxPacketSize[cam->altsetting-1]) - DBG(3, "- Number of requested video frame buffers: %d", + DBG(3, "- Number of requested video frame buffers: %u", cam->max_buffers) if (cam->double_buffer) - DBG(3, "- Hardware double buffering enabled.") + DBG(3, "- Hardware double buffering enabled") else - DBG(3, "- Hardware double buffering disabled.") + DBG(3, "- Hardware double buffering disabled") if (cam->filter_type == 0) - DBG(3, "- Video filtering disabled.") + DBG(3, "- Video filtering disabled") else if (cam->filter_type == 1) - DBG(3, "- Video filtering enabled: type 1-2-1.") + DBG(3, "- Video filtering enabled: type 1-2-1") else if (cam->filter_type == 2) - DBG(3, "- Video filtering enabled: type 2-3-6-3-2.") + DBG(3, "- Video filtering enabled: type 2-3-6-3-2") if (cam->clamping) - DBG(3, "- Video data clamping (CCIR-601 format) enabled.") + DBG(3, "- Video data clamping (CCIR-601 format) enabled") else - DBG(3, "- Video data clamping (CCIR-601 format) disabled.") + DBG(3, "- Video data clamping (CCIR-601 format) disabled") if (cam->largeview) - DBG(3, "- Large view enabled.") + DBG(3, "- Large view enabled") else - DBG(3, "- Large view disabled.") + DBG(3, "- Large view disabled") if ((cam->decompression) == 0 && (!cam->force_palette)) - DBG(3, "- Decompression disabled.") + DBG(3, "- Decompression disabled") else if ((cam->decompression) == 1 && (!cam->force_palette)) - DBG(3, "- Decompression forced.") + DBG(3, "- Decompression forced") else if ((cam->decompression) == 2 && (!cam->force_palette)) - DBG(3, "- Decompression allowed.") + DBG(3, "- Decompression allowed") if (cam->upscaling) - DBG(3, "- Software image scaling enabled.") + DBG(3, "- Software image scaling enabled") else - DBG(3, "- Software image scaling disabled.") + DBG(3, "- Software image scaling disabled") if (cam->force_palette) - DBG(3, "- Image palette forced to %s.", + DBG(3, "- Image palette forced to %s", symbolic(v4l1_plist, cam->picture.palette)) if (cam->force_rgb) - DBG(3, "- RGB component ordering will be used instead of BGR.") + DBG(3, "- RGB component ordering will be used instead of BGR") if (cam->auto_brt) - DBG(3, "- Auto brightness enabled.") + DBG(3, "- Auto brightness enabled") else - DBG(3, "- Auto brightness disabled.") + DBG(3, "- Auto brightness disabled") if (cam->auto_exp) - DBG(3, "- Auto exposure enabled.") + DBG(3, "- Auto exposure enabled") else - DBG(3, "- Auto exposure disabled.") + DBG(3, "- Auto exposure disabled") if (cam->backlight) - DBG(3, "- Backlight exposure algorithm enabled.") + DBG(3, "- Backlight exposure algorithm enabled") else - DBG(3, "- Backlight exposure algorithm disabled.") + DBG(3, "- Backlight exposure algorithm disabled") if (cam->mirror) - DBG(3, "- Mirror enabled.") + DBG(3, "- Mirror enabled") else - DBG(3, "- Mirror disabled.") + DBG(3, "- Mirror disabled") if (cam->bandfilt) - DBG(3, "- Banding filter enabled.") + DBG(3, "- Banding filter enabled") else - DBG(3, "- Banding filter disabled.") + DBG(3, "- Banding filter disabled") - DBG(3, "- Power lighting frequency: %d", cam->lightfreq) + DBG(3, "- Power lighting frequency: %u", cam->lightfreq) if (cam->clockdiv == -1) - DBG(3, "- Automatic clock divisor enabled.") + DBG(3, "- Automatic clock divisor enabled") else DBG(3, "- Clock divisor: %d", cam->clockdiv) if (cam->monochrome) - DBG(3, "- CMOS sensor used as monochrome.") + DBG(3, "- Image sensor used as monochrome") else - DBG(3, "- CMOS sensor not used as monochrome.") + DBG(3, "- Image sensor not used as monochrome") +} + + +/*-------------------------------------------------------------------------- + If the video post-processing module is not loaded, some parameters + must be overridden. + --------------------------------------------------------------------------*/ +static void w9968cf_adjust_configuration(struct w9968cf_device* cam) +{ + if (!w9968cf_vpp) { + if (cam->decompression == 1) { + cam->decompression = 2; + DBG(2, "Video post-processing module not found: " + "'decompression' parameter forced to 2") + } + if (cam->upscaling) { + cam->upscaling = 0; + DBG(2, "Video post-processing module not found: " + "'upscaling' parameter forced to 0") + } + if (cam->picture.palette != VIDEO_PALETTE_UYVY) { + cam->force_palette = 0; + DBG(2, "Video post-processing module not found: " + "'force_palette' parameter forced to 0") + } + cam->picture.palette = VIDEO_PALETTE_UYVY; + cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); + } } @@ -2654,8 +2697,6 @@ static void w9968cf_release_resources(st kfree(cam->data_buffer); up(&w9968cf_devlist_sem); - - DBG(5, "Resources released.") } @@ -2669,38 +2710,45 @@ static int w9968cf_open(struct inode* in struct w9968cf_device* cam; int err; + /* This the only safe way to prevent race conditions with disconnect */ + if (!down_read_trylock(&w9968cf_disconnect)) + return -ERESTARTSYS; + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); down(&cam->dev_sem); if (cam->sensor == CC_UNKNOWN) { - DBG(2, "No supported CMOS sensor has been detected by the " + DBG(2, "No supported image sensor has been detected by the " "'ovcamchip' module for the %s (/dev/video%d). Make " - "sure it is loaded *before* the 'w9968cf' module.", + "sure it is loaded *before* (re)connecting the camera.", symbolic(camlist, cam->id), cam->v4ldev->minor) up(&cam->dev_sem); + up_read(&w9968cf_disconnect); return -ENODEV; } if (cam->users) { - DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.", + DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { up(&cam->dev_sem); + up_read(&w9968cf_disconnect); return -EWOULDBLOCK; } -retry: up(&cam->dev_sem); - err = wait_event_interruptible(cam->open, cam->disconnected || - (cam->users == 0)); - if (err) + err = wait_event_interruptible_exclusive(cam->open, + cam->disconnected || + !cam->users); + if (err) { + up_read(&w9968cf_disconnect); return err; - if (cam->disconnected) + } + if (cam->disconnected) { + up_read(&w9968cf_disconnect); return -ENODEV; + } down(&cam->dev_sem); - /*recheck - there may be several waiters */ - if (cam->users) - goto retry; } DBG(5, "Opening '%s', /dev/video%d ...", @@ -2709,8 +2757,9 @@ retry: cam->streaming = 0; cam->misconfigured = 0; - if (!w9968cf_vppmod_present) - w9968cf_vppmod_detect(); + if (!w9968cf_vpp) + if ((err = w9968cf_vppmod_detect(cam))) + goto out; if ((err = w9968cf_allocate_memory(cam))) goto deallocate_memory; @@ -2728,15 +2777,19 @@ retry: init_waitqueue_head(&cam->wait_queue); + DBG(5, "Video device is open") + up(&cam->dev_sem); + up_read(&w9968cf_disconnect); - DBG(5, "Video device is open.") return 0; deallocate_memory: w9968cf_deallocate_memory(cam); - DBG(2, "Failed to open the video device.") +out: + DBG(2, "Failed to open the video device") up(&cam->dev_sem); + up_read(&w9968cf_disconnect); return err; } @@ -2751,6 +2804,8 @@ static int w9968cf_release(struct inode* w9968cf_stop_transfer(cam); + w9968cf_vppmod_release(cam); + if (cam->disconnected) { w9968cf_release_resources(cam); up(&cam->dev_sem); @@ -2760,10 +2815,9 @@ static int w9968cf_release(struct inode* cam->users--; w9968cf_deallocate_memory(cam); + wake_up_interruptible_nr(&cam->open, 1); - wake_up_interruptible(&cam->open); - - DBG(5, "Video device closed.") + DBG(5, "Video device closed") up(&cam->dev_sem); return 0; } @@ -2785,7 +2839,7 @@ w9968cf_read(struct file* filp, char __u return -ERESTARTSYS; if (cam->disconnected) { - DBG(2, "Device not present.") + DBG(2, "Device not present") up(&cam->fileop_sem); return -ENODEV; } @@ -2817,7 +2871,7 @@ w9968cf_read(struct file* filp, char __u fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; - if (w9968cf_vppmod_present) + if (w9968cf_vpp) w9968cf_postprocess_frame(cam, fr); if (count > fr->length) @@ -2832,7 +2886,7 @@ w9968cf_read(struct file* filp, char __u fr->status = F_UNUSED; - DBG(5, "%zd bytes read.", count) + DBG(5, "%zu bytes read", count) up(&cam->fileop_sem); return count; @@ -2844,25 +2898,25 @@ static int w9968cf_mmap(struct file* fil struct w9968cf_device* cam = (struct w9968cf_device*) video_get_drvdata(video_devdata(filp)); unsigned long vsize = vma->vm_end - vma->vm_start, - psize = cam->nbuffers * w9968cf_get_max_bufsize(cam), + psize = cam->nbuffers * cam->frame[0].size, start = vma->vm_start, pos = (unsigned long)cam->frame[0].buffer, page; if (cam->disconnected) { - DBG(2, "Device not present.") + DBG(2, "Device not present") return -ENODEV; } if (cam->misconfigured) { - DBG(2, "The camera is misconfigured. Close and open it again.") + DBG(2, "The camera is misconfigured. Close and open it again") return -EIO; } - PDBGG("mmapping %li bytes...", vsize) + PDBGG("mmapping %lu bytes...", vsize) - if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) - return -EAGAIN; + if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) + return -EINVAL; while (vsize > 0) { page = kvirt_to_pa(pos) + vma->vm_pgoff; @@ -2871,10 +2925,10 @@ static int w9968cf_mmap(struct file* fil return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; - vsize = (vsize > PAGE_SIZE) ? vsize-PAGE_SIZE : 0; + vsize -= PAGE_SIZE; } - DBG(5, "mmap method successfully called.") + DBG(5, "mmap method successfully called") return 0; } @@ -2892,7 +2946,7 @@ w9968cf_ioctl(struct inode* inode, struc return -ERESTARTSYS; if (cam->disconnected) { - DBG(2, "Device not present.") + DBG(2, "Device not present") up(&cam->fileop_sem); return -ENODEV; } @@ -2903,19 +2957,17 @@ w9968cf_ioctl(struct inode* inode, struc return -EIO; } - err = w9968cf_v4l_ioctl(inode, filp, cmd, (void* )arg); + err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); up(&cam->fileop_sem); return err; } -static int -w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, void* arg) +static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, void __user * arg) { struct w9968cf_device* cam; - void __user *user_arg = (void __user *)arg; const char* v4l1_ioctls[] = { "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", @@ -2944,22 +2996,24 @@ w9968cf_v4l_ioctl(struct inode* inode, s }; sprintf(cap.name, "W996[87]CF USB Camera #%d", cam->v4ldev->minor); - cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present) - ? W9968CF_MAX_WIDTH : cam->maxwidth; - cap.maxheight = (cam->upscaling && w9968cf_vppmod_present) - ? W9968CF_MAX_HEIGHT : cam->maxheight; + cap.maxwidth = (cam->upscaling && w9968cf_vpp) + ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) + : cam->maxwidth; + cap.maxheight = (cam->upscaling && w9968cf_vpp) + ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) + : cam->maxheight; - if (copy_to_user(user_arg, &cap, sizeof(cap))) + if (copy_to_user(arg, &cap, sizeof(cap))) return -EFAULT; - DBG(5, "VIDIOCGCAP successfully called.") + DBG(5, "VIDIOCGCAP successfully called") return 0; } case VIDIOCGCHAN: /* get video channel informations */ { struct video_channel chan; - if (copy_from_user(&chan, user_arg, sizeof(chan))) + if (copy_from_user(&chan, arg, sizeof(chan))) return -EFAULT; if (chan.channel != 0) @@ -2971,10 +3025,10 @@ w9968cf_v4l_ioctl(struct inode* inode, s chan.type = VIDEO_TYPE_CAMERA; chan.norm = VIDEO_MODE_AUTO; - if (copy_to_user(user_arg, &chan, sizeof(chan))) + if (copy_to_user(arg, &chan, sizeof(chan))) return -EFAULT; - DBG(5, "VIDIOCGCHAN successfully called.") + DBG(5, "VIDIOCGCHAN successfully called") return 0; } @@ -2982,13 +3036,13 @@ w9968cf_v4l_ioctl(struct inode* inode, s { struct video_channel chan; - if (copy_from_user(&chan, user_arg, sizeof(chan))) + if (copy_from_user(&chan, arg, sizeof(chan))) return -EFAULT; if (chan.channel != 0) return -EINVAL; - DBG(5, "VIDIOCSCHAN successfully called.") + DBG(5, "VIDIOCSCHAN successfully called") return 0; } @@ -2997,10 +3051,10 @@ w9968cf_v4l_ioctl(struct inode* inode, s if (w9968cf_sensor_get_picture(cam)) return -EIO; - if (copy_to_user(user_arg, &cam->picture, sizeof(cam->picture))) + if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) return -EFAULT; - DBG(5, "VIDIOCGPICT successfully called.") + DBG(5, "VIDIOCGPICT successfully called") return 0; } @@ -3009,19 +3063,19 @@ w9968cf_v4l_ioctl(struct inode* inode, s struct video_picture pict; int err = 0; - if (copy_from_user(&pict, user_arg, sizeof(pict))) + if (copy_from_user(&pict, arg, sizeof(pict))) return -EFAULT; - if ( (cam->force_palette || !w9968cf_vppmod_present) + if ( (cam->force_palette || !w9968cf_vpp) && pict.palette != cam->picture.palette ) { - DBG(4, "Palette %s rejected. Only %s is allowed.", + DBG(4, "Palette %s rejected: only %s is allowed", symbolic(v4l1_plist, pict.palette), symbolic(v4l1_plist, cam->picture.palette)) return -EINVAL; } if (!w9968cf_valid_palette(pict.palette)) { - DBG(4, "Palette %s not supported. VIDIOCSPICT failed.", + DBG(4, "Palette %s not supported. VIDIOCSPICT failed", symbolic(v4l1_plist, pict.palette)) return -EINVAL; } @@ -3030,14 +3084,14 @@ w9968cf_v4l_ioctl(struct inode* inode, s if (cam->decompression == 0) { if (w9968cf_need_decompression(pict.palette)) { DBG(4, "Decompression disabled: palette %s is not " - "allowed. VIDIOCSPICT failed.", + "allowed. VIDIOCSPICT failed", symbolic(v4l1_plist, pict.palette)) return -EINVAL; } } else if (cam->decompression == 1) { if (!w9968cf_need_decompression(pict.palette)) { DBG(4, "Decompression forced: palette %s is not " - "allowed. VIDIOCSPICT failed.", + "allowed. VIDIOCSPICT failed", symbolic(v4l1_plist, pict.palette)) return -EINVAL; } @@ -3045,8 +3099,8 @@ w9968cf_v4l_ioctl(struct inode* inode, s } if (pict.depth != w9968cf_valid_depth(pict.palette)) { - DBG(4, "Requested depth %d bpp is not valid for %s " - "palette: ignored and changed to %d bpp.", + DBG(4, "Requested depth %u bpp is not valid for %s " + "palette: ignored and changed to %u bpp", pict.depth, symbolic(v4l1_plist, pict.palette), w9968cf_valid_depth(pict.palette)) pict.depth = w9968cf_valid_depth(pict.palette); @@ -3079,7 +3133,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s return -EIO; - DBG(5, "VIDIOCSPICT successfully called.") + DBG(5, "VIDIOCSPICT successfully called") return 0; } @@ -3088,11 +3142,11 @@ w9968cf_v4l_ioctl(struct inode* inode, s struct video_window win; int err = 0; - if (copy_from_user(&win, user_arg, sizeof(win))) + if (copy_from_user(&win, arg, sizeof(win))) return -EFAULT; - DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%d, " - "x=%d, y=%d, %dx%d", win.clipcount, win.flags, + DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " + "x=%u, y=%u, %ux%u", win.clipcount, win.flags, win.x, win.y, win.width, win.height) if (win.clipcount != 0 || win.flags != 0) @@ -3100,8 +3154,8 @@ w9968cf_v4l_ioctl(struct inode* inode, s if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, (u16*)&win.height))) { - DBG(4, "Resolution not supported (%dx%d)." - "VIDIOCSWIN failed.", win.width, win.height) + DBG(4, "Resolution not supported (%ux%u). " + "VIDIOCSWIN failed", win.width, win.height) return err; } @@ -3142,10 +3196,10 @@ w9968cf_v4l_ioctl(struct inode* inode, s case VIDIOCGWIN: /* get current window properties */ { - if (copy_to_user(user_arg, &cam->window, sizeof(struct video_window))) + if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) return -EFAULT; - DBG(5, "VIDIOCGWIN successfully called.") + DBG(5, "VIDIOCGWIN successfully called") return 0; } @@ -3154,16 +3208,16 @@ w9968cf_v4l_ioctl(struct inode* inode, s struct video_mbuf mbuf; u8 i; - mbuf.size = cam->nbuffers * w9968cf_get_max_bufsize(cam); + mbuf.size = cam->nbuffers * cam->frame[0].size; mbuf.frames = cam->nbuffers; for (i = 0; i < cam->nbuffers; i++) mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - (unsigned long)cam->frame[0].buffer; - if (copy_to_user(user_arg, &mbuf, sizeof(mbuf))) + if (copy_to_user(arg, &mbuf, sizeof(mbuf))) return -EFAULT; - DBG(5, "VIDIOCGMBUF successfully called.") + DBG(5, "VIDIOCGMBUF successfully called") return 0; } @@ -3173,22 +3227,22 @@ w9968cf_v4l_ioctl(struct inode* inode, s struct w9968cf_frame_t* fr; int err = 0; - if (copy_from_user(&mmap, user_arg, sizeof(mmap))) + if (copy_from_user(&mmap, arg, sizeof(mmap))) return -EFAULT; - DBG(6, "VIDIOCMCAPTURE called: frame #%d, format=%s, %dx%d", + DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", mmap.frame, symbolic(v4l1_plist, mmap.format), mmap.width, mmap.height) if (mmap.frame >= cam->nbuffers) { - DBG(4, "Invalid frame number (%d). " - "VIDIOCMCAPTURE failed.", mmap.frame) + DBG(4, "Invalid frame number (%u). " + "VIDIOCMCAPTURE failed", mmap.frame) return -EINVAL; } if (mmap.format!=cam->picture.palette && - (cam->force_palette || !w9968cf_vppmod_present)) { - DBG(4, "Palette %s rejected. Only %s is allowed.", + (cam->force_palette || !w9968cf_vpp)) { + DBG(4, "Palette %s rejected: only %s is allowed", symbolic(v4l1_plist, mmap.format), symbolic(v4l1_plist, cam->picture.palette)) return -EINVAL; @@ -3196,7 +3250,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s if (!w9968cf_valid_palette(mmap.format)) { DBG(4, "Palette %s not supported. " - "VIDIOCMCAPTURE failed.", + "VIDIOCMCAPTURE failed", symbolic(v4l1_plist, mmap.format)) return -EINVAL; } @@ -3205,14 +3259,14 @@ w9968cf_v4l_ioctl(struct inode* inode, s if (cam->decompression == 0) { if (w9968cf_need_decompression(mmap.format)) { DBG(4, "Decompression disabled: palette %s is not " - "allowed. VIDIOCSPICT failed.", + "allowed. VIDIOCSPICT failed", symbolic(v4l1_plist, mmap.format)) return -EINVAL; } } else if (cam->decompression == 1) { if (!w9968cf_need_decompression(mmap.format)) { DBG(4, "Decompression forced: palette %s is not " - "allowed. VIDIOCSPICT failed.", + "allowed. VIDIOCSPICT failed", symbolic(v4l1_plist, mmap.format)) return -EINVAL; } @@ -3222,7 +3276,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, (u16*)&mmap.height))) { DBG(4, "Resolution not supported (%dx%d). " - "VIDIOCMCAPTURE failed.", + "VIDIOCMCAPTURE failed", mmap.width, mmap.height) return err; } @@ -3239,7 +3293,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s if(*cam->requested_frame || cam->frame_current->queued) { DBG(6, "VIDIOCMCAPTURE. Change settings for " - "frame #%d: %dx%d, format %s. Wait...", + "frame #%u: %dx%d, format %s. Wait...", mmap.frame, mmap.width, mmap.height, symbolic(v4l1_plist, mmap.format)) err = wait_event_interruptible @@ -3274,7 +3328,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s } else if (fr->queued) { - DBG(6, "Wait until frame #%d is free.", mmap.frame) + DBG(6, "Wait until frame #%u is free", mmap.frame) err = wait_event_interruptible(cam->wait_queue, cam->disconnected || @@ -3286,7 +3340,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s } w9968cf_push_frame(cam, mmap.frame); - DBG(5, "VIDIOCMCAPTURE(%d): successfully called.", mmap.frame) + DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) return 0; } @@ -3296,23 +3350,23 @@ w9968cf_v4l_ioctl(struct inode* inode, s struct w9968cf_frame_t* fr; int err = 0; - if (copy_from_user(&f_num, user_arg, sizeof(f_num))) + if (copy_from_user(&f_num, arg, sizeof(f_num))) return -EFAULT; if (f_num >= cam->nbuffers) { - DBG(4, "Invalid frame number (%d). " - "VIDIOCMCAPTURE failed.", f_num) + DBG(4, "Invalid frame number (%u). " + "VIDIOCMCAPTURE failed", f_num) return -EINVAL; } - DBG(6, "VIDIOCSYNC called for frame #%d", f_num) + DBG(6, "VIDIOCSYNC called for frame #%u", f_num) fr = &cam->frame[f_num]; switch (fr->status) { case F_UNUSED: if (!fr->queued) { - DBG(4, "VIDIOSYNC: Frame #%d not requested!", + DBG(4, "VIDIOSYNC: Frame #%u not requested!", f_num) return -EFAULT; } @@ -3330,12 +3384,12 @@ w9968cf_v4l_ioctl(struct inode* inode, s break; } - if (w9968cf_vppmod_present) + if (w9968cf_vpp) w9968cf_postprocess_frame(cam, fr); fr->status = F_UNUSED; - DBG(5, "VIDIOCSYNC(%d) successfully called.", f_num) + DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) return 0; } @@ -3349,10 +3403,10 @@ w9968cf_v4l_ioctl(struct inode* inode, s .teletext = VIDEO_NO_UNIT, }; - if (copy_to_user(user_arg, &unit, sizeof(unit))) + if (copy_to_user(arg, &unit, sizeof(unit))) return -EFAULT; - DBG(5, "VIDIOCGUNIT successfully called.") + DBG(5, "VIDIOCGUNIT successfully called") return 0; } @@ -3361,17 +3415,17 @@ w9968cf_v4l_ioctl(struct inode* inode, s case VIDIOCGFBUF: { - if (clear_user(user_arg, sizeof(struct video_buffer))) + if (clear_user(arg, sizeof(struct video_buffer))) return -EFAULT; - DBG(5, "VIDIOCGFBUF successfully called.") + DBG(5, "VIDIOCGFBUF successfully called") return 0; } case VIDIOCGTUNER: { struct video_tuner tuner; - if (copy_from_user(&tuner, user_arg, sizeof(tuner))) + if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; if (tuner.tuner != 0) @@ -3384,17 +3438,17 @@ w9968cf_v4l_ioctl(struct inode* inode, s tuner.mode = VIDEO_MODE_AUTO; tuner.signal = 0xffff; - if (copy_to_user(user_arg, &tuner, sizeof(tuner))) + if (copy_to_user(arg, &tuner, sizeof(tuner))) return -EFAULT; - DBG(5, "VIDIOCGTUNER successfully called.") + DBG(5, "VIDIOCGTUNER successfully called") return 0; } case VIDIOCSTUNER: { struct video_tuner tuner; - if (copy_from_user(&tuner, user_arg, sizeof(tuner))) + if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; if (tuner.tuner != 0) @@ -3403,7 +3457,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s if (tuner.mode != VIDEO_MODE_AUTO) return -EINVAL; - DBG(5, "VIDIOCSTUNER successfully called.") + DBG(5, "VIDIOCSTUNER successfully called") return 0; } @@ -3423,7 +3477,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s "(type 0x%01X, " "n. 0x%01X, " "dir. 0x%01X, " - "size 0x%02X).", + "size 0x%02X)", V4L1_IOCTL(cmd), _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) @@ -3434,7 +3488,7 @@ w9968cf_v4l_ioctl(struct inode* inode, s "type 0x%01X, " "n. 0x%01X, " "dir. 0x%01X, " - "size 0x%02X.", + "size 0x%02X", V4L1_IOCTL(cmd), _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) @@ -3480,15 +3534,27 @@ w9968cf_usb_probe(struct usb_interface* if (udev->descriptor.idVendor == winbond_id_table[0].idVendor && udev->descriptor.idProduct == winbond_id_table[0].idProduct) mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ - else if (udev->descriptor.idVendor == winbond_id_table[1].idVendor && udev->descriptor.idProduct == winbond_id_table[1].idProduct) mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ - else return -ENODEV; - DBG(2, "%s detected.", symbolic(camlist, mod_id)) + cam = (struct w9968cf_device*) + kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); + if (!cam) + return -ENOMEM; + + memset(cam, 0, sizeof(*cam)); + + init_MUTEX(&cam->dev_sem); + down(&cam->dev_sem); + + cam->usbdev = udev; + /* NOTE: a local copy is used to avoid possible race conditions */ + memcpy(&cam->dev, &udev->dev, sizeof(struct device)); + + DBG(2, "%s detected", symbolic(camlist, mod_id)) if (simcams > W9968CF_MAX_DEVICES) simcams = W9968CF_SIMCAMS; @@ -3501,27 +3567,15 @@ w9968cf_usb_probe(struct usb_interface* if (sc >= simcams) { DBG(2, "Device rejected: too many connected cameras " - "(max. %d)", simcams) - return -EPERM; - } - - cam = (struct w9968cf_device*) - kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); - - if (!cam) { - DBG(1, "Couldn't allocate %zd bytes of kernel memory.", - sizeof(struct w9968cf_device)) - err = -ENOMEM; + "(max. %u)", simcams) + err = -EPERM; goto fail; } - memset(cam, 0, sizeof(*cam)); - init_MUTEX(&cam->dev_sem); - down(&cam->dev_sem); /* Allocate 2 bytes of memory for camera control USB transfers */ if (!(cam->control_buffer = (u16*)kmalloc(2, GFP_KERNEL))) { - DBG(1,"Couldn't allocate memory for camera control transfers.") + DBG(1,"Couldn't allocate memory for camera control transfers") err = -ENOMEM; goto fail; } @@ -3530,7 +3584,7 @@ w9968cf_usb_probe(struct usb_interface* /* Allocate 8 bytes of memory for USB data transfers to the FSB */ if (!(cam->data_buffer = (u16*)kmalloc(8, GFP_KERNEL))) { DBG(1, "Couldn't allocate memory for data " - "transfers to the FSB.") + "transfers to the FSB") err = -ENOMEM; goto fail; } @@ -3539,7 +3593,7 @@ w9968cf_usb_probe(struct usb_interface* /* Register the V4L device */ cam->v4ldev = video_device_alloc(); if (!cam->v4ldev) { - DBG(1, "Could not allocate memory for a V4L structure.") + DBG(1, "Could not allocate memory for a V4L structure") err = -ENOMEM; goto fail; } @@ -3552,19 +3606,20 @@ w9968cf_usb_probe(struct usb_interface* cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); + cam->v4ldev->dev = &cam->dev; err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); if (err) { - DBG(1, "V4L device registration failed.") + DBG(1, "V4L device registration failed") if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(2, "Couldn't find a free /dev/videoX node.") + DBG(2, "Couldn't find a free /dev/videoX node") video_nr[dev_nr] = -1; dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; goto fail; } - DBG(2, "V4L device registered as /dev/video%d.", cam->v4ldev->minor) + DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) /* Set some basic constants */ w9968cf_configure_camera(cam, udev, mod_id, dev_nr); @@ -3579,22 +3634,19 @@ w9968cf_usb_probe(struct usb_interface* w9968cf_i2c_init(cam); - up(&cam->dev_sem); - usb_set_intfdata(intf, cam); + up(&cam->dev_sem); return 0; fail: /* Free unused memory */ - if (cam) { - if (cam->control_buffer) - kfree(cam->control_buffer); - if (cam->data_buffer) - kfree(cam->data_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - up(&cam->dev_sem); - kfree(cam); - } + if (cam->control_buffer) + kfree(cam->control_buffer); + if (cam->data_buffer) + kfree(cam->data_buffer); + if (cam->v4ldev) + video_device_release(cam->v4ldev); + up(&cam->dev_sem); + kfree(cam); return err; } @@ -3604,28 +3656,26 @@ static void w9968cf_usb_disconnect(struc struct w9968cf_device* cam = (struct w9968cf_device*)usb_get_intfdata(intf); + down_write(&w9968cf_disconnect); + if (cam) { /* Prevent concurrent accesses to data */ down(&cam->dev_sem); - cam->streaming = 0; cam->disconnected = 1; DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) - if (waitqueue_active(&cam->open)) - wake_up_interruptible(&cam->open); + wake_up_interruptible_all(&cam->open); if (cam->users) { DBG(2, "The device is open (/dev/video%d)! " "Process name: %s. Deregistration and memory " "deallocation are deferred on close.", cam->v4ldev->minor, cam->command) - cam->misconfigured = 1; - - if (waitqueue_active(&cam->wait_queue)) - wake_up_interruptible(&cam->wait_queue); + w9968cf_stop_transfer(cam); + wake_up_interruptible(&cam->wait_queue); } else w9968cf_release_resources(cam); @@ -3635,7 +3685,7 @@ static void w9968cf_usb_disconnect(struc kfree(cam); } - usb_set_intfdata(intf, NULL); + up_write(&w9968cf_disconnect); } @@ -3653,48 +3703,103 @@ static struct usb_driver w9968cf_usb_dri * Module init, exit and intermodule communication * ****************************************************************************/ -static int w9968cf_vppmod_detect(void) +static int w9968cf_vppmod_detect(struct w9968cf_device* cam) { - w9968cf_vpp_init_decoder = inter_module_get("w9968cf_init_decoder"); - - if (!w9968cf_vpp_init_decoder) { + if (!w9968cf_vpp) if (vppmod_load) - w9968cf_vpp_init_decoder = inter_module_get_request - ( "w9968cf_init_decoder", - "w9968cf-vpp" ); - if (!w9968cf_vpp_init_decoder) { - w9968cf_vppmod_present = 0; - DBG(4, "Video post-processing module not detected.") - return -ENODEV; - } + request_module("w9968cf-vpp"); + + down(&w9968cf_vppmod_lock); + + if (!w9968cf_vpp) { + DBG(4, "Video post-processing module not detected") + w9968cf_adjust_configuration(cam); + goto out; + } + + if (!try_module_get(w9968cf_vpp->owner)) { + DBG(1, "Couldn't increment the reference count of " + "the video post-processing module") + up(&w9968cf_vppmod_lock); + return -ENOSYS; } - w9968cf_vpp_check_headers = inter_module_get("w9968cf_check_headers"); - w9968cf_vpp_decode = inter_module_get("w9968cf_decode"); - w9968cf_vpp_swap_yuvbytes = inter_module_get("w9968cf_swap_yuvbytes"); - w9968cf_vpp_uyvy_to_rgbx = inter_module_get("w9968cf_uyvy_to_rgbx"); - w9968cf_vpp_scale_up = inter_module_get("w9968cf_scale_up"); + w9968cf_vpp->busy++; + + DBG(5, "Video post-processing module detected") + +out: + up(&w9968cf_vppmod_lock); + return 0; +} + + +static void w9968cf_vppmod_release(struct w9968cf_device* cam) +{ + down(&w9968cf_vppmod_lock); + + if (w9968cf_vpp && w9968cf_vpp->busy) { + module_put(w9968cf_vpp->owner); + w9968cf_vpp->busy--; + wake_up(&w9968cf_vppmod_wait); + DBG(5, "Video post-processing module released") + } + + up(&w9968cf_vppmod_lock); +} + + +int w9968cf_vppmod_register(struct w9968cf_vpp_t* vpp) +{ + down(&w9968cf_vppmod_lock); - w9968cf_vppmod_present = 1; + if (w9968cf_vpp) { + KDBG(1, "Video post-processing module already registered") + up(&w9968cf_vppmod_lock); + return -EINVAL; + } - /* Initialization */ - (*w9968cf_vpp_init_decoder)(); + w9968cf_vpp = vpp; + w9968cf_vpp->busy = 0; - DBG(2, "Video post-processing module detected.") + KDBG(2, "Video post-processing module registered") + up(&w9968cf_vppmod_lock); return 0; } -static void w9968cf_vppmod_release(void) +int w9968cf_vppmod_deregister(struct w9968cf_vpp_t* vpp) { - inter_module_put("w9968cf_init_decoder"); - inter_module_put("w9968cf_check_headers"); - inter_module_put("w9968cf_decode"); - inter_module_put("w9968cf_swap_yuvbytes"); - inter_module_put("w9968cf_uyvy_to_rgbx"); - inter_module_put("w9968cf_scale_up"); + down(&w9968cf_vppmod_lock); + + if (!w9968cf_vpp) { + up(&w9968cf_vppmod_lock); + return -EINVAL; + } - DBG(2, "Video post-processing module released.") + if (w9968cf_vpp != vpp) { + KDBG(1, "Only the owner can unregister the video " + "post-processing module") + up(&w9968cf_vppmod_lock); + return -EINVAL; + } + + if (w9968cf_vpp->busy) { + KDBG(2, "Video post-processing module busy. Wait for it to be " + "released...") + up(&w9968cf_vppmod_lock); + wait_event(w9968cf_vppmod_wait, !w9968cf_vpp->busy); + w9968cf_vpp = NULL; + goto out; + } + + w9968cf_vpp = NULL; + + up(&w9968cf_vppmod_lock); + +out: + KDBG(2, "Video post-processing module unregistered") + return 0; } @@ -3702,18 +3807,14 @@ static int __init w9968cf_module_init(vo { int err; - DBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) - DBG(3, W9968CF_MODULE_AUTHOR) - - init_MUTEX(&w9968cf_devlist_sem); + KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) + KDBG(3, W9968CF_MODULE_AUTHOR) - w9968cf_vppmod_detect(); + if (ovmod_load) + request_module("ovcamchip"); - if ((err = usb_register(&w9968cf_usb_driver))) { - if (w9968cf_vppmod_present) - w9968cf_vppmod_release(); + if ((err = usb_register(&w9968cf_usb_driver))) return err; - } return 0; } @@ -3724,12 +3825,13 @@ static void __exit w9968cf_module_exit(v /* w9968cf_usb_disconnect() will be called */ usb_deregister(&w9968cf_usb_driver); - if (w9968cf_vppmod_present) - w9968cf_vppmod_release(); - - DBG(2, W9968CF_MODULE_NAME" deregistered.") + KDBG(2, W9968CF_MODULE_NAME" deregistered") } module_init(w9968cf_module_init); module_exit(w9968cf_module_exit); + + +EXPORT_SYMBOL(w9968cf_vppmod_register); +EXPORT_SYMBOL(w9968cf_vppmod_deregister); --- linux-2.6.8-rc1/drivers/usb/media/w9968cf_externaldef.h 2004-02-03 20:42:37.000000000 -0800 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,94 +0,0 @@ -/*************************************************************************** - * Various definitions for compatibility with OVCAMCHIP external module. * - * This file is part of the W996[87]CF driver for Linux. * - * * - * The definitions have been taken from the OVCAMCHIP module written by * - * Mark McClelland. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _W9968CF_EXTERNALDEF_H_ -#define _W9968CF_EXTERNALDEF_H_ - -#include -#include -#include -#include - -#ifndef I2C_DRIVERID_OVCAMCHIP -# define I2C_DRIVERID_OVCAMCHIP 0xf00f -#endif - -/* Controls */ -enum { - OVCAMCHIP_CID_CONT, /* Contrast */ - OVCAMCHIP_CID_BRIGHT, /* Brightness */ - OVCAMCHIP_CID_SAT, /* Saturation */ - OVCAMCHIP_CID_HUE, /* Hue */ - OVCAMCHIP_CID_EXP, /* Exposure */ - OVCAMCHIP_CID_FREQ, /* Light frequency */ - OVCAMCHIP_CID_BANDFILT, /* Banding filter */ - OVCAMCHIP_CID_AUTOBRIGHT, /* Auto brightness */ - OVCAMCHIP_CID_AUTOEXP, /* Auto exposure */ - OVCAMCHIP_CID_BACKLIGHT, /* Back light compensation */ - OVCAMCHIP_CID_MIRROR, /* Mirror horizontally */ -}; - -/* I2C addresses */ -#define OV7xx0_SID (0x42 >> 1) -#define OV6xx0_SID (0xC0 >> 1) - -/* Sensor types */ -enum { - CC_UNKNOWN, - CC_OV76BE, - CC_OV7610, - CC_OV7620, - CC_OV7620AE, - CC_OV6620, - CC_OV6630, - CC_OV6630AE, - CC_OV6630AF, -}; - -/* API */ -struct ovcamchip_control { - __u32 id; - __s32 value; -}; - -struct ovcamchip_window { - int x; - int y; - int width; - int height; - int format; - int quarter; /* Scale width and height down 2x */ - - /* This stuff will be removed eventually */ - int clockdiv; /* Clock divisor setting */ -}; - -/* Commands. - You must call OVCAMCHIP_CMD_INITIALIZE before any of other commands */ -#define OVCAMCHIP_CMD_Q_SUBTYPE _IOR (0x88, 0x00, int) -#define OVCAMCHIP_CMD_INITIALIZE _IOW (0x88, 0x01, int) -#define OVCAMCHIP_CMD_S_CTRL _IOW (0x88, 0x02, struct ovcamchip_control) -#define OVCAMCHIP_CMD_G_CTRL _IOWR (0x88, 0x03, struct ovcamchip_control) -#define OVCAMCHIP_CMD_S_MODE _IOW (0x88, 0x04, struct ovcamchip_window) -#define OVCAMCHIP_MAX_CMD _IO (0x88, 0x3f) - -#endif /* _W9968CF_EXTERNALDEF_H_ */ --- linux-2.6.8-rc1/drivers/usb/media/w9968cf.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/media/w9968cf.h 2004-07-13 17:09:25.000000000 -0700 @@ -24,21 +24,26 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include -#include -#include "w9968cf_externaldef.h" +#include + +#include "w9968cf_vpp.h" /**************************************************************************** * Default values * ****************************************************************************/ +#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */ #define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */ /* Comment/uncomment the following line to enable/disable debugging messages */ @@ -95,8 +100,8 @@ static const struct w9968cf_format w9968 #define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */ -#define W9968CF_MAX_WIDTH 800 /* should be >= 640 */ -#define W9968CF_MAX_HEIGHT 600 /* should be >= 480 */ +#define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */ +#define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */ #define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */ #define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */ @@ -130,13 +135,11 @@ static const struct w9968cf_format w9968 #define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ "Dual Mode Camera Chip" -#define W9968CF_MODULE_VERSION "v1.25-basic" +#define W9968CF_MODULE_VERSION "1:1.32-basic" #define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia" #define W9968CF_AUTHOR_EMAIL "" #define W9968CF_MODULE_LICENSE "GPL" -static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */ - static const struct usb_device_id winbond_id_table[] = { { /* Creative Labs Video Blaster WebCam Go Plus */ @@ -151,18 +154,19 @@ static const struct usb_device_id winbon { } /* terminating entry */ }; -MODULE_DEVICE_TABLE(usb, winbond_id_table); - /* W996[87]CF camera models, internal ids: */ enum w9968cf_model_id { W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */ W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/ - W9968CF_MOD_ADPA5R = 21, /* Aroma Digi Pen ADG-5000 Refurbished */ - W9986CF_MOD_AU = 31, /* AVerTV USB */ - W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */ - W9968CF_MOD_DLLDK = 37, /* Die Lebon LDC-D35A Digital Kamera */ + W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */ + W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */ + W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */ + W9968CF_MOD_LL = 37, /* Lebon LDC-035A */ W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */ + W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */ W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */ + W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */ + W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */ }; enum w9968cf_frame_status { @@ -173,9 +177,10 @@ enum w9968cf_frame_status { }; struct w9968cf_frame_t { - #define W9968CF_HW_BUF_SIZE 640*480*2 /* buf.size of original frames */ void* buffer; + unsigned long size; u32 length; + int number; enum w9968cf_frame_status status; struct w9968cf_frame_t* next; u8 queued; @@ -189,12 +194,19 @@ enum w9968cf_vpp_flag { VPP_UYVY_TO_RGBX = 0x08, }; -static struct list_head w9968cf_dev_list; /* head of V4L registered cameras list */ -static LIST_HEAD(w9968cf_dev_list); -struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */ +static struct w9968cf_vpp_t* w9968cf_vpp; +static DECLARE_MUTEX(w9968cf_vppmod_lock); +static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); + +static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ +static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */ + +static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ /* Main device driver structure */ struct w9968cf_device { + struct device dev; /* device structure */ + enum w9968cf_model_id id; /* private device identifier */ struct video_device* v4ldev; /* -> V4L structure */ @@ -207,10 +219,10 @@ struct w9968cf_device { u16* data_buffer; /* -> data to send to the FSB */ struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS]; - struct w9968cf_frame_t frame_tmp; /* temporary frame */ + struct w9968cf_frame_t frame_tmp; /* temporary frame */ + struct w9968cf_frame_t frame_vpp; /* helper frame.*/ struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; - void* vpp_buffer; /*-> helper buf.for video post-processing routines */ u8 max_buffers, /* number of requested buffers */ force_palette, /* yes=1/no=0 */ @@ -233,7 +245,7 @@ struct w9968cf_device { hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ - start_cropy; /* pixels from VS incative edge to 1st cropped pixel*/ + start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/ enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ @@ -246,13 +258,13 @@ struct w9968cf_device { u8 sensor_initialized; /* flag: yes=1, no=0 */ - /* Determined by CMOS sensor type: */ + /* Determined by the image sensor type: */ int sensor, /* type of image sensor chip (CC_*) */ - monochrome; /* CMOS sensor is (probably) monochrome */ - u16 maxwidth, /* maximum width supported by the CMOS sensor */ - maxheight, /* maximum height supported by the CMOS sensor */ - minwidth, /* minimum width supported by the CMOS sensor */ - minheight; /* minimum height supported by the CMOS sensor */ + monochrome; /* image sensor is (probably) monochrome */ + u16 maxwidth, /* maximum width supported by the image sensor */ + maxheight, /* maximum height supported by the image sensor */ + minwidth, /* minimum width supported by the image sensor */ + minheight; /* minimum height supported by the image sensor */ u8 auto_brt, /* auto brightness enabled flag */ auto_exp, /* auto exposure enabled flag */ backlight, /* backlight exposure algorithm flag */ @@ -270,8 +282,9 @@ struct w9968cf_device { fileop_sem; /* for read and ioctl */ spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ flist_lock; /* for requested frame list accesses */ - char command[16]; /* name of the program holding the device */ wait_queue_head_t open, wait_queue; + + char command[16]; /* name of the program holding the device */ }; @@ -280,31 +293,47 @@ struct w9968cf_device { ****************************************************************************/ #undef DBG +#undef KDBG #ifdef W9968CF_DEBUG -# define DBG(level, fmt, args...) \ -{ \ -if ( ((specific_debug) && (debug == (level))) || \ - ((!specific_debug) && (debug >= (level))) ) { \ - if ((level) == 1) \ - err(fmt, ## args); \ - else if ((level) == 2 || (level) == 3) \ - info(fmt, ## args); \ - else if ((level) == 4) \ - warn(fmt, ## args); \ - else if ((level) >= 5) \ - info("[%s:%d] " fmt, \ - __FUNCTION__, __LINE__ , ## args); \ -} \ +/* For device specific debugging messages */ +# define DBG(level, fmt, args...) \ +{ \ + if ( ((specific_debug) && (debug == (level))) || \ + ((!specific_debug) && (debug >= (level))) ) { \ + if ((level) == 1) \ + dev_err(&cam->dev, fmt "\n", ## args); \ + else if ((level) == 2 || (level) == 3) \ + dev_info(&cam->dev, fmt "\n", ## args); \ + else if ((level) == 4) \ + dev_warn(&cam->dev, fmt "\n", ## args); \ + else if ((level) >= 5) \ + dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args); \ + } \ +} +/* For generic kernel (not device specific) messages */ +# define KDBG(level, fmt, args...) \ +{ \ + if ( ((specific_debug) && (debug == (level))) || \ + ((!specific_debug) && (debug >= (level))) ) { \ + if ((level) >= 1 && (level) <= 4) \ + pr_info("w9968cf: " fmt "\n", ## args); \ + else if ((level) >= 5) \ + pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \ + __LINE__ , ## args); \ + } \ } #else /* Not debugging: nothing */ # define DBG(level, fmt, args...) do {;} while(0); +# define KDBG(level, fmt, args...) do {;} while(0); #endif #undef PDBG +#define PDBG(fmt, args...) \ +dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); + #undef PDBGG -#define PDBG(fmt, args...) info("[%s:%d] "fmt, \ - __PRETTY_FUNCTION__, __LINE__ , ## args); #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ #endif /* _W9968CF_H_ */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/drivers/usb/media/w9968cf_vpp.h 2004-07-13 17:09:24.000000000 -0700 @@ -0,0 +1,43 @@ +/*************************************************************************** + * Interface for video post-processing functions for the W996[87]CF driver * + * for Linux. * + * * + * Copyright (C) 2002-2004 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _W9968CF_VPP_H_ +#define _W9968CF_VPP_H_ + +#include +#include + +struct w9968cf_vpp_t { + struct module* owner; + int (*check_headers)(const unsigned char*, const unsigned long); + int (*decode)(const char*, const unsigned long, const unsigned, + const unsigned, char*); + void (*swap_yuvbytes)(void*, unsigned long); + void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8); + void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16); + + u8 busy; /* read-only flag: module is/is not in use */ +}; + +extern int w9968cf_vppmod_register(struct w9968cf_vpp_t*); +extern int w9968cf_vppmod_deregister(struct w9968cf_vpp_t*); + +#endif /* _W9968CF_VPP_H_ */ --- linux-2.6.8-rc1/drivers/usb/misc/auerswald.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/misc/auerswald.c 2004-07-13 17:09:53.000000000 -0700 @@ -269,7 +269,7 @@ typedef struct /* Forwards */ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs); static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp); -extern struct usb_driver auerswald_driver; +static struct usb_driver auerswald_driver; /*-------------------------------------------------------------------*/ @@ -699,7 +699,7 @@ static int auerchain_control_msg (pauerc dr->wLength = cpu_to_le16 (size); usb_fill_control_urb (urb, dev, pipe, (unsigned char*)dr, data, size, /* build urb */ - auerchain_blocking_completion,0); + auerchain_blocking_completion,NULL); ret = auerchain_start_wait_urb (acp, urb, timeout, &length); usb_free_urb (urb); --- linux-2.6.8-rc1/drivers/usb/misc/emi26_fw.h 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/misc/emi26_fw.h 2004-07-13 17:09:24.000000000 -0700 @@ -12,6 +12,10 @@ * and which may not be reproduced, used, sold or transferred to * any third party without Emagic's written consent. All Rights Reserved. * + * Permission is hereby granted for the distribution of this firmware + * image as part of a Linux or other Open Source operating system kernel + * in text or binary form as required. + * * This firmware may not be modified and may only be used with the * Emagic EMI 2|6 Audio Interface. Distribution and/or Modification of * any driver which includes this firmware, in whole or in part, --- linux-2.6.8-rc1/drivers/usb/misc/speedtch.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/misc/speedtch.c 2004-07-13 17:09:13.000000000 -0700 @@ -1149,7 +1149,7 @@ static int udsl_usb_probe (struct usb_in } /* ATM init */ - if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) { + if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, NULL))) { dbg ("udsl_usb_probe: failed to register ATM device!"); goto fail; } --- linux-2.6.8-rc1/drivers/usb/misc/usbtest.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/misc/usbtest.c 2004-07-13 17:09:13.000000000 -0700 @@ -121,8 +121,8 @@ get_endpoints (struct usbtest_dev *dev, for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; - in = out = 0; - iso_in = iso_out = 0; + in = out = NULL; + iso_in = iso_out = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; @@ -216,11 +216,11 @@ static struct urb *simple_alloc_urb ( struct urb *urb; if (bytes < 0) - return 0; + return NULL; urb = usb_alloc_urb (0, SLAB_KERNEL); if (!urb) return urb; - usb_fill_bulk_urb (urb, udev, pipe, 0, bytes, simple_callback, 0); + usb_fill_bulk_urb (urb, udev, pipe, NULL, bytes, simple_callback, NULL); urb->interval = (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE; @@ -231,7 +231,7 @@ static struct urb *simple_alloc_urb ( &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); - urb = 0; + urb = NULL; } else memset (urb->transfer_buffer, 0, bytes); return urb; @@ -380,7 +380,7 @@ alloc_sglist (int nents, int max, int va sg = kmalloc (nents * sizeof *sg, SLAB_KERNEL); if (!sg) - return 0; + return NULL; memset (sg, 0, nents * sizeof *sg); for (i = 0; i < nents; i++) { @@ -389,7 +389,7 @@ alloc_sglist (int nents, int max, int va buf = kmalloc (size, SLAB_KERNEL); if (!buf) { free_sglist (sg, i); - return 0; + return NULL; } memset (buf, 0, size); @@ -637,7 +637,7 @@ static int ch9_postconfig (struct usbtes /* and sometimes [9.2.6.6] speed dependent descriptors */ if (udev->descriptor.bcdUSB == 0x0200) { /* pre-swapped */ - struct usb_qualifier_descriptor *d = 0; + struct usb_qualifier_descriptor *d = NULL; /* device qualifier [9.6.2] */ retval = usb_get_descriptor (udev, @@ -817,11 +817,11 @@ error: if ((status = usb_submit_urb (urb, SLAB_ATOMIC)) != 0) { dbg ("can't resubmit ctrl %02x.%02x, err %d", reqp->bRequestType, reqp->bRequest, status); - urb->dev = 0; + urb->dev = NULL; } else ctx->pending++; } else - urb->dev = 0; + urb->dev = NULL; /* signal completion when nothing's queued */ if (ctx->pending == 0) @@ -1368,7 +1368,7 @@ static struct urb *iso_alloc_urb ( unsigned i, maxp, packets; if (bytes < 0 || !desc) - return 0; + return NULL; maxp = 0x7ff & desc->wMaxPacketSize; maxp *= 1 + (0x3 & (desc->wMaxPacketSize >> 11)); packets = (bytes + maxp - 1) / maxp; @@ -1385,7 +1385,7 @@ static struct urb *iso_alloc_urb ( &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); - return 0; + return NULL; } memset (urb->transfer_buffer, 0, bytes); for (i = 0; i < packets; i++) { --- linux-2.6.8-rc1/drivers/usb/net/kaweth.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/net/kaweth.c 2004-07-13 17:09:13.000000000 -0700 @@ -1293,7 +1293,7 @@ static int kaweth_internal_control_msg(s return -ENOMEM; usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, - len, usb_api_blocking_completion,0); + len, usb_api_blocking_completion,NULL); retv = usb_start_wait_urb(urb, timeout, &length); if (retv < 0) { --- linux-2.6.8-rc1/drivers/usb/net/usbnet.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/net/usbnet.c 2004-07-13 17:09:24.000000000 -0700 @@ -316,7 +316,7 @@ get_endpoints (struct usbnet *dev, struc for (tmp = 0; tmp < intf->num_altsetting; tmp++) { unsigned ep; - in = out = 0; + in = out = NULL; alt = intf->altsetting + tmp; /* take the first altsetting with in-bulk + out-bulk; @@ -454,6 +454,15 @@ static const struct driver_info an2720_i #define AX_MCAST_FILTER_SIZE 8 #define AX_MAX_MCAST 64 +#define AX_INTERRUPT_BUFSIZE 8 + +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ +struct ax8817x_data { + u8 multi_filter[AX_MCAST_FILTER_SIZE]; + struct urb *int_urb; + u8 *int_buf; +}; + static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { @@ -496,6 +505,30 @@ static void ax8817x_async_cmd_callback(s usb_free_urb(urb); } +static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usbnet *dev = (struct usbnet *)urb->context; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + int link; + + if (urb->status < 0) { + printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d", + urb->status); + } else { + if (data->int_buf[5] == 0x90) { + link = data->int_buf[2] & 0x01; + if (netif_carrier_ok(dev->net) != link) { + if (link) + netif_carrier_on(dev->net); + else + netif_carrier_off(dev->net); + devdbg(dev, "ax8817x - Link Status is: %d", link); + } + } + usb_submit_urb(data->int_urb, GFP_KERNEL); + } +} + static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { @@ -535,6 +568,7 @@ static void ax8817x_write_cmd_async(stru static void ax8817x_set_multicast(struct net_device *net) { struct usbnet *dev = (struct usbnet *) net->priv; + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; u8 rx_ctl = 0x8c; if (net->flags & IFF_PROMISC) { @@ -549,25 +583,24 @@ static void ax8817x_set_multicast(struct * for our 8 byte filter buffer * to avoid allocating memory that * is tricky to free later */ - u8 *multi_filter = (u8 *)&dev->data; struct dev_mc_list *mc_list = net->mc_list; u32 crc_bits; int i; - memset(multi_filter, 0, AX_MCAST_FILTER_SIZE); + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ for (i = 0; i < net->mc_count; i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; - multi_filter[crc_bits >> 3] |= + data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); mc_list = mc_list->next; } ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, - AX_MCAST_FILTER_SIZE, multi_filter); + AX_MCAST_FILTER_SIZE, data->multi_filter); rx_ctl |= 0x10; } @@ -669,13 +702,6 @@ static void ax8817x_get_drvinfo (struct info->eedump_len = 0x3e; } -static u32 ax8817x_get_link (struct net_device *net) -{ - struct usbnet *dev = (struct usbnet *)net->priv; - - return (u32)mii_link_ok(&dev->mii); -} - static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = (struct usbnet *)net->priv; @@ -695,7 +721,7 @@ static int ax8817x_set_settings(struct n devices that may be connected at the same time. */ static struct ethtool_ops ax8817x_ethtool_ops = { .get_drvinfo = ax8817x_get_drvinfo, - .get_link = ax8817x_get_link, + .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = ax8817x_get_wol, @@ -709,13 +735,34 @@ static int ax8817x_bind(struct usbnet *d { int ret; u8 buf[6]; - u16 *buf16 = (u16 *) buf; int i; unsigned long gpio_bits = dev->driver_info->data; + struct ax8817x_data *data = (struct ax8817x_data *)dev->data; dev->in = usb_rcvbulkpipe(dev->udev, 3); dev->out = usb_sndbulkpipe(dev->udev, 2); + // allocate irq urb + if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { + dbg ("%s: cannot allocate interrupt URB", + dev->net->name); + return -ENOMEM; + } + + if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { + dbg ("%s: cannot allocate memory for interrupt buffer", + dev->net->name); + usb_free_urb(data->int_urb); + return -ENOMEM; + } + memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); + + usb_fill_int_urb (data->int_urb, dev->udev, + usb_rcvintpipe (dev->udev, 1), + data->int_buf, AX_INTERRUPT_BUFSIZE, + ax8817x_interrupt_complete, dev, + dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); + /* Toggle the GPIOs in a manufacturer/model specific way */ for (i = 2; i >= 0; i--) { if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, @@ -756,49 +803,37 @@ static int ax8817x_bind(struct usbnet *d dev->mii.reg_num_mask = 0x1f; dev->mii.phy_id = buf[1]; - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to go to software MII mode: %02x", ret); - return ret; - } - - *buf16 = cpu_to_le16(BMCR_RESET); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, - dev->mii.phy_id, MII_BMCR, 2, buf16)) < 0) { - dbg("Failed to write MII reg - MII_BMCR: %02x", ret); - return ret; - } - - /* Advertise that we can do full-duplex pause */ - *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, - dev->mii.phy_id, MII_ADVERTISE, - 2, buf16)) < 0) { - dbg("Failed to write MII_REG advertisement: %02x", ret); - return ret; - } + dev->net->set_multicast_list = ax8817x_set_multicast; + dev->net->ethtool_ops = &ax8817x_ethtool_ops; - *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, - dev->mii.phy_id, MII_BMCR, - 2, buf16)) < 0) { - dbg("Failed to write MII reg autonegotiate: %02x", ret); + ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, + cpu_to_le16(BMCR_RESET)); + ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400)); + mii_nway_restart(&dev->mii); + + if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { + dbg("Failed to submit interrupt URB: %02x", ret); + usb_free_urb(data->int_urb); return ret; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to set hardware MII: %02x", ret); - return ret; - } + return 0; +} - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax8817x_ethtool_ops; +static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct ax8817x_data *data = (struct ax8817x_data *)dev->data; - return 0; + usb_unlink_urb(data->int_urb); + usb_free_urb(data->int_urb); + kfree(data->int_buf); } static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", .bind = ax8817x_bind, + .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x00130103, }; @@ -806,6 +841,7 @@ static const struct driver_info ax8817x_ static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", .bind = ax8817x_bind, + .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x009f9d9f, }; @@ -813,6 +849,7 @@ static const struct driver_info dlink_du static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", .bind = ax8817x_bind, + .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x00130103, }; @@ -820,6 +857,7 @@ static const struct driver_info netgear_ static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", .bind = ax8817x_bind, + .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x001f1d1f, }; @@ -1086,7 +1124,7 @@ static void cdc_unbind (struct usbnet *d /* ensure immediate exit from usbnet_disconnect */ usb_set_intfdata(info->data, NULL); usb_driver_release_interface (&usbnet_driver, info->data); - info->data = 0; + info->data = NULL; } /* and vice versa (just in case) */ @@ -1094,7 +1132,7 @@ static void cdc_unbind (struct usbnet *d /* ensure immediate exit from usbnet_disconnect */ usb_set_intfdata(info->control, NULL); usb_driver_release_interface (&usbnet_driver, info->control); - info->control = 0; + info->control = NULL; } } @@ -1641,7 +1679,7 @@ nc_vendor_write (struct usbnet *dev, u8 req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, regnum, - 0, 0, // data is in setup packet + NULL, 0, // data is in setup packet CONTROL_TIMEOUT_JIFFIES); } @@ -2084,7 +2122,7 @@ pl_vendor_req (struct usbnet *dev, u8 re req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, val, index, - 0, 0, + NULL, 0, CONTROL_TIMEOUT_JIFFIES); } @@ -2418,7 +2456,7 @@ static void rx_complete (struct urb *urb skb_put (skb, urb->actual_length); entry->state = rx_done; - entry->urb = 0; + entry->urb = NULL; switch (urb_status) { // success @@ -2462,7 +2500,7 @@ static void rx_complete (struct urb *urb block: entry->state = rx_cleanup; entry->urb = urb; - urb = 0; + urb = NULL; break; // data overrun ... flush fifo? @@ -2557,7 +2595,7 @@ static int usbnet_stop (struct net_devic schedule_timeout (UNLINK_TIMEOUT_JIFFIES); devdbg (dev, "waited for %d urb completions", temp); } - dev->wait = 0; + dev->wait = NULL; remove_wait_queue (&unlink_wakeup, &wait); /* deferred work (task, timer, softirq) must also stop. @@ -2716,7 +2754,7 @@ kevent (void *data) /* tasklet could resubmit itself forever if memory is tight */ if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { - struct urb *urb = 0; + struct urb *urb = NULL; if (netif_running (dev->net)) urb = usb_alloc_urb (0, GFP_KERNEL); @@ -2771,7 +2809,7 @@ static void tx_complete (struct urb *urb } } - urb->dev = 0; + urb->dev = NULL; entry->state = tx_done; defer_bh (dev, skb); } @@ -2795,13 +2833,13 @@ static int usbnet_start_xmit (struct sk_ struct usbnet *dev = (struct usbnet *) net->priv; int length; int retval = NET_XMIT_SUCCESS; - struct urb *urb = 0; + struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; unsigned long flags; #ifdef CONFIG_USB_NET1080 - struct nc_header *header = 0; - struct nc_trailer *trailer = 0; + struct nc_header *header = NULL; + struct nc_trailer *trailer = NULL; #endif /* CONFIG_USB_NET1080 */ // some devices want funky USB-level framing, for @@ -3211,6 +3249,10 @@ static const struct usb_device_id produc // Buffalo LUA-U2-KTX USB_DEVICE (0x0411, 0x003d), .driver_info = (unsigned long) &ax8817x_info, +}, { + // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" + USB_DEVICE (0x6189, 0x182d), + .driver_info = (unsigned long) &ax8817x_info, }, #endif --- linux-2.6.8-rc1/drivers/usb/serial/belkin_sa.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/belkin_sa.c 2004-07-13 17:09:24.000000000 -0700 @@ -75,16 +75,11 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "belkin_sa.h" +static int debug; + /* * Version Information */ @@ -276,7 +271,7 @@ static void belkin_sa_read_int_callback goto exit; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* Handle known interrupt data */ /* ignore data[0] and data[1] */ @@ -614,6 +609,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/bus.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/bus.c 2004-07-13 17:09:24.000000000 -0700 @@ -14,13 +14,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" static int usb_serial_device_match (struct device *dev, struct device_driver *drv) --- linux-2.6.8-rc1/drivers/usb/serial/cyberjack.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/cyberjack.c 2004-07-13 17:09:24.000000000 -0700 @@ -35,16 +35,11 @@ #include #include #include +#include "usb-serial.h" #define CYBERJACK_LOCAL_BUF_SIZE 32 -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -#include "usb-serial.h" +static int debug; /* * Version Information @@ -243,7 +238,7 @@ static int cyberjack_write (struct usb_s memcpy (priv->wrbuf+priv->wrfilled, buf, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, priv->wrbuf+priv->wrfilled); priv->wrfilled += count; @@ -318,7 +313,7 @@ static void cyberjack_read_int_callback( if (urb->status) return; - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* React only to interrupts signaling a bulk_in transfer */ if( (urb->actual_length==4) && (data[0]==0x01) ) { @@ -374,14 +369,12 @@ static void cyberjack_read_bulk_callback dbg("%s - port %d", __FUNCTION__, port->number); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); if (urb->status) { - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); - tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { @@ -520,6 +513,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/digi_acceleport.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/digi_acceleport.c 2004-07-13 17:09:24.000000000 -0700 @@ -246,16 +246,8 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" - /* Defines */ /* @@ -480,6 +472,8 @@ static int digi_read_oob_callback( struc /* Statics */ +static int debug; + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, @@ -2068,6 +2062,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/empeg.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/empeg.c 2004-07-13 17:09:24.000000000 -0700 @@ -63,15 +63,10 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" +static int debug; + /* * Version Information */ @@ -249,7 +244,7 @@ static int empeg_write (struct usb_seria memcpy (urb->transfer_buffer, current_position, transfer_size); } - usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, urb->transfer_buffer); /* build up our urb */ usb_fill_bulk_urb ( @@ -365,7 +360,7 @@ static void empeg_read_bulk_callback (st return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); tty = port->tty; @@ -609,6 +604,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/ezusb.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/drivers/usb/serial/ezusb.c 2004-07-13 17:09:24.000000000 -0700 @@ -16,13 +16,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ @@ -35,7 +28,7 @@ int ezusb_writememory (struct usb_serial /* dbg("ezusb_writememory %x, %d", address, length); */ if (!serial->dev) { - dbg("%s - no physical device present, failing.", __FUNCTION__); + err("%s - no physical device present, failing.", __FUNCTION__); return -ENODEV; } @@ -52,12 +45,12 @@ int ezusb_writememory (struct usb_serial int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) { - int response; - dbg("%s - %d", __FUNCTION__, reset_bit); + int response; + + /* dbg("%s - %d", __FUNCTION__, reset_bit); */ response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { + if (response < 0) dev_err(&serial->dev->dev, "%s- %d failed\n", __FUNCTION__, reset_bit); - } return response; } --- linux-2.6.8-rc1/drivers/usb/serial/ftdi_sio.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/ftdi_sio.c 2004-07-13 17:09:24.000000000 -0700 @@ -253,12 +253,6 @@ #include #include #include -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "ftdi_sio.h" @@ -269,6 +263,8 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" +static int debug; + static struct usb_device_id id_table_sio [] = { { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { } /* Terminating entry */ @@ -1492,7 +1488,7 @@ static int ftdi_write (struct usb_serial } } - usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); /* fill the buffer and send it */ usb_fill_bulk_urb(urb, port->serial->dev, @@ -1658,7 +1654,7 @@ static void ftdi_process_read (struct us /* The first two bytes of every read packet are status */ if (urb->actual_length > 2) { - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); } else { dbg("Status only: %03oo %03oo",data[0],data[1]); } @@ -2241,6 +2237,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/serial/generic.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/generic.c 2004-07-13 17:09:24.000000000 -0700 @@ -19,16 +19,10 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" - +static int debug; + #ifdef CONFIG_USB_SERIAL_GENERIC static __u16 vendor = 0x05f9; static __u16 product = 0xffff; @@ -169,6 +163,7 @@ int usb_serial_generic_write (struct usb { struct usb_serial *serial = port->serial; int result; + unsigned char *data; dbg("%s - port %d", __FUNCTION__, port->number); @@ -193,8 +188,8 @@ int usb_serial_generic_write (struct usb else { memcpy (port->write_urb->transfer_buffer, buf, count); } - - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + data = port->write_urb->transfer_buffer; + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, data); /* set up our urb */ usb_fill_bulk_urb (port->write_urb, serial->dev, @@ -267,7 +262,7 @@ void usb_serial_generic_read_bulk_callba return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (tty && urb->actual_length) { --- linux-2.6.8-rc1/drivers/usb/serial/io_edgeport.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/io_edgeport.c 2004-07-13 17:09:24.000000000 -0700 @@ -259,15 +259,7 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" - #include "io_edgeport.h" #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ @@ -299,19 +291,13 @@ #define IMAGE_VERSION_NAME OperationalCodeImageVersion_GEN2 #include "io_fw_down2.h" /* Define array OperationalCodeImage[] */ - #define MAX_NAME_LEN 64 - #define CHASE_TIMEOUT (5*HZ) /* 5 seconds */ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ #define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ -#ifndef SERIAL_MAGIC - #define SERIAL_MAGIC 0x6702 -#endif -#define PORT_MAGIC 0x7301 - +static int debug; /* receive port state */ enum RXSTATE { @@ -793,7 +779,7 @@ static void edge_interrupt_callback (str // process this interrupt-read even if there are no ports open if (length) { - usb_serial_debug_data (__FILE__, __FUNCTION__, length, data); + usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, length, data); if (length > 1) { bytes_avail = data[0] | (data[1] << 8); @@ -869,7 +855,7 @@ static void edge_bulk_in_callback (struc if (urb->actual_length) { raw_data_length = urb->actual_length; - usb_serial_debug_data (__FILE__, __FUNCTION__, raw_data_length, data); + usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, raw_data_length, data); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; @@ -1327,7 +1313,7 @@ static int edge_write (struct usb_serial } else { memcpy(&fifo->fifo[fifo->head], data, firsthalf); } - usb_serial_debug_data (__FILE__, __FUNCTION__, firsthalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, firsthalf, &fifo->fifo[fifo->head]); // update the index and size fifo->head += firsthalf; @@ -1348,7 +1334,7 @@ static int edge_write (struct usb_serial } else { memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); } - usb_serial_debug_data (__FILE__, __FUNCTION__, secondhalf, &fifo->fifo[fifo->head]); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, secondhalf, &fifo->fifo[fifo->head]); // update the index and size fifo->count += secondhalf; fifo->head += secondhalf; @@ -1424,7 +1410,7 @@ static void send_more_port_data(struct e count = fifo->count; buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { - dev_err(&edge_serial->serial->dev->dev, "%s - no more kernel memory...\n", __FUNCTION__); + dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__); edge_port->write_in_progress = FALSE; return; } @@ -1448,9 +1434,8 @@ static void send_more_port_data(struct e fifo->count -= secondhalf; } - if (count) { - usb_serial_debug_data (__FILE__, __FUNCTION__, count, &buffer[2]); - } + if (count) + usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, count, &buffer[2]); /* fill up the urb with all of our data and submit it */ usb_fill_bulk_urb (urb, edge_serial->serial->dev, @@ -2443,7 +2428,7 @@ static int write_cmd_usb (struct edgepor struct urb *urb; int timeout; - usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); + usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, length, buffer); /* Allocate our next urb */ urb = usb_alloc_urb (0, GFP_ATOMIC); @@ -3074,6 +3059,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/io_ti.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/io_ti.c 2004-07-13 17:09:24.000000000 -0700 @@ -35,19 +35,13 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" - #include "io_16654.h" #include "io_usbvend.h" #include "io_ti.h" +static int debug; + /* * Version Information */ @@ -315,8 +309,8 @@ static int TIReadDownloadMemory(struct u } if (read_length > 1) { - usb_serial_debug_data (__FILE__, __FUNCTION__, - read_length, buffer); + usb_serial_debug_data(debug, &dev->dev, __FUNCTION__, + read_length, buffer); } /* Update pointers/length */ @@ -357,7 +351,7 @@ static int TIReadBootMemory (struct edge } dbg ("%s - start_address = %x, length = %d", __FUNCTION__, start_address, length); - usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); + usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer); serial->TiReadI2C = 1; @@ -390,7 +384,7 @@ static int TIWriteBootMemory (struct edg } dbg ("%s - start_sddr = %x, length = %d", __FUNCTION__, start_address, length); - usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); + usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, length, buffer); return status; } @@ -412,7 +406,7 @@ static int TIWriteDownloadI2C (struct ed write_length = length; dbg ("%s - BytesInFirstPage Addr = %x, length = %d", __FUNCTION__, start_address, write_length); - usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer); + usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer); /* Write first page */ be_start_address = cpu_to_be16 (start_address); @@ -439,7 +433,7 @@ static int TIWriteDownloadI2C (struct ed write_length = length; dbg ("%s - Page Write Addr = %x, length = %d", __FUNCTION__, start_address, write_length); - usb_serial_debug_data (__FILE__, __FUNCTION__, write_length, buffer); + usb_serial_debug_data(debug, &serial->serial->dev->dev, __FUNCTION__, write_length, buffer); /* Write next page */ be_start_address = cpu_to_be16 (start_address); @@ -1669,7 +1663,7 @@ static void edge_interrupt_callback (str goto exit; } - usb_serial_debug_data (__FILE__, __FUNCTION__, length, data); + usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, __FUNCTION__, length, data); if (length != 2) { dbg ("%s - expecting packet of size 2, got %d", __FUNCTION__, length); @@ -1761,7 +1755,7 @@ static void edge_bulk_in_callback (struc tty = edge_port->port->tty; if (tty && urb->actual_length) { - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, urb->actual_length, data); if (edge_port->close_pending) { dbg ("%s - close is pending, dropping data on the floor.", __FUNCTION__); @@ -2045,7 +2039,7 @@ static int edge_write (struct usb_serial memcpy (port->write_urb->transfer_buffer, data, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); /* set up our urb */ usb_fill_bulk_urb (port->write_urb, port->serial->dev, @@ -2684,9 +2678,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -MODULE_PARM(ignore_cpu_rev, "i"); +module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); --- linux-2.6.8-rc1/drivers/usb/serial/ipaq.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/ipaq.c 2004-07-13 17:09:24.000000000 -0700 @@ -56,13 +56,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug = 0; -#endif - #include "usb-serial.h" #include "ipaq.h" @@ -76,7 +69,8 @@ #define DRIVER_AUTHOR "Ganesh Varadarajan " #define DRIVER_DESC "USB PocketPC PDA driver" -static int product, vendor; +static __u16 product, vendor; +static int debug; /* Function prototypes for an ipaq */ static int ipaq_open (struct usb_serial_port *port, struct file *filp); @@ -315,7 +309,7 @@ static void ipaq_read_bulk_callback(stru return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (tty && urb->actual_length) { @@ -396,7 +390,7 @@ static int ipaq_write_bulk(struct usb_se } else { memcpy(pkt->data, buf, count); } - usb_serial_debug_data(__FILE__, __FUNCTION__, count, pkt->data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, pkt->data); pkt->len = count; pkt->written = 0; @@ -579,11 +573,11 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -MODULE_PARM(vendor, "h"); +module_param(vendor, ushort, 0); MODULE_PARM_DESC(vendor, "User specified USB idVendor"); -MODULE_PARM(product, "h"); +module_param(product, ushort, 0); MODULE_PARM_DESC(product, "User specified USB idProduct"); --- linux-2.6.8-rc1/drivers/usb/serial/ir-usb.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/ir-usb.c 2004-07-13 17:09:24.000000000 -0700 @@ -58,13 +58,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" /* @@ -101,9 +94,11 @@ struct irda_class_desc { u8 bMaxUnicastList; } __attribute__ ((packed)); +static int debug; + /* if overridden by the user, then use their value for the size of the read and * write urbs */ -static int buffer_size = 0; +static int buffer_size; /* if overridden by the user, then use the specified number of XBOFs */ static int xbof = -1; @@ -404,7 +399,8 @@ static void ir_write_bulk_callback (stru } usb_serial_debug_data ( - __FILE__, + debug, + &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer); @@ -439,7 +435,8 @@ static void ir_read_bulk_callback (struc ir_baud = *data & 0x0f; usb_serial_debug_data ( - __FILE__, + debug, + &port->dev, __FUNCTION__, urb->actual_length, data); @@ -614,10 +611,10 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -MODULE_PARM(xbof, "i"); +module_param(xbof, int, 0); MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); -MODULE_PARM(buffer_size, "i"); +module_param(buffer_size, int, 0); MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); --- linux-2.6.8-rc1/drivers/usb/serial/Kconfig 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/Kconfig 2004-07-13 17:09:24.000000000 -0700 @@ -20,13 +20,6 @@ config USB_SERIAL To compile this driver as a module, choose M here: the module will be called usbserial. -config USB_SERIAL_DEBUG - bool "USB Serial Converter verbose debug" - depends on USB_SERIAL=y - help - Say Y here if you want verbose debug messages from the USB Serial - Drivers sent to the kernel debug log. - config USB_SERIAL_CONSOLE bool "USB Serial Console device support (EXPERIMENTAL)" depends on USB_SERIAL=y && EXPERIMENTAL --- linux-2.6.8-rc1/drivers/usb/serial/keyspan.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/keyspan.c 2004-07-13 17:09:24.000000000 -0700 @@ -107,20 +107,12 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; - #define DEBUG -#else - static int debug; - #undef DEBUG -#endif - #include - #include "usb-serial.h" #include "keyspan.h" +static int debug; + /* * Version Information */ @@ -1175,7 +1167,7 @@ static void keyspan_close(struct usb_ser stop_urb(p_priv->out_urbs[i]); } } - port->tty = 0; + port->tty = NULL; } @@ -2362,6 +2354,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/serial/keyspan_pda.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/keyspan_pda.c 2004-07-13 17:09:24.000000000 -0700 @@ -80,12 +80,7 @@ #include #include -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - +static int debug; struct ezusb_hex_record { __u16 address; @@ -781,7 +776,7 @@ static int keyspan_pda_startup (struct u usb_set_serial_port_data(serial->port[0], priv); init_waitqueue_head(&serial->port[0]->write_wait); INIT_WORK(&priv->wakeup_work, (void *)keyspan_pda_wakeup_write, - (void *)(&serial->port[0])); + (void *)(serial->port[0])); INIT_WORK(&priv->unthrottle_work, (void *)keyspan_pda_request_unthrottle, (void *)(serial)); @@ -909,6 +904,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/serial/kl5kusb105.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/kl5kusb105.c 2004-07-13 17:09:24.000000000 -0700 @@ -56,16 +56,10 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "kl5kusb105.h" +static int debug; /* * Version Information @@ -659,7 +653,8 @@ static void klsi_105_read_bulk_callback } else if (urb->actual_length <= 2) { dbg("%s - size %d URB not understood", __FUNCTION__, urb->actual_length); - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, + urb->actual_length, data); } else { int i; int bytes_sent = ((__u8 *) data)[0] + @@ -671,8 +666,8 @@ static void klsi_105_read_bulk_callback * intermixed tty_flip_buffer_push()s * FIXME */ - usb_serial_debug_data (__FILE__, __FUNCTION__, - urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, + urb->actual_length, data); if (bytes_sent + 2 > urb->actual_length) { dbg("%s - trying to read more data than available" @@ -1051,11 +1046,7 @@ MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "enable extensive debugging messages"); -/* FIXME: implement -MODULE_PARM(num_urbs, "i"); -MODULE_PARM_DESC(num_urbs, "number of URBs to use in write pool"); -*/ /* vim: set sts=8 ts=8 sw=8: */ --- linux-2.6.8-rc1/drivers/usb/serial/kobil_sct.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/kobil_sct.c 2004-07-13 17:09:24.000000000 -0700 @@ -48,18 +48,10 @@ #include #include #include - - +#include "usb-serial.h" #include "kobil_sct.h" -//#include "../core/usb-debug.c" -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -#include "usb-serial.h" +static int debug; /* Version Information */ #define DRIVER_VERSION "21/05/2004" @@ -361,7 +353,7 @@ static void kobil_close (struct usb_seri if (port->write_urb){ usb_unlink_urb( port->write_urb ); usb_free_urb( port->write_urb ); - port->write_urb = 0; + port->write_urb = NULL; } if (port->interrupt_in_urb){ usb_unlink_urb (port->interrupt_in_urb); @@ -456,7 +448,7 @@ static int kobil_write (struct usb_seria memcpy (priv->buf + priv->filled, buf, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->buf + priv->filled); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, priv->buf + priv->filled); priv->filled = priv->filled + count; @@ -788,5 +780,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE( "GPL" ); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/serial/Makefile 2003-06-14 12:17:59.000000000 -0700 +++ 25/drivers/usb/serial/Makefile 2004-07-13 17:09:24.000000000 -0700 @@ -9,25 +9,26 @@ obj-$(CONFIG_USB_SERIAL) += usbserial. usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE) += console.o usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o -obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o -obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o -obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o -obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o -obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o -obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o -obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o +usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) + obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o -obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o -obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o +obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o -obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o -obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o -obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o +obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o +obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o +obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o +obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o +obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o +obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o +obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o +obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o +obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o +obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o +obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o -usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y) --- linux-2.6.8-rc1/drivers/usb/serial/mct_u232.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/drivers/usb/serial/mct_u232.c 2004-07-13 17:09:24.000000000 -0700 @@ -76,17 +76,9 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "mct_u232.h" - /* * Version Information */ @@ -105,6 +97,8 @@ static int write_blocking; /* disabled by default */ #endif +static int debug; + /* * Function prototypes */ @@ -523,7 +517,7 @@ static int mct_u232_write (struct usb_se while (count > 0) { size = (count > port->bulk_out_size) ? port->bulk_out_size : count; - usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, size, buf); if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) { @@ -631,7 +625,7 @@ static void mct_u232_read_int_callback ( return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here @@ -912,11 +906,11 @@ MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); #ifdef FIX_WRITE_RETURN_CODE_PROBLEM -MODULE_PARM(write_blocking, "i"); +module_param(write_blocking, int, 0); MODULE_PARM_DESC(write_blocking, "The write function will block to write out all data"); #endif -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/serial/omninet.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/omninet.c 2004-07-13 17:09:24.000000000 -0700 @@ -47,15 +47,9 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" +static int debug; /* * Version Information @@ -280,7 +274,7 @@ static int omninet_write (struct usb_ser memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, wport->write_urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, wport->write_urb->transfer_buffer); header->oh_seq = od->od_outseq++; header->oh_len = count; @@ -373,6 +367,5 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - --- linux-2.6.8-rc1/drivers/usb/serial/pl2303.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/pl2303.c 2004-07-13 17:09:24.000000000 -0700 @@ -49,13 +49,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "pl2303.h" @@ -65,7 +58,7 @@ #define DRIVER_VERSION "v0.11" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" - +static int debug; static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, @@ -251,7 +244,7 @@ static int pl2303_write (struct usb_seri memcpy (port->write_urb->transfer_buffer, buf, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; @@ -716,7 +709,7 @@ static void pl2303_read_int_callback (st } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer); if (urb->actual_length < UART_STATE) goto exit; @@ -770,7 +763,7 @@ static void pl2303_read_bulk_callback (s return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* get tty_flag from status */ tty_flag = TTY_NORMAL; --- linux-2.6.8-rc1/drivers/usb/serial/safe_serial.c 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/safe_serial.c 2004-07-13 17:09:24.000000000 -0700 @@ -72,18 +72,14 @@ #include #include #include +#include "usb-serial.h" -#ifndef CONFIG_USB_SERIAL_DEBUG -#define CONFIG_USB_SERIAL_DEBUG 0 -#endif #ifndef CONFIG_USB_SAFE_PADDED #define CONFIG_USB_SAFE_PADDED 0 #endif -static int debug = CONFIG_USB_SERIAL_DEBUG; -#include "usb-serial.h" // must follow the declaration of debug - +static int debug; static int safe = 1; static int padded = CONFIG_USB_SAFE_PADDED; @@ -102,19 +98,20 @@ MODULE_LICENSE("GPL"); #if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) static __u16 vendor; // no default static __u16 product; // no default -MODULE_PARM (vendor, "i"); -MODULE_PARM (product, "i"); -MODULE_PARM_DESC (vendor, "User specified USB idVendor (required)"); -MODULE_PARM_DESC (product, "User specified USB idProduct (required)"); +module_param(vendor, ushort, 0); +MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); +module_param(product, ushort, 0); +MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); #endif -MODULE_PARM (debug, "i"); -MODULE_PARM (safe, "i"); -MODULE_PARM (padded, "i"); - -MODULE_PARM_DESC (debug, "Debug enabled or not"); -MODULE_PARM_DESC (safe, "Turn Safe Encapsulation On/Off"); -MODULE_PARM_DESC (padded, "Pad to full wMaxPacketSize On/Off"); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +module_param(safe, bool, 0); +MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); + +module_param(padded, bool, 0); +MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off"); #define CDC_DEVICE_CLASS 0x02 @@ -346,7 +343,7 @@ static int safe_write (struct usb_serial port->write_urb->transfer_buffer_length = count; } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); #ifdef ECHO_TX { int i; --- linux-2.6.8-rc1/drivers/usb/serial/usb-serial.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/usb-serial.c 2004-07-13 17:09:24.000000000 -0700 @@ -336,14 +336,6 @@ #include #include #include - - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "pl2303.h" @@ -354,7 +346,6 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" - /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .owner = THIS_MODULE, @@ -370,10 +361,10 @@ static struct usb_driver usb_serial_driv drivers depend on it. */ -static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ +static int debug; +static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ static LIST_HEAD(usb_serial_driver_list); - struct usb_serial *usb_serial_get_by_index(unsigned index) { struct usb_serial *serial = serial_table[index]; --- linux-2.6.8-rc1/drivers/usb/serial/usb-serial.h 2004-06-15 23:29:43.000000000 -0700 +++ 25/drivers/usb/serial/usb-serial.h 2004-07-13 17:09:24.000000000 -0700 @@ -294,21 +294,21 @@ extern struct usb_serial_device_type usb extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; -static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data) +static inline void usb_serial_debug_data(int debug, + struct device *dev, + const char *function, int size, + const unsigned char *data) { int i; - if (!debug) - return; - - printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); + if (debug) { + dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size); + for (i = 0; i < size; ++i) + printk ("%.2x ", data[i]); + printk ("\n"); } - printk ("\n"); } - /* Use our own dbg macro */ #undef dbg #define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0) --- linux-2.6.8-rc1/drivers/usb/serial/visor.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/visor.c 2004-07-13 17:09:24.000000000 -0700 @@ -155,13 +155,6 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "visor.h" @@ -195,6 +188,7 @@ static int palm_os_3_probe (struct usb_s static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_id *id); /* Parameters that may be passed into the module. */ +static int debug; static __u16 vendor; static __u16 product; @@ -504,7 +498,7 @@ static int visor_write (struct usb_seria memcpy (buffer, buf, count); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer); usb_fill_bulk_urb (urb, serial->dev, usb_sndbulkpipe (serial->dev, @@ -590,7 +584,7 @@ static void visor_read_bulk_callback (st return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (tty && urb->actual_length) { @@ -621,6 +615,7 @@ static void visor_read_bulk_callback (st static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs) { + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; int result; switch (urb->status) { @@ -647,8 +642,8 @@ static void visor_read_int_callback (str * Rumor has it this endpoint is used to notify when data * is ready to be read from the bulk ones. */ - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, - urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, + urb->actual_length, urb->transfer_buffer); exit: result = usb_submit_urb (urb, GFP_ATOMIC); @@ -799,7 +794,8 @@ static int palm_os_4_probe (struct usb_s dev_err(dev, "%s - error %d getting connection info\n", __FUNCTION__, retval); else - usb_serial_debug_data (__FILE__, __FUNCTION__, retval, transfer_buffer); + usb_serial_debug_data(debug, &serial->dev->dev, __FUNCTION__, + retval, transfer_buffer); kfree (transfer_buffer); return 0; --- linux-2.6.8-rc1/drivers/usb/serial/whiteheat.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/serial/whiteheat.c 2004-07-13 17:09:24.000000000 -0700 @@ -80,17 +80,12 @@ #include #include #include - -#ifdef CONFIG_USB_SERIAL_DEBUG - static int debug = 1; -#else - static int debug; -#endif - #include "usb-serial.h" #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ #include "whiteheat.h" /* WhiteHEAT specific commands */ +static int debug; + #ifndef CMSPAR #define CMSPAR 0 #endif @@ -747,7 +742,7 @@ static int whiteheat_write(struct usb_se memcpy (urb->transfer_buffer, buf + sent, bytes); } - usb_serial_debug_data (__FILE__, __FUNCTION__, bytes, urb->transfer_buffer); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, bytes, urb->transfer_buffer); urb->dev = serial->dev; urb->transfer_buffer_length = bytes; @@ -975,10 +970,6 @@ static void command_port_write_callback dbg ("nonzero urb status: %d", urb->status); return; } - - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); - - return; } @@ -997,7 +988,7 @@ static void command_port_read_callback ( return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &command_port->dev, __FUNCTION__, urb->actual_length, data); command_info = usb_get_serial_port_data(command_port); if (!command_info) { @@ -1059,7 +1050,7 @@ static void whiteheat_read_callback(stru return; } - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); spin_lock(&info->lock); list_add_tail(&wrap->list, &info->rx_urb_q); @@ -1519,8 +1510,8 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM(urb_pool_size, "i"); +module_param(urb_pool_size, int, 0); MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); -MODULE_PARM(debug, "i"); +module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); --- linux-2.6.8-rc1/drivers/usb/storage/scsiglue.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/storage/scsiglue.c 2004-07-13 17:09:24.000000000 -0700 @@ -261,7 +261,7 @@ static int device_reset( Scsi_Cmnd *srb static int bus_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int result; + int result, rc; US_DEBUGP("%s called\n", __FUNCTION__); if (us->sm_state != US_STATE_IDLE) { @@ -286,8 +286,16 @@ static int bus_reset( Scsi_Cmnd *srb ) result = -EBUSY; US_DEBUGP("Refusing to reset a multi-interface device\n"); } else { - result = usb_reset_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", result); + rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); + if (rc < 0) { + US_DEBUGP("unable to lock device for reset: %d\n", rc); + result = rc; + } else { + result = usb_reset_device(us->pusb_dev); + if (rc) + usb_unlock_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } } up(&(us->dev_semaphore)); --- linux-2.6.8-rc1/drivers/usb/storage/sddr09.c 2004-03-10 20:41:30.000000000 -0800 +++ 25/drivers/usb/storage/sddr09.c 2004-07-13 17:09:13.000000000 -0700 @@ -1089,7 +1089,7 @@ sddr09_get_cardinfo(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("Result of read_deviceID is %d\n", result); printk("sddr09: could not read card info\n"); - return 0; + return NULL; } sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X", --- linux-2.6.8-rc1/drivers/usb/storage/transport.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/usb/storage/transport.c 2004-07-13 17:09:24.000000000 -0700 @@ -260,9 +260,7 @@ int usb_stor_clear_halt(struct us_data * USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); - /* reset the toggles and endpoint flags */ - usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe)); + /* reset the endpoint toggle */ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); --- linux-2.6.8-rc1/drivers/video/aty/mach64_cursor.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/drivers/video/aty/mach64_cursor.c 2004-07-13 17:09:13.000000000 -0700 @@ -182,7 +182,7 @@ struct aty_cursor *__init aty_init_curso cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC); if (!cursor) - return 0; + return NULL; memset(cursor, 0, sizeof(*cursor)); info->fix.smem_len -= PAGE_SIZE; --- linux-2.6.8-rc1/drivers/video/aty/radeon_base.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/aty/radeon_base.c 2004-07-13 17:35:10.000000000 -0700 @@ -2069,19 +2069,22 @@ static int radeonfb_pci_register (struct struct fb_info *info; struct radeonfb_info *rinfo; u32 tmp; + int ret; RTRACE("radeonfb_pci_register BEGIN\n"); /* Enable device in PCI config */ - if (pci_enable_device(pdev) != 0) { + ret = pci_enable_device(pdev); + if (ret < 0) { printk(KERN_ERR "radeonfb: Cannot enable PCI device\n"); - return -ENODEV; + goto err_out; } info = framebuffer_alloc(sizeof(struct radeonfb_info), &pdev->dev); if (!info) { printk (KERN_ERR "radeonfb: could not allocate memory\n"); - return -ENODEV; + ret = -ENOMEM; + goto err_disable; } rinfo = info->par; rinfo->info = info; @@ -2106,23 +2109,19 @@ static int radeonfb_pci_register (struct rinfo->mmio_base_phys = pci_resource_start (pdev, 2); /* request the mem regions */ - if (!request_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve FB region\n"); - goto free_rinfo; - } - - if (!request_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2), "radeonfb")) { - printk (KERN_ERR "radeonfb: cannot reserve MMIO region\n"); - goto release_fb; + ret = pci_request_regions(pdev, "radeonfb"); + if (ret < 0) { + printk( KERN_ERR "radeonfb: cannot reserve PCI regions." + " Someone already got them?\n"); + goto err_release_fb; } /* map the regions */ - rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE); + rinfo->mmio_base = (unsigned long) ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); if (!rinfo->mmio_base) { - printk (KERN_ERR "radeonfb: cannot map MMIO\n"); - goto release_mmio; + printk(KERN_ERR "radeonfb: cannot map MMIO\n"); + ret = -EIO; + goto err_release_pci; } /* On PPC, the firmware sets up a memory mapping that tends @@ -2226,23 +2225,20 @@ static int radeonfb_pci_register (struct RTRACE("radeonfb: probed %s %ldk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024)); - rinfo->mapped_vram = MAX_MAPPED_VRAM; - if (rinfo->video_ram < rinfo->mapped_vram) - rinfo->mapped_vram = rinfo->video_ram; - for (;;) { + rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM, rinfo->video_ram); + + do { rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys, rinfo->mapped_vram); - if (rinfo->fb_base == 0 && rinfo->mapped_vram > MIN_MAPPED_VRAM) { - rinfo->mapped_vram /= 2; - continue; - } - memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); - break; - } + } while ( rinfo->fb_base == 0 && + ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) ); - if (!rinfo->fb_base) { + if (rinfo->fb_base) + memset_io(rinfo->fb_base, 0, rinfo->mapped_vram); + else { printk (KERN_ERR "radeonfb: cannot map FB\n"); - goto unmap_rom; + ret = -EIO; + goto err_unmap_rom; } RTRACE("radeonfb: mapped %ldk videoram\n", rinfo->mapped_vram/1024); @@ -2330,9 +2326,10 @@ static int radeonfb_pci_register (struct printk("radeonfb: Power Management enabled for Mobility chipsets\n"); } - if (register_framebuffer(info) < 0) { + ret = register_framebuffer(info); + if (ret < 0) { printk (KERN_ERR "radeonfb: could not register framebuffer\n"); - goto unmap_fb; + goto err_unmap_fb; } #ifdef CONFIG_MTRR @@ -2358,30 +2355,30 @@ static int radeonfb_pci_register (struct RTRACE("radeonfb_pci_register END\n"); return 0; -unmap_fb: +err_unmap_fb: iounmap ((void*)rinfo->fb_base); -unmap_rom: +err_unmap_rom: if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); if (rinfo->mon2_EDID) kfree(rinfo->mon2_EDID); if (rinfo->mon1_modedb) fb_destroy_modedb(rinfo->mon1_modedb); + fb_dealloc_cmap(&info->cmap); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); iounmap ((void*)rinfo->mmio_base); -release_mmio: - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); -release_fb: - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); -free_rinfo: +err_release_pci: + pci_release_regions(pdev); +err_release_fb: framebuffer_release(info); - return -ENODEV; +err_disable: + pci_disable_device(pdev); +err_out: + return ret; } @@ -2413,10 +2410,7 @@ static void __devexit radeonfb_pci_unreg iounmap ((void*)rinfo->mmio_base); iounmap ((void*)rinfo->fb_base); - release_mem_region (rinfo->mmio_base_phys, - pci_resource_len(pdev, 2)); - release_mem_region (rinfo->fb_base_phys, - pci_resource_len(pdev, 0)); + pci_release_regions(pdev); if (rinfo->mon1_EDID) kfree(rinfo->mon1_EDID); @@ -2427,7 +2421,9 @@ static void __devexit radeonfb_pci_unreg #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); #endif + fb_dealloc_cmap(&info->cmap); framebuffer_release(info); + pci_disable_device(pdev); } --- linux-2.6.8-rc1/drivers/video/cirrusfb.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/cirrusfb.c 2004-07-13 17:09:13.000000000 -0700 @@ -2199,7 +2199,7 @@ static struct cirrusfb_info *cirrusfb_pc } else { DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n"); get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys); - cinfo->regbase = 0; /* FIXME: this forces VGA. alternatives? */ + cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */ } DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys); --- linux-2.6.8-rc1/drivers/video/fbmem.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/fbmem.c 2004-07-13 17:09:13.000000000 -0700 @@ -1459,7 +1459,7 @@ fbmem_init(void) { int i; - create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL); + create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); devfs_mk_dir("fb"); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) --- linux-2.6.8-rc1/drivers/video/i810/i810_gtf.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/drivers/video/i810/i810_gtf.c 2004-07-13 17:09:13.000000000 -0700 @@ -222,7 +222,7 @@ void i810fb_fill_var_timings(struct fb_v u32 i810_get_watermark(const struct fb_var_screeninfo *var, struct i810fb_par *par) { - struct wm_info *wmark = 0; + struct wm_info *wmark = NULL; u32 i, size = 0, pixclock, wm_best = 0, min, diff; if (par->mem_freq == 100) { --- linux-2.6.8-rc1/drivers/video/Kconfig 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/Kconfig 2004-07-13 17:33:09.000000000 -0700 @@ -446,6 +446,15 @@ config FB_RIVA_I2C independently validate video mode parameters, you should say Y here. +config FB_RIVA_DEBUG + bool "Lots of debug output from Riva(nVidia) driver" + depends on FB_RIVA + default n + help + Say Y here if you want the Riva driver to output all sorts + of debugging informations to provide to the maintainer when + something goes wrong. + config FB_I810 tristate "Intel 810/815 support (EXPERIMENTAL)" depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI --- linux-2.6.8-rc1/drivers/video/kyro/fbdev.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/kyro/fbdev.c 2004-07-13 17:09:13.000000000 -0700 @@ -84,7 +84,7 @@ typedef struct { } device_info_t; /* global graphics card info structure (one per card) */ -static device_info_t deviceInfo = { 0 }; +static device_info_t deviceInfo; static char *mode_option __initdata = NULL; static int nopan __initdata = 0; --- linux-2.6.8-rc1/drivers/video/riva/fbdev.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/riva/fbdev.c 2004-07-13 17:35:37.148469400 -0700 @@ -48,6 +48,9 @@ #include #include #endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif #include "rivafb.h" #include "nvreg.h" @@ -64,15 +67,16 @@ * various helpful macros and constants * * ------------------------------------------------------------------------- */ - -#undef RIVAFBDEBUG -#ifdef RIVAFBDEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#ifdef CONFIG_FB_RIVA_DEBUG +#define NVTRACE printk #else -#define DPRINTK(fmt, args...) +#define NVTRACE if(0) printk #endif -#ifndef RIVA_NDEBUG +#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __FUNCTION__) +#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __FUNCTION__) + +#ifdef CONFIG_FB_RIVA_DEBUG #define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ @@ -173,18 +177,18 @@ static struct riva_chip_info { { "GeForce2-GTS", NV_ARCH_10 }, { "GeForce2-ULTRA", NV_ARCH_10 }, { "Quadro2-PRO", NV_ARCH_10 }, - { "GeForce4-MX-460", NV_ARCH_20 }, - { "GeForce4-MX-440", NV_ARCH_20 }, - { "GeForce4-MX-420", NV_ARCH_20 }, - { "GeForce4-440-GO", NV_ARCH_20 }, - { "GeForce4-420-GO", NV_ARCH_20 }, - { "GeForce4-420-GO-M32", NV_ARCH_20 }, - { "Quadro4-500-XGL", NV_ARCH_20 }, - { "GeForce4-440-GO-M64", NV_ARCH_20 }, - { "Quadro4-200", NV_ARCH_20 }, - { "Quadro4-550-XGL", NV_ARCH_20 }, - { "Quadro4-500-GOGL", NV_ARCH_20 }, - { "GeForce2", NV_ARCH_20 }, + { "GeForce4-MX-460", NV_ARCH_10 }, + { "GeForce4-MX-440", NV_ARCH_10 }, + { "GeForce4-MX-420", NV_ARCH_10 }, + { "GeForce4-440-GO", NV_ARCH_10 }, + { "GeForce4-420-GO", NV_ARCH_10 }, + { "GeForce4-420-GO-M32", NV_ARCH_10 }, + { "Quadro4-500-XGL", NV_ARCH_10 }, + { "GeForce4-440-GO-M64", NV_ARCH_10 }, + { "Quadro4-200", NV_ARCH_10 }, + { "Quadro4-550-XGL", NV_ARCH_10 }, + { "Quadro4-500-GOGL", NV_ARCH_10 }, + { "GeForce2", NV_ARCH_10 }, { "GeForce3", NV_ARCH_20 }, { "GeForce3 Ti 200", NV_ARCH_20 }, { "GeForce3 Ti 500", NV_ARCH_20 }, @@ -351,6 +355,38 @@ static const struct riva_regs reg_templa 0xEB /* MISC */ }; +/* + * Backlight control + */ +#ifdef CONFIG_PMAC_BACKLIGHT + +static int riva_backlight_levels[] = { + 0x158, + 0x192, + 0x1c6, + 0x200, + 0x234, + 0x268, + 0x2a2, + 0x2d6, + 0x310, + 0x344, + 0x378, + 0x3b2, + 0x3e6, + 0x41a, + 0x454, + 0x534, +}; + +static int riva_set_backlight_enable(int on, int level, void *data); +static int riva_set_backlight_level(int level, void *data); +static struct backlight_controller riva_backlight_controller = { + riva_set_backlight_enable, + riva_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + /* ------------------------------------------------------------------------- * * * MMIO access macros @@ -592,6 +628,7 @@ static void riva_save_state(struct riva_ { int i; + NVTRACE_ENTER(); par->riva.LockUnlock(&par->riva, 0); par->riva.UnloadStateExt(&par->riva, ®s->ext); @@ -609,6 +646,7 @@ static void riva_save_state(struct riva_ for (i = 0; i < NUM_SEQ_REGS; i++) regs->seq[i] = SEQin(par, i); + NVTRACE_LEAVE(); } /** @@ -630,6 +668,7 @@ static void riva_load_state(struct riva_ RIVA_HW_STATE *state = ®s->ext; int i; + NVTRACE_ENTER(); CRTCout(par, 0x11, 0x00); par->riva.LockUnlock(&par->riva, 0); @@ -656,6 +695,7 @@ static void riva_load_state(struct riva_ for (i = 0; i < NUM_SEQ_REGS; i++) SEQout(par, i, regs->seq[i]); + NVTRACE_LEAVE(); } /** @@ -676,6 +716,7 @@ static void riva_load_video_mode(struct struct riva_par *par = (struct riva_par *) info->par; struct riva_regs newmode; + NVTRACE_ENTER(); /* time to calculate */ rivafb_blank(1, info); @@ -806,10 +847,12 @@ static void riva_load_video_mode(struct riva_load_state(par, &par->current_state); par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */ rivafb_blank(0, info); + NVTRACE_LEAVE(); } static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) { + NVTRACE_ENTER(); var->xres = var->xres_virtual = modedb->xres; var->yres = modedb->yres; if (var->yres_virtual < var->yres) @@ -824,6 +867,7 @@ static void riva_update_var(struct fb_va var->vsync_len = modedb->vsync_len; var->sync = modedb->sync; var->vmode = modedb->vmode; + NVTRACE_LEAVE(); } /** @@ -859,6 +903,7 @@ static int rivafb_do_maximize(struct fb_ }; int i; + NVTRACE_ENTER(); /* use highest possible virtual resolution */ if (var->xres_virtual == -1 && var->yres_virtual == -1) { printk(KERN_WARNING PFX @@ -871,7 +916,7 @@ static int rivafb_do_maximize(struct fb_ if (modes[i].xres == -1) { printk(KERN_ERR PFX "could not find a virtual resolution that fits into video memory!!\n"); - DPRINTK("EXIT - EINVAL error\n"); + NVTRACE("EXIT - EINVAL error\n"); return -EINVAL; } var->xres_virtual = modes[i].xres; @@ -897,7 +942,7 @@ static int rivafb_do_maximize(struct fb_ printk(KERN_ERR PFX "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); + NVTRACE("EXIT - EINVAL error\n"); return -EINVAL; } } @@ -924,7 +969,7 @@ static int rivafb_do_maximize(struct fb_ var->yres_virtual = 0x7fff/nom; if (var->xres_virtual > 0x7fff/nom) var->xres_virtual = 0x7fff/nom; - + NVTRACE_LEAVE(); return 0; } @@ -1004,6 +1049,36 @@ static int riva_get_cmap_len(const struc /* ------------------------------------------------------------------------- * * + * Backlight operations + * + * ------------------------------------------------------------------------- */ + +#ifdef CONFIG_PMAC_BACKLIGHT +static int riva_set_backlight_enable(int on, int level, void *data) +{ + struct riva_par *par = (struct riva_par *)data; + U032 tmp_pcrt, tmp_pmc; + + tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF; + tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC; + if(on && (level > BACKLIGHT_OFF)) { + tmp_pcrt |= 0x1; + tmp_pmc |= (1 << 31); // backlight bit + tmp_pmc |= riva_backlight_levels[level-1] << 16; // level + } + par->riva.PCRTC0[0x081C/4] = tmp_pcrt; + par->riva.PMC[0x10F0/4] = tmp_pmc; + return 0; +} + +static int riva_set_backlight_level(int level, void *data) +{ + return riva_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + +/* ------------------------------------------------------------------------- * + * * framebuffer operations * * ------------------------------------------------------------------------- */ @@ -1013,6 +1088,7 @@ static int rivafb_open(struct fb_info *i struct riva_par *par = (struct riva_par *) info->par; int cnt = atomic_read(&par->ref_count); + NVTRACE_ENTER(); if (!cnt) { memset(&par->state, 0, sizeof(struct vgastate)); par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; @@ -1029,6 +1105,7 @@ static int rivafb_open(struct fb_info *i riva_save_state(par, &par->initial_state); } atomic_inc(&par->ref_count); + NVTRACE_LEAVE(); return 0; } @@ -1037,6 +1114,7 @@ static int rivafb_release(struct fb_info struct riva_par *par = (struct riva_par *) info->par; int cnt = atomic_read(&par->ref_count); + NVTRACE_ENTER(); if (!cnt) return -EINVAL; if (cnt == 1) { @@ -1047,6 +1125,7 @@ static int rivafb_release(struct fb_info par->riva.LockUnlock(&par->riva, 1); } atomic_dec(&par->ref_count); + NVTRACE_LEAVE(); return 0; } @@ -1056,6 +1135,7 @@ static int rivafb_check_var(struct fb_va int nom, den; /* translating from pixels->bytes */ int mode_valid = 0; + NVTRACE_ENTER(); switch (var->bits_per_pixel) { case 1 ... 8: var->red.offset = var->green.offset = var->blue.offset = 0; @@ -1101,7 +1181,7 @@ static int rivafb_check_var(struct fb_va printk(KERN_ERR PFX "mode %dx%dx%d rejected...color depth not supported.\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK("EXIT, returning -EINVAL\n"); + NVTRACE("EXIT, returning -EINVAL\n"); return -EINVAL; } @@ -1191,6 +1271,7 @@ static int rivafb_check_var(struct fb_va var->green.msb_right = var->blue.msb_right = var->transp.offset = var->transp.length = var->transp.msb_right = 0; + NVTRACE_LEAVE(); return 0; } @@ -1198,6 +1279,7 @@ static int rivafb_set_par(struct fb_info { struct riva_par *par = (struct riva_par *) info->par; + NVTRACE_ENTER(); riva_common_setup(par); RivaGetConfig(&par->riva, par->Chipset); /* vgaHWunlock() + riva unlock (0x7F) */ @@ -1211,6 +1293,7 @@ static int rivafb_set_par(struct fb_info info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3)); info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + NVTRACE_LEAVE(); return 0; } @@ -1233,6 +1316,7 @@ static int rivafb_pan_display(struct fb_ struct riva_par *par = (struct riva_par *)info->par; unsigned int base; + NVTRACE_ENTER(); if (var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; if (var->yoffset > (var->yres_virtual - var->yres)) @@ -1259,6 +1343,7 @@ static int rivafb_pan_display(struct fb_ info->var.vmode |= FB_VMODE_YWRAP; else info->var.vmode &= ~FB_VMODE_YWRAP; + NVTRACE_LEAVE(); return 0; } @@ -1270,6 +1355,7 @@ static int rivafb_blank(int blank, struc tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */ vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */ + NVTRACE_ENTER(); if (blank) { tmp |= 0x20; switch (blank - 1) { @@ -1288,6 +1374,14 @@ static int rivafb_blank(int blank, struc } SEQout(par, 0x01, tmp); CRTCout(par, 0x1a, vesa); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ( par->FlatPanel && _machine == _MACH_Pmac) { + set_backlight_enable(!blank); + } +#endif + + NVTRACE_LEAVE(); return 0; } @@ -1676,6 +1770,7 @@ static int __devinit riva_set_fbinfo(str { unsigned int cmap_len; + NVTRACE_ENTER(); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN @@ -1696,6 +1791,7 @@ static int __devinit riva_set_fbinfo(str info->pixmap.scan_align = 4; info->pixmap.flags = FB_PIXMAP_SYSTEM; info->var.yres_virtual = -1; + NVTRACE_LEAVE(); return (rivafb_check_var(&info->var, info)); } @@ -1710,6 +1806,7 @@ static int riva_get_EDID_OF(struct fb_in "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; int i; + NVTRACE_ENTER(); dp = pci_device_to_OF_node(pd); for (; dp != NULL; dp = dp->child) { disptype = (unsigned char *)get_property(dp, "display-type", NULL); @@ -1726,6 +1823,7 @@ static int riva_get_EDID_OF(struct fb_in } } } + NVTRACE_LEAVE(); return 0; } #endif /* CONFIG_PPC_OF */ @@ -1735,6 +1833,7 @@ static void riva_update_default_var(stru struct fb_monspecs *specs = &info->monspecs; struct fb_videomode modedb; + NVTRACE_ENTER(); /* respect mode options */ if (mode_option) { fb_find_mode(var, info, mode_option, @@ -1759,21 +1858,24 @@ static void riva_update_default_var(stru riva_update_var(var, &modedb); } var->accel_flags |= FB_ACCELF_TEXT; + NVTRACE_LEAVE(); } static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev) { + struct riva_par *par; + int i; + + NVTRACE_ENTER(); #ifdef CONFIG_PPC_OF if (!riva_get_EDID_OF(info, pdev)) printk("rivafb: could not retrieve EDID from OF\n"); #else /* XXX use other methods later */ #ifdef CONFIG_FB_RIVA_I2C - struct riva_par *par = (struct riva_par *) info->par; - int i; - riva_create_i2c_busses(par); + par = (struct riva_par *) info->par; for (i = par->bus; i >= 1; i--) { riva_probe_i2c_connector(par, i, &par->EDID); if (par->EDID) { @@ -1781,9 +1883,9 @@ static void riva_get_EDID(struct fb_info break; } } - riva_delete_i2c_busses(par); #endif #endif + NVTRACE_LEAVE(); } @@ -1813,6 +1915,7 @@ static int __devinit rivafb_probe(struct struct riva_par *default_par; struct fb_info *info; + NVTRACE_ENTER(); assert(pd != NULL); assert(rci != NULL); @@ -1933,6 +2036,10 @@ static int __devinit rivafb_probe(struct } #endif /* CONFIG_MTRR */ +#ifdef CONFIG_FB_RIVA_I2C + riva_create_i2c_busses((struct riva_par *) info->par); +#endif + info->fbops = &riva_fb_ops; info->fix = rivafb_fix; riva_get_EDID(info, pd); @@ -1958,9 +2065,18 @@ static int __devinit rivafb_probe(struct info->fix.id, info->fix.smem_len / (1024 * 1024), info->fix.smem_start); +#ifdef CONFIG_PMAC_BACKLIGHT + if (default_par->FlatPanel && _machine == _MACH_Pmac) + register_backlight_controller(&riva_backlight_controller, + default_par, "mnca"); +#endif + NVTRACE_LEAVE(); return 0; err_out_iounmap_fb: +#ifdef CONFIG_FB_RIVA_I2C + riva_delete_i2c_busses((struct riva_par *) info->par); +#endif iounmap(info->screen_base); err_out_free_base1: if (default_par->riva.Architecture == NV_ARCH_03) @@ -1986,9 +2102,14 @@ static void __exit rivafb_remove(struct struct fb_info *info = pci_get_drvdata(pd); struct riva_par *par = (struct riva_par *) info->par; + NVTRACE_ENTER(); if (!info) return; +#ifdef CONFIG_FB_RIVA_I2C + riva_delete_i2c_busses(par); +#endif + unregister_framebuffer(info); #ifdef CONFIG_MTRR if (par->mtrr.vram_valid) @@ -2007,6 +2128,7 @@ static void __exit rivafb_remove(struct kfree(par); kfree(info); pci_set_drvdata(pd, NULL); + NVTRACE_LEAVE(); } /* ------------------------------------------------------------------------- * @@ -2020,6 +2142,7 @@ int __init rivafb_setup(char *options) { char *this_opt; + NVTRACE_ENTER(); if (!options || !*options) return 0; @@ -2043,6 +2166,7 @@ int __init rivafb_setup(char *options) } else mode_option = this_opt; } + NVTRACE_LEAVE(); return 0; } #endif /* !MODULE */ --- linux-2.6.8-rc1/drivers/video/riva/riva_hw.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/drivers/video/riva/riva_hw.c 2004-07-13 17:09:13.000000000 -0700 @@ -1344,7 +1344,7 @@ static void UpdateFifoState { case NV_ARCH_04: LOAD_FIXED_STATE(nv4,FIFO); - chip->Tri03 = 0L; + chip->Tri03 = NULL; chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); break; case NV_ARCH_10: @@ -1354,7 +1354,7 @@ static void UpdateFifoState */ LOAD_FIXED_STATE(nv10tri05,PGRAPH); LOAD_FIXED_STATE(nv10,FIFO); - chip->Tri03 = 0L; + chip->Tri03 = NULL; chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); break; } @@ -1394,13 +1394,13 @@ static void LoadStateExt case 32: LOAD_FIXED_STATE_32BPP(nv3,PRAMIN); LOAD_FIXED_STATE_32BPP(nv3,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; case 8: default: LOAD_FIXED_STATE_8BPP(nv3,PRAMIN); LOAD_FIXED_STATE_8BPP(nv3,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; } for (i = 0x00000; i < 0x00800; i++) @@ -1438,13 +1438,13 @@ static void LoadStateExt case 32: LOAD_FIXED_STATE_32BPP(nv4,PRAMIN); LOAD_FIXED_STATE_32BPP(nv4,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; case 8: default: LOAD_FIXED_STATE_8BPP(nv4,PRAMIN); LOAD_FIXED_STATE_8BPP(nv4,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; } chip->PGRAPH[0x00000640/4] = state->offset0; @@ -1483,13 +1483,13 @@ static void LoadStateExt case 32: LOAD_FIXED_STATE_32BPP(nv10,PRAMIN); LOAD_FIXED_STATE_32BPP(nv10,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; case 8: default: LOAD_FIXED_STATE_8BPP(nv10,PRAMIN); LOAD_FIXED_STATE_8BPP(nv10,PGRAPH); - chip->Tri03 = 0L; + chip->Tri03 = NULL; break; } --- linux-2.6.8-rc1/fs/afs/fsclient.c 2004-02-03 20:42:38.000000000 -0800 +++ 25/fs/afs/fsclient.c 2004-07-13 17:09:13.000000000 -0700 @@ -59,7 +59,7 @@ int afs_rxfs_get_root_volume(struct afs_ { struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[2]; + struct kvec piov[2]; size_t sent; int ret; u32 param[1]; @@ -189,7 +189,7 @@ int afs_rxfs_get_volume_info(struct afs_ { struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[3]; + struct kvec piov[3]; size_t sent; int ret; u32 param[2], *bp, zero; @@ -304,7 +304,7 @@ int afs_rxfs_fetch_file_status(struct af { struct afs_server_callslot callslot; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; size_t sent; int ret; u32 *bp; @@ -429,7 +429,7 @@ int afs_rxfs_fetch_file_data(struct afs_ { struct afs_server_callslot callslot; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; size_t sent; int ret; u32 *bp; @@ -580,7 +580,7 @@ int afs_rxfs_give_up_callback(struct afs { struct afs_server_callslot callslot; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; size_t sent; int ret; u32 *bp; @@ -686,7 +686,7 @@ int afs_rxfs_lookup(struct afs_server *s { struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[3]; + struct kvec piov[3]; size_t sent; int ret; u32 *bp, zero; --- linux-2.6.8-rc1/fs/afs/mntpt.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/afs/mntpt.c 2004-07-13 17:35:10.000000000 -0700 @@ -182,7 +182,7 @@ static struct vfsmount *afs_mntpt_do_aut goto error; /* read the contents of the AFS special symlink */ - filler = mntpt->d_inode->i_mapping->a_ops->readpage; + filler = (filler_t *)mntpt->d_inode->i_mapping->a_ops->readpage; page = read_cache_page(mntpt->d_inode->i_mapping, 0, filler, NULL); if (IS_ERR(page)) { @@ -250,7 +250,7 @@ static int afs_mntpt_follow_link(struct if (IS_ERR(newmnt)) return PTR_ERR(newmnt); - struct_cpy(&newnd, nd); + newnd = *nd; newnd.dentry = dentry; err = do_add_mount(newmnt, &newnd, 0, &afs_vfsmounts); --- linux-2.6.8-rc1/fs/afs/vlclient.c 2004-02-03 20:42:38.000000000 -0800 +++ 25/fs/afs/vlclient.c 2004-07-13 17:09:13.000000000 -0700 @@ -97,7 +97,7 @@ int afs_rxvl_probe(struct afs_server *se { struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; size_t sent; int ret; u32 param[1]; @@ -187,7 +187,7 @@ int afs_rxvl_get_entry_by_name(struct af struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[3]; + struct kvec piov[3]; unsigned tmp; size_t sent; int ret, loop; @@ -322,7 +322,7 @@ int afs_rxvl_get_entry_by_id(struct afs_ struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; unsigned tmp; size_t sent; int ret, loop; @@ -459,7 +459,7 @@ int afs_rxvl_get_entry_by_id_async(struc { struct rxrpc_connection *conn; struct rxrpc_call *call; - struct iovec piov[1]; + struct kvec piov[1]; size_t sent; int ret; u32 param[3]; --- linux-2.6.8-rc1/fs/afs/vlocation.c 2004-02-03 20:42:38.000000000 -0800 +++ 25/fs/afs/vlocation.c 2004-07-13 17:35:10.000000000 -0700 @@ -906,7 +906,7 @@ static cachefs_match_val_t afs_vlocation if (!vlocation->valid || vlocation->vldb.rtime == vldb->rtime ) { - struct_cpy(&vlocation->vldb, vldb); + vlocation->vldb = *vldb; vlocation->valid = 1; _leave(" = SUCCESS [c->m]"); return CACHEFS_MATCH_SUCCESS; @@ -947,7 +947,7 @@ static void afs_vlocation_cache_update(v _enter(""); - struct_cpy(vldb,&vlocation->vldb); + *vldb = vlocation->vldb; } /* end afs_vlocation_cache_update() */ #endif --- linux-2.6.8-rc1/fs/binfmt_aout.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/binfmt_aout.c 2004-07-13 17:09:38.000000000 -0700 @@ -307,7 +307,7 @@ static int load_aout_binary(struct linux (current->mm->start_data = N_DATADDR(ex)); current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); - current->mm->free_area_cache = TASK_UNMAPPED_BASE; + current->mm->free_area_cache = current->mm->mmap_base; current->mm->rss = 0; current->mm->mmap = NULL; --- linux-2.6.8-rc1/fs/binfmt_elf.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/binfmt_elf.c 2004-07-13 17:09:52.000000000 -0700 @@ -627,8 +627,14 @@ static int load_elf_binary(struct linux_ executable_stack = EXSTACK_DISABLE_X; break; } +#ifndef CONFIG_DEFAULT_NOEXEC + /* + * Legacy binaries (unless the arch defaults to noexec) have an + * expectation of executability - turn it on: + */ if (i == elf_ex.e_phnum) def_flags |= VM_EXEC | VM_MAYEXEC; +#endif /* Some simple consistency checks for the interpreter */ if (elf_interpreter) { @@ -705,7 +711,7 @@ static int load_elf_binary(struct linux_ /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; - current->mm->free_area_cache = TASK_UNMAPPED_BASE; + current->mm->free_area_cache = current->mm->mmap_base; retval = setup_arg_pages(bprm, executable_stack); if (retval < 0) { send_sig(SIGKILL, current, 0); --- linux-2.6.8-rc1/fs/bio.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/bio.c 2004-07-13 17:09:50.000000000 -0700 @@ -376,6 +376,115 @@ int bio_add_page(struct bio *bio, struct len, offset); } +/** + * bio_uncopy_user - finish previously mapped bio + * @bio: bio being terminated + * + * Free pages allocated from bio_copy_user() and write back data + * to user space in case of a read. + */ +int bio_uncopy_user(struct bio *bio) +{ + struct bio_vec *bvec; + int i, ret = 0; + + if (bio_data_dir(bio) == READ) { + char *uaddr = bio->bi_private; + + __bio_for_each_segment(bvec, bio, i, 0) { + char *addr = page_address(bvec->bv_page); + + if (!ret && copy_to_user(uaddr, addr, bvec->bv_len)) + ret = -EFAULT; + + __free_page(bvec->bv_page); + uaddr += bvec->bv_len; + } + } + + bio_put(bio); + return ret; +} + +/** + * bio_copy_user - copy user data to bio + * @q: destination block queue + * @uaddr: start of user address + * @len: length in bytes + * @write_to_vm: bool indicating writing to pages or not + * + * Prepares and returns a bio for indirect user io, bouncing data + * to/from kernel pages as necessary. Must be paired with + * call bio_uncopy_user() on io completion. + */ +struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr, + unsigned int len, int write_to_vm) +{ + unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + struct bio_vec *bvec; + struct page *page; + struct bio *bio; + int i, ret; + + bio = bio_alloc(GFP_KERNEL, end - start); + if (!bio) + return ERR_PTR(-ENOMEM); + + ret = 0; + while (len) { + unsigned int bytes = PAGE_SIZE; + + if (bytes > len) + bytes = len; + + page = alloc_page(q->bounce_gfp | GFP_KERNEL); + if (!page) { + ret = -ENOMEM; + break; + } + + if (__bio_add_page(q, bio, page, bytes, 0) < bytes) { + ret = -EINVAL; + break; + } + + len -= bytes; + } + + /* + * success + */ + if (!ret) { + if (!write_to_vm) { + bio->bi_rw |= (1 << BIO_RW); + /* + * for a write, copy in data to kernel pages + */ + ret = -EFAULT; + bio_for_each_segment(bvec, bio, i) { + char *addr = page_address(bvec->bv_page); + + if (copy_from_user(addr, (char *) uaddr, bvec->bv_len)) + goto cleanup; + } + } + + bio->bi_private = (void *) uaddr; + return bio; + } + + /* + * cleanup + */ +cleanup: + bio_for_each_segment(bvec, bio, i) + __free_page(bvec->bv_page); + + bio_put(bio); + return ERR_PTR(ret); +} + static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, unsigned long uaddr, unsigned int len, int write_to_vm) @@ -392,12 +501,13 @@ static struct bio *__bio_map_user(reques * size for now, in the future we can relax this restriction */ if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q))) - return NULL; + return ERR_PTR(-EINVAL); bio = bio_alloc(GFP_KERNEL, nr_pages); if (!bio) - return NULL; + return ERR_PTR(-ENOMEM); + ret = -ENOMEM; pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); if (!pages) goto out; @@ -446,12 +556,13 @@ static struct bio *__bio_map_user(reques if (!write_to_vm) bio->bi_rw |= (1 << BIO_RW); + bio->bi_flags |= (1 << BIO_USER_MAPPED); blk_queue_bounce(q, &bio); return bio; out: kfree(pages); bio_put(bio); - return NULL; + return ERR_PTR(ret); } /** @@ -462,7 +573,7 @@ out: * @write_to_vm: bool indicating writing to pages or not * * Map the user space address into a bio suitable for io to a block - * device. + * device. Returns an error pointer in case of error. */ struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev, unsigned long uaddr, unsigned int len, int write_to_vm) @@ -471,26 +582,29 @@ struct bio *bio_map_user(request_queue_t bio = __bio_map_user(q, bdev, uaddr, len, write_to_vm); - if (bio) { - /* - * subtle -- if __bio_map_user() ended up bouncing a bio, - * it would normally disappear when its bi_end_io is run. - * however, we need it for the unmap, so grab an extra - * reference to it - */ - bio_get(bio); + if (IS_ERR(bio)) + return bio; - if (bio->bi_size < len) { - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio, 0); - return NULL; - } - } + /* + * subtle -- if __bio_map_user() ended up bouncing a bio, + * it would normally disappear when its bi_end_io is run. + * however, we need it for the unmap, so grab an extra + * reference to it + */ + bio_get(bio); - return bio; + if (bio->bi_size == len) + return bio; + + /* + * don't support partial mappings + */ + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio); + return ERR_PTR(-EINVAL); } -static void __bio_unmap_user(struct bio *bio, int write_to_vm) +static void __bio_unmap_user(struct bio *bio) { struct bio_vec *bvec; int i; @@ -511,7 +625,7 @@ static void __bio_unmap_user(struct bio * make sure we dirty pages we wrote to */ __bio_for_each_segment(bvec, bio, i, 0) { - if (write_to_vm) + if (bio_data_dir(bio) == READ) set_page_dirty_lock(bvec->bv_page); page_cache_release(bvec->bv_page); @@ -523,17 +637,15 @@ static void __bio_unmap_user(struct bio /** * bio_unmap_user - unmap a bio * @bio: the bio being unmapped - * @write_to_vm: bool indicating whether pages were written to * - * Unmap a bio previously mapped by bio_map_user(). The @write_to_vm - * must be the same as passed into bio_map_user(). Must be called with + * Unmap a bio previously mapped by bio_map_user(). Must be called with * a process context. * * bio_unmap_user() may sleep. */ -void bio_unmap_user(struct bio *bio, int write_to_vm) +void bio_unmap_user(struct bio *bio) { - __bio_unmap_user(bio, write_to_vm); + __bio_unmap_user(bio); bio_put(bio); } @@ -864,3 +976,5 @@ EXPORT_SYMBOL(bio_unmap_user); EXPORT_SYMBOL(bio_pair_release); EXPORT_SYMBOL(bio_split); EXPORT_SYMBOL(bio_split_pool); +EXPORT_SYMBOL(bio_copy_user); +EXPORT_SYMBOL(bio_uncopy_user); --- linux-2.6.8-rc1/fs/buffer.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/buffer.c 2004-07-13 17:09:51.000000000 -0700 @@ -213,7 +213,7 @@ void end_buffer_write_sync(struct buffer if (uptodate) { set_buffer_uptodate(bh); } else { - if (printk_ratelimit()) { + if (!buffer_eopnotsupp(bh) && printk_ratelimit()) { buffer_io_error(bh); printk(KERN_WARNING "lost page write due to " "I/O error on %s\n", @@ -947,7 +947,7 @@ int __set_page_dirty_buffers(struct page spin_unlock(&mapping->private_lock); if (!TestSetPageDirty(page)) { - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ if (!mapping->backing_dev_info->memory_backed) inc_page_state(nr_dirty); @@ -955,7 +955,7 @@ int __set_page_dirty_buffers(struct page page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); } @@ -1551,6 +1551,7 @@ __getblk(struct block_device *bdev, sect { struct buffer_head *bh = __find_get_block(bdev, block, size); + might_sleep(); if (bh == NULL) bh = __getblk_slow(bdev, block, size); return bh; @@ -1776,6 +1777,8 @@ void unmap_underlying_metadata(struct bl { struct buffer_head *old_bh; + might_sleep(); + old_bh = __find_get_block_slow(bdev, block, 0); if (old_bh) { clear_buffer_dirty(old_bh); @@ -2756,21 +2759,33 @@ static int end_bio_bh_io_sync(struct bio if (bio->bi_size) return 1; + if (err == -EOPNOTSUPP) { + set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); + set_bit(BH_Eopnotsupp, &bh->b_state); + } + bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); bio_put(bio); return 0; } -void submit_bh(int rw, struct buffer_head * bh) +int submit_bh(int rw, struct buffer_head * bh) { struct bio *bio; + int ret = 0; BUG_ON(!buffer_locked(bh)); BUG_ON(!buffer_mapped(bh)); BUG_ON(!bh->b_end_io); - /* Only clear out a write error when rewriting */ - if (test_set_buffer_req(bh) && rw == WRITE) + if (buffer_ordered(bh) && (rw == WRITE)) + rw = WRITE_BARRIER; + + /* + * Only clear out a write error when rewriting, should this + * include WRITE_SYNC as well? + */ + if (test_set_buffer_req(bh) && (rw == WRITE || rw == WRITE_BARRIER)) clear_buffer_write_io_error(bh); /* @@ -2792,7 +2807,14 @@ void submit_bh(int rw, struct buffer_hea bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh; + bio_get(bio); submit_bio(rw, bio); + + if (bio_flagged(bio, BIO_EOPNOTSUPP)) + ret = -EOPNOTSUPP; + + bio_put(bio); + return ret; } /** @@ -2851,20 +2873,30 @@ void ll_rw_block(int rw, int nr, struct /* * For a data-integrity writeout, we need to wait upon any in-progress I/O - * and then start new I/O and then wait upon it. + * and then start new I/O and then wait upon it. The caller must have a ref on + * the buffer_head. */ -void sync_dirty_buffer(struct buffer_head *bh) +int sync_dirty_buffer(struct buffer_head *bh) { + int ret = 0; + WARN_ON(atomic_read(&bh->b_count) < 1); lock_buffer(bh); if (test_clear_buffer_dirty(bh)) { get_bh(bh); bh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, bh); + ret = submit_bh(WRITE, bh); wait_on_buffer(bh); + if (buffer_eopnotsupp(bh)) { + clear_buffer_eopnotsupp(bh); + ret = -EOPNOTSUPP; + } + if (!ret && !buffer_uptodate(bh)) + ret = -EIO; } else { unlock_buffer(bh); } + return ret; } /* --- linux-2.6.8-rc1/fs/cifs/asn1.c 2003-06-22 12:04:44.000000000 -0700 +++ 25/fs/cifs/asn1.c 2004-07-13 17:09:13.582208064 -0700 @@ -201,7 +201,7 @@ asn1_header_decode(struct asn1_ctx *ctx, if (def) *eoc = ctx->pointer + len; else - *eoc = 0; + *eoc = NULL; return 1; } --- linux-2.6.8-rc1/fs/cifs/CHANGES 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/CHANGES 2004-07-13 17:09:13.000000000 -0700 @@ -1,7 +1,11 @@ Version 1.20 ------------ Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps -info into /proc/fs/cifs/DebugData +info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir +(in build_wildcard_path_from_dentry). Fix mknod to pass type field +(block/char/fifo) properly. Remove spurious mount warning log entry when +credentials passed as mount argument. Set major/minor device number in +inode for block and char devices when unix extensions enabled. Version 1.19 ------------ --- linux-2.6.8-rc1/fs/cifs/cifs_debug.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/cifs_debug.c 2004-07-13 17:09:13.583207912 -0700 @@ -313,65 +313,65 @@ cifs_proc_init(void) proc_fs_cifs->owner = THIS_MODULE; create_proc_read_entry("DebugData", 0, proc_fs_cifs, - cifs_debug_data_read, 0); + cifs_debug_data_read, NULL); #ifdef CONFIG_CIFS_STATS create_proc_read_entry("Stats", 0, proc_fs_cifs, - cifs_stats_read, 0); + cifs_stats_read, NULL); #endif pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, - cifsFYI_read, 0); + cifsFYI_read, NULL); if (pde) pde->write_proc = cifsFYI_write; pde = create_proc_read_entry("traceSMB", 0, proc_fs_cifs, - traceSMB_read, 0); + traceSMB_read, NULL); if (pde) pde->write_proc = traceSMB_write; pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, - oplockEnabled_read, 0); + oplockEnabled_read, NULL); if (pde) pde->write_proc = oplockEnabled_write; pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, - quotaEnabled_read, 0); + quotaEnabled_read, NULL); if (pde) pde->write_proc = quotaEnabled_write; pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, - linuxExtensionsEnabled_read, 0); + linuxExtensionsEnabled_read, NULL); if (pde) pde->write_proc = linuxExtensionsEnabled_write; pde = create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, - multiuser_mount_read, 0); + multiuser_mount_read, NULL); if (pde) pde->write_proc = multiuser_mount_write; pde = create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, - extended_security_read, 0); + extended_security_read, NULL); if (pde) pde->write_proc = extended_security_write; pde = create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, - lookupFlag_read, 0); + lookupFlag_read, NULL); if (pde) pde->write_proc = lookupFlag_write; pde = create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, - ntlmv2_enabled_read, 0); + ntlmv2_enabled_read, NULL); if (pde) pde->write_proc = ntlmv2_enabled_write; pde = create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, - packet_signing_enabled_read, 0); + packet_signing_enabled_read, NULL); if (pde) pde->write_proc = packet_signing_enabled_write; } --- linux-2.6.8-rc1/fs/cifs/cifssmb.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/cifssmb.c 2004-07-13 17:09:13.586207456 -0700 @@ -190,7 +190,7 @@ CIFSSMBNegotiate(unsigned int xid, struc rc = -EIO; return rc; } - rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ , + rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); if (rc) return rc; @@ -363,7 +363,7 @@ CIFSSMBLogoff(const int xid, struct cifs return -EBUSY; } - rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */, + rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */, (void **) &pSMB, (void **) &smb_buffer_response); if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) @@ -2067,7 +2067,7 @@ CIFSGetDFSRefer(const int xid, struct ci if (ses == NULL) return -ENODEV; getDFSRetry: - rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB, + rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB, (void **) &pSMBr); if (rc) return rc; @@ -2836,6 +2836,23 @@ setPermsRetry: data_offset->DevMajor = cpu_to_le64(MAJOR(device)); data_offset->DevMinor = cpu_to_le64(MINOR(device)); data_offset->Permissions = cpu_to_le64(mode); + + if(S_ISREG(mode)) + data_offset->Type = cpu_to_le32(UNIX_FILE); + else if(S_ISDIR(mode)) + data_offset->Type = cpu_to_le32(UNIX_DIR); + else if(S_ISLNK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SYMLINK); + else if(S_ISCHR(mode)) + data_offset->Type = cpu_to_le32(UNIX_CHARDEV); + else if(S_ISBLK(mode)) + data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); + else if(S_ISFIFO(mode)) + data_offset->Type = cpu_to_le32(UNIX_FIFO); + else if(S_ISSOCK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SOCKET); + + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); --- linux-2.6.8-rc1/fs/cifs/cifs_uniupr.h 2003-06-14 12:18:00.000000000 -0700 +++ 25/fs/cifs/cifs_uniupr.h 2004-07-13 17:09:13.584207760 -0700 @@ -132,7 +132,7 @@ const struct UniCaseRange CifsUniUpperRa {0x0490, 0x04cc, UniCaseRangeU0490}, {0x1e00, 0x1ffc, UniCaseRangeU1e00}, {0xff40, 0xff5a, UniCaseRangeUff40}, - {0, 0, 0} + {0} }; #endif --- linux-2.6.8-rc1/fs/cifs/connect.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/connect.c 2004-07-13 17:09:13.589207000 -0700 @@ -715,6 +715,8 @@ cifs_parse_mount_options(char *options, if((i==15) && (value[i] != 0)) printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); } + } else if (strnicmp(data, "credentials", 4) == 0) { + /* ignore */ } else if (strnicmp(data, "version", 3) == 0) { /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { @@ -1443,7 +1445,7 @@ CIFSSessSetup(unsigned int xid, struct c /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - 0 /* no tCon exists yet */ , 13 /* wct */ ); + NULL /* no tCon exists yet */ , 13 /* wct */ ); pSMB->req_no_secext.AndXCommand = 0xFF; pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); @@ -1699,7 +1701,7 @@ CIFSSpnegoSessSetup(unsigned int xid, st /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - 0 /* no tCon exists yet */ , 12 /* wct */ ); + NULL /* no tCon exists yet */ , 12 /* wct */ ); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); @@ -1961,7 +1963,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned i /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - 0 /* no tCon exists yet */ , 12 /* wct */ ); + NULL /* no tCon exists yet */ , 12 /* wct */ ); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); @@ -2301,7 +2303,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xi /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - 0 /* no tCon exists yet */ , 12 /* wct */ ); + NULL /* no tCon exists yet */ , 12 /* wct */ ); pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; @@ -2674,7 +2676,7 @@ CIFSTCon(unsigned int xid, struct cifsSe smb_buffer_response = smb_buffer; header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, - 0 /*no tid */ , 4 /*wct */ ); + NULL /*no tid */ , 4 /*wct */ ); smb_buffer->Uid = ses->Suid; pSMB = (TCONX_REQ *) smb_buffer; pSMBr = (TCONX_RSP *) smb_buffer_response; --- linux-2.6.8-rc1/fs/cifs/dir.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/dir.c 2004-07-13 17:09:13.590206848 -0700 @@ -101,6 +101,7 @@ cifs_bp_rename_retry: return full_path; } +/* Note: caller must free return buffer */ char * build_wildcard_path_from_dentry(struct dentry *direntry) { @@ -108,18 +109,28 @@ build_wildcard_path_from_dentry(struct d int namelen = 0; char *full_path; + if(direntry == NULL) + return NULL; /* not much we can do if dentry is freed and + we need to reopen the file after it was closed implicitly + when the server crashed */ + +cifs_bwp_rename_retry: for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + return NULL; + } } - namelen += 3; /* allow for trailing null and wildcard (slash and *) */ - full_path = kmalloc(namelen, GFP_KERNEL); - namelen--; - full_path[namelen] = 0; /* trailing null */ - namelen--; - full_path[namelen] = '*'; - namelen--; + + full_path = kmalloc(namelen+3, GFP_KERNEL); + if(full_path == NULL) + return full_path; + full_path[namelen] = '\\'; + full_path[namelen+1] = '*'; + full_path[namelen+2] = 0; /* trailing null */ for (temp = direntry; !IS_ROOT(temp);) { namelen -= 1 + temp->d_name.len; @@ -129,13 +140,26 @@ build_wildcard_path_from_dentry(struct d full_path[namelen] = '\\'; strncpy(full_path + namelen + 1, temp->d_name.name, temp->d_name.len); + cFYI(0, (" name: %s ", full_path + namelen)); } temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + kfree(full_path); + return NULL; + } } - if (namelen != 0) + if (namelen != 0) { cERROR(1, ("We did not end path lookup where we expected namelen is %d", namelen)); + /* presumably this is only possible if we were racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ + kfree(full_path); + namelen = 0; + goto cifs_bwp_rename_retry; + } return full_path; } @@ -431,9 +455,16 @@ cifs_dir_open(struct inode *inode, struc cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; - full_path = build_wildcard_path_from_dentry(file->f_dentry); + if(file->f_dentry) { + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + } else { + FreeXid(xid); + return -EIO; + } - cFYI(1, (" inode = 0x%p and full path is %s", inode, full_path)); + cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); if (full_path) kfree(full_path); --- linux-2.6.8-rc1/fs/cifs/file.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/file.c 2004-07-13 17:09:13.591206696 -0700 @@ -1105,7 +1105,7 @@ cifs_readpages(struct file *file, struct struct cifsTconInfo *pTcon; int bytes_read = 0; unsigned int read_size,i; - char * smb_read_data = 0; + char * smb_read_data = NULL; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; struct cifsFileInfo * open_file; @@ -1170,7 +1170,7 @@ cifs_readpages(struct file *file, struct if(rc== -EAGAIN) { if(smb_read_data) { cifs_buf_release(smb_read_data); - smb_read_data = 0; + smb_read_data = NULL; } } } @@ -1224,7 +1224,7 @@ cifs_readpages(struct file *file, struct } if(smb_read_data) { cifs_buf_release(smb_read_data); - smb_read_data = 0; + smb_read_data = NULL; } bytes_read = 0; } @@ -1234,7 +1234,7 @@ cifs_readpages(struct file *file, struct /* need to free smb_read_data buf before exit */ if(smb_read_data) { cifs_buf_release(smb_read_data); - smb_read_data = 0; + smb_read_data = NULL; } FreeXid(xid); @@ -1463,9 +1463,13 @@ unix_fill_in_inode(struct inode *tmp_ino } else if (pfindData->Type == UNIX_CHARDEV) { *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (pfindData->Type == UNIX_BLOCKDEV) { *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (pfindData->Type == UNIX_FIFO) { *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; @@ -1682,7 +1686,14 @@ cifs_readdir(struct file *file, void *di data = kmalloc(bufsize, GFP_KERNEL); pfindData = (FILE_DIRECTORY_INFO *) data; + if(file->f_dentry == NULL) { + FreeXid(xid); + return -EIO; + } + down(&file->f_dentry->d_sb->s_vfs_rename_sem); full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); --- linux-2.6.8-rc1/fs/cifs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/inode.c 2004-07-13 17:09:13.592206544 -0700 @@ -110,8 +110,12 @@ cifs_get_inode_info_unix(struct inode ** inode->i_mode |= S_IFDIR; } else if (findData.Type == UNIX_CHARDEV) { inode->i_mode |= S_IFCHR; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); } else if (findData.Type == UNIX_BLOCKDEV) { inode->i_mode |= S_IFBLK; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); } else if (findData.Type == UNIX_FIFO) { inode->i_mode |= S_IFIFO; } else if (findData.Type == UNIX_SOCKET) { --- linux-2.6.8-rc1/fs/cifs/misc.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/cifs/misc.c 2004-07-13 17:09:13.593206392 -0700 @@ -150,7 +150,7 @@ tconInfoFree(struct cifsTconInfo *buf_to struct smb_hdr * cifs_buf_get(void) { - struct smb_hdr *ret_buf = 0; + struct smb_hdr *ret_buf = NULL; /* We could use negotiated size instead of max_msgsize - but it may be more efficient to always alloc same size --- linux-2.6.8-rc1/fs/cifs/README 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/cifs/README 2004-07-13 17:09:13.000000000 -0700 @@ -101,10 +101,11 @@ Linux: Note that ea support is required for supporting Linux xattrs. Some administrators also change the "map archive" and the "create mask" -parameters from their default values. Creating special devices (mknod) remotely -may require specifying a mkdev function to Samba. For more information on these -see the manual pages ("man smb.conf") on the Samba server system. Note that the -cifs vfs, unlike the smbfs vfs, does not read the smb.conf on the client system +parameters from their default values. Creating special devices (mknod) +remotely may require specifying a mkdev function to Samba if you are not using +Samba 3.0.5 or later. For more information on these see the manual pages +("man smb.conf") on the Samba server system. Note that the cifs vfs, +unlike the smbfs vfs, does not read the smb.conf on the client system (the few optional settings are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete open files (required for strict POSIX compliance). Windows Servers already --- linux-2.6.8-rc1/fs/cifs/TODO 2004-06-15 23:29:43.000000000 -0700 +++ 25/fs/cifs/TODO 2004-07-13 17:09:13.000000000 -0700 @@ -82,7 +82,7 @@ but recognizes them succeed but still return access denied (appears to be Windows server not cifs client problem) and has not been reproduced recently. NTFS partitions do not have this problem. -4) debug connectation lock test case 10 which fails against +4) debug connectathon lock test case 10 which fails against Samba (may be unmappable due to POSIX to Windows lock model differences but worth investigating). Also debug Samba to see why lock test case 7 takes longer to complete to Samba @@ -91,7 +91,7 @@ than to Windows. Misc testing to do ================== 1) check out max path names and max path name components against various server -types. Return max path name in stat -f information +types. Try nested symlinks. Return max path name in stat -f information 2) Modify file portion of ltp so it can run against a mounted network share and run it against cifs vfs. --- linux-2.6.8-rc1/fs/coda/inode.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/coda/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -142,7 +142,7 @@ static int get_device_index(struct coda_ static int coda_fill_super(struct super_block *sb, void *data, int silent) { - struct inode *root = 0; + struct inode *root = NULL; struct coda_sb_info *sbi = NULL; struct venus_comm *vc = NULL; struct CodaFid fid; --- linux-2.6.8-rc1/fs/coda/psdev.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/coda/psdev.c 2004-07-13 17:09:13.000000000 -0700 @@ -296,7 +296,7 @@ static int coda_psdev_open(struct inode INIT_LIST_HEAD(&vcp->vc_pending); INIT_LIST_HEAD(&vcp->vc_processing); init_waitqueue_head(&vcp->vc_waitq); - vcp->vc_sb = 0; + vcp->vc_sb = NULL; vcp->vc_seq = 0; } --- linux-2.6.8-rc1/fs/coda/sysctl.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/coda/sysctl.c 2004-07-13 17:09:13.000000000 -0700 @@ -240,7 +240,7 @@ void coda_sysctl_clean(void) #ifdef CONFIG_SYSCTL if ( fs_table_header ) { unregister_sysctl_table(fs_table_header); - fs_table_header = 0; + fs_table_header = NULL; } #endif --- linux-2.6.8-rc1/fs/compat.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/compat.c 2004-07-13 17:09:36.000000000 -0700 @@ -824,7 +824,7 @@ static int compat_fillonedir(void *__buf return -EINVAL; buf->result++; dirent = buf->dirent; - if (!access_ok(VERIFY_WRITE, (unsigned long)dirent, + if (!access_ok(VERIFY_WRITE, dirent, (unsigned long)(dirent->d_name + namlen + 1) - (unsigned long)dirent)) goto efault; @@ -1373,14 +1373,14 @@ int compat_do_execve(char * filename, int retval; int i; - sched_balance_exec(); - file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) return retval; + sched_exec(); + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); --- linux-2.6.8-rc1/fs/compat_ioctl.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/compat_ioctl.c 2004-07-13 17:09:22.000000000 -0700 @@ -115,6 +115,8 @@ #include #include +#include + #undef INCLUDES #endif @@ -257,66 +259,6 @@ struct video_window32 { compat_int_t clipcount; }; -static void free_kvideo_clips(struct video_window *kp) -{ - struct video_clip *cp; - - cp = kp->clips; - if(cp != NULL) - kfree(cp); -} - -static int get_video_window32(struct video_window *kp, struct video_window32 __user *up) -{ - struct video_clip32 __user *ucp; - struct video_clip *kcp; - int nclips, err, i; - u32 tmp; - - if(get_user(kp->x, &up->x)) - return -EFAULT; - __get_user(kp->y, &up->y); - __get_user(kp->width, &up->width); - __get_user(kp->height, &up->height); - __get_user(kp->chromakey, &up->chromakey); - __get_user(kp->flags, &up->flags); - __get_user(kp->clipcount, &up->clipcount); - __get_user(tmp, &up->clips); - ucp = compat_ptr(tmp); - kp->clips = NULL; - - nclips = kp->clipcount; - if(nclips == 0) - return 0; - - if(ucp == 0) - return -EINVAL; - - /* Peculiar interface... */ - if(nclips < 0) - nclips = VIDEO_CLIPMAP_SIZE; - - kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); - err = -ENOMEM; - if(kcp == NULL) - goto cleanup_and_err; - - kp->clips = kcp; - for(i = 0; i < nclips; i++) { - __get_user(kcp[i].x, &ucp[i].x); - __get_user(kcp[i].y, &ucp[i].y); - __get_user(kcp[i].width, &ucp[i].width); - __get_user(kcp[i].height, &ucp[i].height); - kcp[nclips].next = NULL; - } - - return 0; - -cleanup_and_err: - free_kvideo_clips(kp); - return err; -} - /* You get back everything except the clips... */ static int put_video_window32(struct video_window *kp, struct video_window32 __user *up) { @@ -340,6 +282,66 @@ static int put_video_window32(struct vid #define VIDIOCGFREQ32 _IOR('v',14, u32) #define VIDIOCSFREQ32 _IOW('v',15, u32) +enum { + MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip) +}; + +static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct video_window32 __user *up = compat_ptr(arg); + struct video_window __user *vw; + struct video_clip __user *p; + int nclips; + u32 n; + + if (get_user(nclips, &up->clipcount)) + return -EFAULT; + + /* Peculiar interface... */ + if (nclips < 0) + nclips = VIDEO_CLIPMAP_SIZE; + + if (nclips > MaxClips) + return -ENOMEM; + + vw = compat_alloc_user_space(sizeof(struct video_window) + + nclips * sizeof(struct video_clip)); + + p = nclips ? (struct video_clip __user *)(vw + 1) : NULL; + + if (get_user(n, &up->x) || put_user(n, &vw->x) || + get_user(n, &up->y) || put_user(n, &vw->y) || + get_user(n, &up->width) || put_user(n, &vw->width) || + get_user(n, &up->height) || put_user(n, &vw->height) || + get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) || + get_user(n, &up->flags) || put_user(n, &vw->flags) || + get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) || + get_user(n, &up->clips) || put_user(p, &vw->clips)) + return -EFAULT; + + if (nclips) { + struct video_clip32 __user *u = compat_ptr(n); + int i; + if (!u) + return -EINVAL; + for (i = 0; i < nclips; i++, u++, p++) { + s32 v; + if (get_user(v, &u->x) || + put_user(v, &p->x) || + get_user(v, &u->y) || + put_user(v, &p->y) || + get_user(v, &u->width) || + put_user(v, &p->width) || + get_user(v, &u->height) || + put_user(v, &p->height) || + put_user(NULL, &p->next)) + return -EFAULT; + } + } + + return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p); +} + static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { union { @@ -357,7 +359,6 @@ static int do_video_ioctl(unsigned int f case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; - case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; @@ -370,10 +371,6 @@ static int do_video_ioctl(unsigned int f err = get_video_tuner32(&karg.vt, up); break; - case VIDIOCSWIN: - err = get_video_window32(&karg.vw, up); - break; - case VIDIOCSFBUF: err = get_video_buffer32(&karg.vb, up); break; @@ -389,9 +386,6 @@ static int do_video_ioctl(unsigned int f err = sys_ioctl(fd, cmd, (unsigned long)&karg); set_fs(old_fs); - if(cmd == VIDIOCSWIN) - free_kvideo_clips(&karg.vw); - if(err == 0) { switch(cmd) { case VIDIOCGTUNER: @@ -2525,54 +2519,15 @@ struct usbdevfs_ctrltransfer32 { static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct usbdevfs_ctrltransfer kctrl; - struct usbdevfs_ctrltransfer32 __user *uctrl; - mm_segment_t old_fs; + struct usbdevfs_ctrltransfer32 __user *p32 = compat_ptr(arg); + struct usbdevfs_ctrltransfer __user *p; __u32 udata; - void __user *uptr; - void *kptr; - int err; - - uctrl = compat_ptr(arg); - - if (copy_from_user(&kctrl, uctrl, - (sizeof(struct usbdevfs_ctrltransfer32) - - sizeof(compat_caddr_t)))) - return -EFAULT; - - if (get_user(udata, &uctrl->data)) - return -EFAULT; - uptr = compat_ptr(udata); - /* In usbdevice_fs, it limits the control buffer to a page, - * for simplicity so do we. - */ - if (!uptr || kctrl.wLength > PAGE_SIZE) - return -EINVAL; - - kptr = (void *)__get_free_page(GFP_KERNEL); - - if ((kctrl.bRequestType & USB_DIR_IN) == 0) { - err = -EFAULT; - if (copy_from_user(kptr, uptr, kctrl.wLength)) - goto out; - } - - kctrl.data = kptr; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl); - set_fs(old_fs); - - if (err >= 0 && - ((kctrl.bRequestType & USB_DIR_IN) != 0)) { - if (copy_to_user(uptr, kptr, kctrl.wLength)) - err = -EFAULT; - } - -out: - free_page((unsigned long) kptr); - return err; + p = compat_alloc_user_space(sizeof(*p)); + if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || + get_user(udata, &p32->data) || + put_user(compat_ptr(udata), &p->data)) + return -EFAULT; + return sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)p); } @@ -2587,54 +2542,20 @@ struct usbdevfs_bulktransfer32 { static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct usbdevfs_bulktransfer kbulk; - struct usbdevfs_bulktransfer32 __user *ubulk; - mm_segment_t old_fs; - __u32 udata; - void __user *uptr; - void *kptr; - int err; - - ubulk = compat_ptr(arg); - - if (get_user(kbulk.ep, &ubulk->ep) || - get_user(kbulk.len, &ubulk->len) || - get_user(kbulk.timeout, &ubulk->timeout) || - get_user(udata, &ubulk->data)) + struct usbdevfs_bulktransfer32 __user *p32 = compat_ptr(arg); + struct usbdevfs_bulktransfer __user *p; + compat_uint_t n; + compat_caddr_t addr; + + p = compat_alloc_user_space(sizeof(*p)); + + if (get_user(n, &p32->ep) || put_user(n, &p->ep) || + get_user(n, &p32->len) || put_user(n, &p->len) || + get_user(n, &p32->timeout) || put_user(n, &p->timeout) || + get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) return -EFAULT; - uptr = compat_ptr(udata); - - /* In usbdevice_fs, it limits the control buffer to a page, - * for simplicity so do we. - */ - if (!uptr || kbulk.len > PAGE_SIZE) - return -EINVAL; - - kptr = (void *) __get_free_page(GFP_KERNEL); - - if ((kbulk.ep & 0x80) == 0) { - err = -EFAULT; - if (copy_from_user(kptr, uptr, kbulk.len)) - goto out; - } - - kbulk.data = kptr; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk); - set_fs(old_fs); - - if (err >= 0 && - ((kbulk.ep & 0x80) != 0)) { - if (copy_to_user(uptr, kptr, kbulk.len)) - err = -EFAULT; - } - -out: - free_page((unsigned long) kptr); - return err; + return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p); } /* This needs more work before we can enable it. Unfortunately @@ -3342,7 +3263,7 @@ HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_e HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSWIN32, do_set_window) HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) --- linux-2.6.8-rc1/fs/dcache.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/dcache.c 2004-07-13 17:35:41.000000000 -0700 @@ -379,6 +379,11 @@ static void prune_dcache(int count) struct dentry *dentry; struct list_head *tmp; + if (unlikely((count & 255) == 0)) { + spin_unlock(&dcache_lock); + cpu_relax(); + spin_lock(&dcache_lock); + } tmp = dentry_unused.prev; if (tmp == &dentry_unused) break; --- linux-2.6.8-rc1/fs/exec.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/exec.c 2004-07-13 17:09:38.000000000 -0700 @@ -546,6 +546,7 @@ static int exec_mmap(struct mm_struct *m tsk->active_mm = mm; activate_mm(active_mm, mm); task_unlock(tsk); + arch_pick_mmap_layout(mm); if (old_mm) { if (active_mm != old_mm) BUG(); mmput(old_mm); @@ -1081,7 +1082,7 @@ int do_execve(char * filename, if (IS_ERR(file)) return retval; - sched_balance_exec(); + sched_exec(); bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); --- linux-2.6.8-rc1/fs/ext2/acl.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/fs/ext2/acl.c 2004-07-13 17:09:13.000000000 -0700 @@ -161,7 +161,7 @@ ext2_get_acl(struct inode *inode, int ty int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; + return NULL; switch(type) { case ACL_TYPE_ACCESS: --- linux-2.6.8-rc1/fs/ext2/xattr.c 2004-02-17 20:48:45.000000000 -0800 +++ 25/fs/ext2/xattr.c 2004-07-13 17:09:13.000000000 -0700 @@ -772,7 +772,8 @@ ext2_xattr_set2(struct inode *inode, str s_first_data_block) + EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); - int block = ext2_new_block(inode, goal, 0, 0, &error); + int block = ext2_new_block(inode, goal, + NULL, NULL, &error); if (error) goto cleanup; ea_idebug(inode, "creating block %d", block); --- linux-2.6.8-rc1/fs/ext3/acl.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ext3/acl.c 2004-07-13 17:09:13.000000000 -0700 @@ -164,7 +164,7 @@ ext3_get_acl(struct inode *inode, int ty int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; + return NULL; switch(type) { case ACL_TYPE_ACCESS: --- linux-2.6.8-rc1/fs/ext3/balloc.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ext3/balloc.c 2004-07-13 17:09:35.000000000 -0700 @@ -96,9 +96,87 @@ read_block_bitmap(struct super_block *sb error_out: return bh; } +/* + * The reservation window structure operations + * -------------------------------------------- + * Operations include: + * dump, find, add, remove, is_empty, find_next_reservable_window, etc. + * + * We use sorted double linked list for the per-filesystem reservation + * window list. (like in vm_region). + * + * Initially, we keep those small operations in the abstract functions, + * so later if we need a better searching tree than double linked-list, + * we could easily switch to that without changing too much + * code. + */ +static inline void rsv_window_dump(struct reserve_window *head, char *fn) +{ + struct reserve_window *rsv; + + printk("Block Allocation Reservation Windows Map (%s):\n", fn); + list_for_each_entry(rsv, &head->rsv_list, rsv_list) { + printk("reservation window 0x%p start: %d, end: %d\n", + rsv, rsv->rsv_start, rsv->rsv_end); + } +} + +static int +goal_in_my_reservation(struct reserve_window *rsv, int goal, + unsigned int group, struct super_block * sb) +{ + unsigned long group_first_block, group_last_block; + + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + + if ((rsv->rsv_start > group_last_block) || + (rsv->rsv_end < group_first_block)) + return 0; + if ((goal >= 0) && ((goal + group_first_block < rsv->rsv_start) + || (goal + group_first_block > rsv->rsv_end))) + return 0; + return 1; +} + +static inline void rsv_window_add(struct reserve_window *rsv, + struct reserve_window *prev) +{ + /* insert the new reservation window after the head */ + list_add(&rsv->rsv_list, &prev->rsv_list); +} + +static inline void rsv_window_remove(struct reserve_window *rsv) +{ + rsv->rsv_start = 0; + rsv->rsv_end = 0; + rsv->rsv_alloc_hit = 0; + list_del(&rsv->rsv_list); + INIT_LIST_HEAD(&rsv->rsv_list); +} + +static inline int rsv_is_empty(struct reserve_window *rsv) +{ + /* a valid reservation end block could not be 0 */ + return (rsv->rsv_end == 0); +} + +void ext3_discard_reservation(struct inode *inode) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + struct reserve_window *rsv = &ei->i_rsv_window; + spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; + + if (!rsv_is_empty(rsv)) { + spin_lock(rsv_lock); + rsv_window_remove(rsv); + spin_unlock(rsv_lock); + } +} /* Free given blocks, update quota and i_blocks field */ -void ext3_free_blocks (handle_t *handle, struct inode * inode, +void ext3_free_blocks(handle_t *handle, struct inode *inode, unsigned long block, unsigned long count) { struct buffer_head *bitmap_bh = NULL; @@ -275,7 +353,7 @@ do_more: error_return: brelse(bitmap_bh); ext3_std_error(sb, err); - if (dquot_freed_blocks) + if (dquot_freed_blocks && !(EXT3_I(inode)->i_state & EXT3_STATE_RESIZE)) DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); return; } @@ -296,7 +374,7 @@ error_return: * data-writes at some point, and disable it for metadata allocations or * sync-data inodes. */ -static inline int ext3_test_allocatable(int nr, struct buffer_head *bh) +static int ext3_test_allocatable(int nr, struct buffer_head *bh) { int ret; struct journal_head *jh = bh2jh(bh); @@ -313,6 +391,33 @@ static inline int ext3_test_allocatable( return ret; } +static int +bitmap_search_next_usable_block(int start, struct buffer_head *bh, + int maxblocks) +{ + int next; + struct journal_head *jh = bh2jh(bh); + + /* + * The bitmap search --- search forward alternately through the actual + * bitmap and the last-committed copy until we find a bit free in + * both + */ + while (start < maxblocks) { + next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start); + if (next >= maxblocks) + return -1; + if (ext3_test_allocatable(next, bh)) + return next; + jbd_lock_bh_state(bh); + if (jh->b_committed_data) + start = ext3_find_next_zero_bit(jh->b_committed_data, + maxblocks, next); + jbd_unlock_bh_state(bh); + } + return -1; +} + /* * Find an allocatable block in a bitmap. We honour both the bitmap and * its last-committed copy (if that exists), and perform the "most @@ -325,7 +430,6 @@ find_next_usable_block(int start, struct { int here, next; char *p, *r; - struct journal_head *jh = bh2jh(bh); if (start > 0) { /* @@ -337,6 +441,8 @@ find_next_usable_block(int start, struct * next 64-bit boundary is simple.. */ int end_goal = (start + 63) & ~63; + if (end_goal > maxblocks) + end_goal = maxblocks; here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); if (here < end_goal && ext3_test_allocatable(here, bh)) return here; @@ -351,7 +457,7 @@ find_next_usable_block(int start, struct r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *)bh->b_data)) << 3; - if (next < maxblocks && ext3_test_allocatable(next, bh)) + if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) return next; /* @@ -359,19 +465,8 @@ find_next_usable_block(int start, struct * bitmap and the last-committed copy until we find a bit free in * both */ - while (here < maxblocks) { - next = ext3_find_next_zero_bit(bh->b_data, maxblocks, here); - if (next >= maxblocks) - return -1; - if (ext3_test_allocatable(next, bh)) - return next; - jbd_lock_bh_state(bh); - if (jh->b_committed_data) - here = ext3_find_next_zero_bit(jh->b_committed_data, - maxblocks, next); - jbd_unlock_bh_state(bh); - } - return -1; + here = bitmap_search_next_usable_block(here, bh, maxblocks); + return here; } /* @@ -407,62 +502,464 @@ claim_block(spinlock_t *lock, int block, */ static int ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, - struct buffer_head *bitmap_bh, int goal, int *errp) + struct buffer_head *bitmap_bh, int goal, struct reserve_window *my_rsv) { - int i; - int fatal; - int credits = 0; + int group_first_block, start, end; - *errp = 0; - - /* - * Make sure we use undo access for the bitmap, because it is critical - * that we do the frozen_data COW on bitmap buffers in all cases even - * if the buffer is in BJ_Forget state in the committing transaction. - */ - BUFFER_TRACE(bitmap_bh, "get undo access for new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits); - if (fatal) { - *errp = fatal; - goto fail; + /* we do allocation within the reservation window if we have a window */ + if (my_rsv) { + group_first_block = + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + if (my_rsv->rsv_start >= group_first_block) + start = my_rsv->rsv_start - group_first_block; + else + /* reservation window cross group boundary */ + start = 0; + end = my_rsv->rsv_end - group_first_block + 1; + if (end > EXT3_BLOCKS_PER_GROUP(sb)) + /* reservation window crosses group boundary */ + end = EXT3_BLOCKS_PER_GROUP(sb); + if ((start <= goal) && (goal < end)) + start = goal; + else + goal = -1; + } else { + if (goal > 0) + start = goal; + else + start = 0; + end = EXT3_BLOCKS_PER_GROUP(sb); } + BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb)); + repeat: if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) { - goal = find_next_usable_block(goal, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); + goal = find_next_usable_block(start, bitmap_bh, end); if (goal < 0) goto fail_access; + if (!my_rsv) { + int i; - for (i = 0; i < 7 && goal > 0 && - ext3_test_allocatable(goal - 1, bitmap_bh); - i++, goal--); + for (i = 0; i < 7 && goal > start && + ext3_test_allocatable(goal - 1, + bitmap_bh); + i++, goal--) + ; + } } + start = goal; if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) { /* * The block was allocated by another thread, or it was * allocated and then freed by another thread */ + start++; goal++; - if (goal >= EXT3_BLOCKS_PER_GROUP(sb)) + if (start >= end) goto fail_access; goto repeat; } + if (my_rsv) + my_rsv->rsv_alloc_hit++; + return goal; +fail_access: + return -1; +} + +/** + * find_next_reservable_window(): + * find a reservable space within the given range + * It does not allocate the reservation window for now + * alloc_new_reservation() will do the work later. + * + * @search_head: the head of the searching list; + * This is not necessary the list head of the whole filesystem + * + * we have both head and start_block to assist the search + * for the reservable space. The list start from head, + * but we will shift to the place where start_block is, + * then start from there, we looking for a resevable space. + * + * @fs_rsv_head: per-filesystem reervation list head. + * + * @size: the target new reservation window size + * @group_first_block: the first block we consider to start + * the real search from + * + * @last_block: + * the maxium block number that our goal reservable space + * could start from. This is normally the last block in this + * group. The search will end when we found the start of next + * possiblereservable space is out of this boundary. + * This could handle the cross bounday reservation window request. + * + * basically we search from the given range, rather than the whole + * reservation double linked list, (start_block, last_block) + * to find a free region that of of my size and has not + * been reserved. + * + * on succeed, it returns the reservation window to be append to. + * failed, return NULL. + */ +static inline +struct reserve_window *find_next_reservable_window( + struct reserve_window *search_head, + struct reserve_window *fs_rsv_head, + unsigned long size, int *start_block, + int last_block) +{ + struct reserve_window *rsv; + int cur; + + /* TODO:make the start of the reservation window byte alligned */ + /*cur = *start_block & 8;*/ + cur = *start_block; + rsv = list_entry(search_head->rsv_list.next, + struct reserve_window, rsv_list); + while (rsv != fs_rsv_head) { + if (cur + size <= rsv->rsv_start) { + /* + * Found a reserveable space big enough. We could + * have a reservation across the group boundary here + */ + break; + } + if (cur <= rsv->rsv_end) + cur = rsv->rsv_end + 1; - BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); - fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + /* TODO? + * in the case we could not find a reservable space + * that is what is expected, during the re-search, we could + * remember what's the largest reservable space we could have + * and return that one. + * + * For now it will fail if we could not find the reservable + * space with expected-size (or more)... + */ + rsv = list_entry(rsv->rsv_list.next, + struct reserve_window, rsv_list); + if (cur > last_block) + return NULL; /* fail */ + } + /* + * we come here either : + * when we rearch to the end of the whole list, + * and there is empty reservable space after last entry in the list. + * append it to the end of the list. + * + * or we found one reservable space in the middle of the list, + * return the reservation window that we could append to. + * succeed. + */ + *start_block = cur; + return list_entry(rsv->rsv_list.prev, struct reserve_window, rsv_list); +} + +/** + * alloc_new_reservation()--allocate a new reservation window + * if there is an existing reservation, discard it first + * then allocate the new one from there + * otherwise allocate the new reservation from the given + * start block, or the beginning of the group, if a goal + * is not given. + * + * To make a new reservation, we search part of the filesystem + * reservation list(the list that inside the group). + * + * If we have a old reservation, the search goal is the end of + * last reservation. If we do not have a old reservatio, then we + * start from a given goal, or the first block of the group, if + * the goal is not given. + * + * We first find a reservable space after the goal, then from + * there,we check the bitmap for the first free block after + * it. If there is no free block until the end of group, then the + * whole group is full, we failed. Otherwise, check if the free + * block is inside the expected reservable space, if so, we + * succeed. + * If the first free block is outside the reseravle space, then + * start from the first free block, we search for next avalibale + * space, and go on. + * + * on succeed, a new reservation will be found and inserted into the list + * It contains at least one free block, and it is not overlap with other + * reservation window. + * + * failed: we failed to found a reservation window in this group + * + * @rsv: the reservation + * + * @goal: The goal. It is where the search for a + * free reservable space should start from. + * if we have a old reservation, start_block is the end of + * old reservation. Otherwise, + * if we have a goal(goal >0 ), then start from there, + * no goal(goal = -1), we start from the first block + * of the group. + * + * @sb: the super block + * @group: the group we are trying to do allocate in + * @bitmap_bh: the block group block bitmap + */ +static int alloc_new_reservation(struct reserve_window *my_rsv, + int goal, struct super_block *sb, + unsigned int group, struct buffer_head *bitmap_bh) +{ + struct reserve_window *search_head; + int group_first_block, group_end_block, start_block; + int first_free_block; + int reservable_space_start; + struct reserve_window *prev_rsv; + struct reserve_window *fs_rsv_head = &EXT3_SB(sb)->s_rsv_window_head; + unsigned long size; + + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1; + + if (goal < 0) + start_block = group_first_block; + else + start_block = goal + group_first_block; + + size = atomic_read(&my_rsv->rsv_goal_size); + /* if we have a old reservation, start the search from the old rsv */ + if (!rsv_is_empty(my_rsv)) { + /* + * if the old reservation is cross group boundary + * we will come here when we just failed to allocate from + * the first part of the window. We still have another part + * that belongs to the next group. In this case, there is no + * point to discard our window and try to allocate a new one + * in this group(which will fail). we should + * keep the reservation window, just simply move on. + * + * Maybe we could shift the start block of the reservation + * window to the first block of next group. + */ + + if ((my_rsv->rsv_start <= group_end_block) && + (my_rsv->rsv_end > group_end_block)) + return -1; + + /* remember where we are before we discard the old one */ + if (my_rsv->rsv_end + 1 > start_block) + start_block = my_rsv->rsv_end + 1; + search_head = my_rsv; + if ((my_rsv->rsv_alloc_hit > (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { + /* + * if we previously allocation hit ration is greater than half + * we double the size of reservation window next time + * otherwise keep the same + */ + size = size * 2; + if (size > EXT3_MAX_RESERVE_BLOCKS) + size = EXT3_MAX_RESERVE_BLOCKS; + atomic_set(&my_rsv->rsv_goal_size, size); + } + } + else { + /* + * we don't have a reservation, + * we set our goal(start_block) and + * the list head for the search + */ + search_head = fs_rsv_head; + } + + /* + * find_next_reservable_window() simply find a reservable window + * inside the given range(start_block, group_end_block). + * + * To make sure the reservation window has a free bit inside it, we + * need to check the bitmap after we found a reservable window. + */ +retry: + prev_rsv = find_next_reservable_window(search_head, fs_rsv_head, size, + &start_block, group_end_block); + if (prev_rsv == NULL) + goto failed; + reservable_space_start = start_block; + /* + * On success, find_next_reservable_window() returns the + * reservation window where there is a reservable space after it. + * Before we reserve this reservable space, we need + * to make sure there is at least a free block inside this region. + * + * searching the first free bit on the block bitmap and copy of + * last committed bitmap alternatively, until we found a allocatable + * block. Search start from the start block of the reservable space + * we just found. + */ + first_free_block = bitmap_search_next_usable_block( + reservable_space_start - group_first_block, + bitmap_bh, group_end_block - group_first_block + 1); + + if (first_free_block < 0) { + /* + * no free block left on the bitmap, no point + * to reserve the space. return failed. + */ + goto failed; + } + start_block = first_free_block + group_first_block; + /* + * check if the first free block is within the + * free space we just found + */ + if ((start_block >= reservable_space_start) && + (start_block < reservable_space_start + size)) + goto found_rsv_window; + /* + * if the first free bit we found is out of the reservable space + * this means there is no free block on the reservable space + * we should continue search for next reservable space, + * start from where the free block is, + * we also shift the list head to where we stopped last time + */ + search_head = prev_rsv; + goto retry; + +found_rsv_window: + /* + * great! the reservable space contains some free blocks. + * if the search returns that we should add the new + * window just next to where the old window, we don't + * need to remove the old window first then add it to the + * same place, just update the new start and new end. + */ + if (my_rsv != prev_rsv) { + if (!rsv_is_empty(my_rsv)) + rsv_window_remove(my_rsv); + rsv_window_add(my_rsv, prev_rsv); + } + my_rsv->rsv_start = reservable_space_start; + my_rsv->rsv_end = my_rsv->rsv_start + size - 1; + return 0; /* succeed */ +failed: + return -1; /* failed */ +} + +/* + * This is the main function used to allocate a new block and its reservation + * window. + * + * Each time when a new block allocation is need, first try to allocate from + * its own reservation. If it does not have a reservation window, instead of + * looking for a free bit on bitmap first, then look up the reservation list to + * see if it is inside somebody else's reservation window, we try to allocate a + * reservation window for it start from the goal first. Then do the block + * allocation within the reservation window. + * + * This will aviod keep searching the reservation list again and again when + * someboday is looking for a free block(without reservation), and there are + * lots of free blocks, but they are all being reserved + * + * We use a sorted double linked list for the per-filesystem reservation list. + * The insert, remove and find a free space(non-reserved) operations for the + * sorted double linked list should be fast. + * + */ +static int +ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, + unsigned int group, struct buffer_head *bitmap_bh, + int goal, struct reserve_window * my_rsv, + int *errp) +{ + spinlock_t *rsv_lock; + unsigned long group_first_block; + int ret = 0; + int fatal; + int credits = 0; + + *errp = 0; + + /* + * Make sure we use undo access for the bitmap, because it is critical + * that we do the frozen_data COW on bitmap buffers in all cases even + * if the buffer is in BJ_Forget state in the committing transaction. + */ + BUFFER_TRACE(bitmap_bh, "get undo access for new block"); + fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits); if (fatal) { *errp = fatal; - goto fail; + return -1; + } + + /* + * we don't deal with reservation when + * filesystem is mounted without reservation + * or the file is not a regular file + * of last attemp of allocating a block with reservation turn on failed + */ + if (my_rsv == NULL ) { + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); + goto out; + } + rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; + /* + * goal is a group relative block number (if there is a goal) + * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb) + * first block is a filesystem wide block number + * first block is the block number of the first block in this group + */ + group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + + group * EXT3_BLOCKS_PER_GROUP(sb); + + /* + * Basically we will allocate a new block from inode's reservation + * window. + * + * We need to allocate a new reservation window, if: + * a) inode does not have a reservation window; or + * b) last attemp of allocating a block from existing reservation + * failed; or + * c) we come here with a goal and with a reservation window + * + * We do not need to allocate a new reservation window if we come here + * at the beginning with a goal and the goal is inside the window, or + * or we don't have a goal but already have a reservation window. + * then we could go to allocate from the reservation window directly. + */ + while (1) { + if (rsv_is_empty(my_rsv) || (ret < 0) || + !goal_in_my_reservation(my_rsv, goal, group, sb)) { + spin_lock(rsv_lock); + ret = alloc_new_reservation(my_rsv, goal, sb, + group, bitmap_bh); + spin_unlock(rsv_lock); + if (ret < 0) + break; /* failed */ + + if (!goal_in_my_reservation(my_rsv, goal, group, sb)) + goal = -1; + } + if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) + || (my_rsv->rsv_end < group_first_block)) + BUG(); + ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, + my_rsv); + if (ret >= 0) + break; /* succeed */ + } +out: + if (ret >= 0) { + BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " + "bitmap block"); + fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + return -1; + } + return ret; } - return goal; -fail_access: BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); ext3_journal_release_buffer(handle, bitmap_bh, credits); -fail: - return -1; + return ret; } static int ext3_has_free_blocks(struct ext3_sb_info *sbi) @@ -503,16 +1000,16 @@ int ext3_should_retry_alloc(struct super * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */ -int -ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, - u32 *prealloc_count, u32 *prealloc_block, int *errp) -{ - struct buffer_head *bitmap_bh = NULL; /* bh */ - struct buffer_head *gdp_bh; /* bh2 */ - int group_no; /* i */ - int ret_block; /* j */ - int bgi; /* blockgroup iteration index */ - int target_block; /* tmp */ +int ext3_new_block(handle_t *handle, struct inode *inode, + unsigned long goal, int *errp) +{ + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *gdp_bh; + int group_no; + int goal_group; + int ret_block; + int bgi; /* blockgroup iteration index */ + int target_block; int fatal = 0, err; int performed_allocation = 0; int free_blocks; @@ -520,6 +1017,7 @@ ext3_new_block(handle_t *handle, struct struct ext3_group_desc *gdp; struct ext3_super_block *es; struct ext3_sb_info *sbi; + struct reserve_window *my_rsv = NULL; #ifdef EXT3FS_DEBUG static int goal_hits, goal_attempts; #endif @@ -541,7 +1039,8 @@ ext3_new_block(handle_t *handle, struct sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; ext3_debug("goal=%lu.\n", goal); - + if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode)) + my_rsv = &EXT3_I(inode)->i_rsv_window; if (!ext3_has_free_blocks(sbi)) { *errp = -ENOSPC; goto out; @@ -559,6 +1058,8 @@ ext3_new_block(handle_t *handle, struct if (!gdp) goto io_error; + goal_group = group_no; +retry: free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); if (free_blocks > 0) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % @@ -566,8 +1067,8 @@ ext3_new_block(handle_t *handle, struct bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - ret_block = ext3_try_to_allocate(sb, handle, group_no, - bitmap_bh, ret_block, &fatal); + ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, + bitmap_bh, ret_block, my_rsv, &fatal); if (fatal) goto out; if (ret_block >= 0) @@ -595,14 +1096,25 @@ ext3_new_block(handle_t *handle, struct bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - ret_block = ext3_try_to_allocate(sb, handle, group_no, - bitmap_bh, -1, &fatal); + ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no, + bitmap_bh, -1, my_rsv, &fatal); if (fatal) goto out; if (ret_block >= 0) goto allocated; } - + /* + * We may end up a bogus ealier ENOSPC error due to + * filesystem is "full" of reservations, but + * there maybe indeed free blocks avaliable on disk + * In this case, we just forget about the reservations + * just do block allocation as without reservations. + */ + if (my_rsv) { + my_rsv = NULL; + group_no = goal_group; + goto retry; + } /* No space left on the device */ *errp = -ENOSPC; goto out; --- linux-2.6.8-rc1/fs/ext3/file.c 2003-10-08 15:07:09.000000000 -0700 +++ 25/fs/ext3/file.c 2004-07-13 17:09:30.000000000 -0700 @@ -33,8 +33,10 @@ */ static int ext3_release_file (struct inode * inode, struct file * filp) { - if (filp->f_mode & FMODE_WRITE) - ext3_discard_prealloc (inode); + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && + (atomic_read(&inode->i_writecount) == 1)) + ext3_discard_reservation(inode); if (is_dx(inode) && filp->private_data) ext3_htree_free_dir_info(filp->private_data); --- linux-2.6.8-rc1/fs/ext3/ialloc.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/fs/ext3/ialloc.c 2004-07-13 17:09:29.000000000 -0700 @@ -581,10 +581,11 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; -#ifdef EXT3_PREALLOCATE - ei->i_prealloc_block = 0; - ei->i_prealloc_count = 0; -#endif + ei->i_rsv_window.rsv_start = 0; + ei->i_rsv_window.rsv_end = 0; + atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); + ei->i_rsv_window.rsv_alloc_hit = 0; + INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list); ei->i_block_group = group; ext3_set_inode_flags(inode); --- linux-2.6.8-rc1/fs/ext3/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ext3/inode.c 2004-07-13 17:09:51.000000000 -0700 @@ -66,6 +66,8 @@ int ext3_forget(handle_t *handle, int is { int err; + might_sleep(); + BUFFER_TRACE(bh, "enter"); jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " @@ -177,19 +179,6 @@ static int ext3_journal_test_restart(han } /* - * Called at each iput() - * - * The inode may be "bad" if ext3_read_inode() saw an error from - * ext3_get_inode(), so we need to check that to avoid freeing random disk - * blocks. - */ -void ext3_put_inode(struct inode *inode) -{ - if (!is_bad_inode(inode)) - ext3_discard_prealloc(inode); -} - -/* * Called at the last iput() if i_nlink is zero. */ void ext3_delete_inode (struct inode * inode) @@ -242,62 +231,12 @@ no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ } -void ext3_discard_prealloc (struct inode * inode) -{ -#ifdef EXT3_PREALLOCATE - struct ext3_inode_info *ei = EXT3_I(inode); - /* Writer: ->i_prealloc* */ - if (ei->i_prealloc_count) { - unsigned short total = ei->i_prealloc_count; - unsigned long block = ei->i_prealloc_block; - ei->i_prealloc_count = 0; - ei->i_prealloc_block = 0; - /* Writer: end */ - ext3_free_blocks (inode, block, total); - } -#endif -} - static int ext3_alloc_block (handle_t *handle, struct inode * inode, unsigned long goal, int *err) { unsigned long result; -#ifdef EXT3_PREALLOCATE -#ifdef EXT3FS_DEBUG - static unsigned long alloc_hits, alloc_attempts; -#endif - struct ext3_inode_info *ei = EXT3_I(inode); - /* Writer: ->i_prealloc* */ - if (ei->i_prealloc_count && - (goal == ei->i_prealloc_block || - goal + 1 == ei->i_prealloc_block)) - { - result = ei->i_prealloc_block++; - ei->i_prealloc_count--; - /* Writer: end */ - ext3_debug ("preallocation hit (%lu/%lu).\n", - ++alloc_hits, ++alloc_attempts); - } else { - ext3_discard_prealloc (inode); - ext3_debug ("preallocation miss (%lu/%lu).\n", - alloc_hits, ++alloc_attempts); - if (S_ISREG(inode->i_mode)) - result = ext3_new_block (inode, goal, - &ei->i_prealloc_count, - &ei->i_prealloc_block, err); - else - result = ext3_new_block(inode, goal, NULL, NULL, err); - /* - * AKPM: this is somewhat sticky. I'm not surprised it was - * disabled in 2.2's ext3. Need to integrate b_committed_data - * guarding with preallocation, if indeed preallocation is - * effective. - */ - } -#else - result = ext3_new_block(handle, inode, goal, NULL, NULL, err); -#endif + result = ext3_new_block(handle, inode, goal, err); return result; } @@ -974,52 +913,17 @@ struct buffer_head *ext3_bread(handle_t int block, int create, int *err) { struct buffer_head * bh; - int prev_blocks; - prev_blocks = inode->i_blocks; - - bh = ext3_getblk (handle, inode, block, create, err); + bh = ext3_getblk(handle, inode, block, create, err); if (!bh) return bh; -#ifdef EXT3_PREALLOCATE - /* - * If the inode has grown, and this is a directory, then use a few - * more of the preallocated blocks to keep directory fragmentation - * down. The preallocated blocks are guaranteed to be contiguous. - */ - if (create && - S_ISDIR(inode->i_mode) && - inode->i_blocks > prev_blocks && - EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_PREALLOC)) { - int i; - struct buffer_head *tmp_bh; - - for (i = 1; - EXT3_I(inode)->i_prealloc_count && - i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks; - i++) { - /* - * ext3_getblk will zero out the contents of the - * directory for us - */ - tmp_bh = ext3_getblk(handle, inode, - block+i, create, err); - if (!tmp_bh) { - brelse (bh); - return 0; - } - brelse (tmp_bh); - } - } -#endif if (buffer_uptodate(bh)) return bh; - ll_rw_block (READ, 1, &bh); - wait_on_buffer (bh); + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; - brelse (bh); + put_bh(bh); *err = -EIO; return NULL; } @@ -2155,7 +2059,7 @@ void ext3_truncate(struct inode * inode) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - ext3_discard_prealloc(inode); + ext3_discard_reservation(inode); /* * We have to lock the EOF page here, because lock_page() nests @@ -2311,8 +2215,10 @@ static unsigned long ext3_get_inode_bloc struct buffer_head *bh; struct ext3_group_desc * gdp; + if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO && + ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) || ino > le32_to_cpu( EXT3_SB(sb)->s_es->s_inodes_count)) { @@ -2548,11 +2454,11 @@ void ext3_read_inode(struct inode * inod } ei->i_disksize = inode->i_size; inode->i_generation = le32_to_cpu(raw_inode->i_generation); -#ifdef EXT3_PREALLOCATE - ei->i_prealloc_count = 0; -#endif ei->i_block_group = iloc.block_group; - + ei->i_rsv_window.rsv_start = 0; + ei->i_rsv_window.rsv_end= 0; + atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); + INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list); /* * NOTE! The in-memory inode i_data array is in little-endian order * even on big-endian machines: we do NOT byteswap the block numbers! @@ -2966,6 +2872,7 @@ int ext3_mark_inode_dirty(handle_t *hand struct ext3_iloc iloc; int err; + might_sleep(); err = ext3_reserve_inode_write(handle, inode, &iloc); if (!err) err = ext3_mark_iloc_dirty(handle, inode, &iloc); --- linux-2.6.8-rc1/fs/ext3/ioctl.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/ext3/ioctl.c 2004-07-13 17:09:35.000000000 -0700 @@ -20,6 +20,7 @@ int ext3_ioctl (struct inode * inode, st { struct ext3_inode_info *ei = EXT3_I(inode); unsigned int flags; + unsigned short rsv_window_size; ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); @@ -151,6 +152,74 @@ flags_err: return ret; } #endif + case EXT3_IOC_GETRSVSZ: + if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) { + rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size); + return put_user(rsv_window_size, (int *)arg); + } + return -ENOTTY; + case EXT3_IOC_SETRSVSZ: + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) + return -ENOTTY; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(rsv_window_size, (int *)arg)) + return -EFAULT; + + if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; + atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size); + return 0; + case EXT3_IOC_GROUP_EXTEND: { + unsigned long n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EACCES; + + if (sb->s_flags & MS_RDONLY) + return -EROFS; + + if (get_user(n_blocks_count, (__u32 *)arg)) + return -EFAULT; + + err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + case EXT3_IOC_GROUP_ADD: { + struct ext3_new_group_data input; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EACCES; + + if (inode->i_sb->s_flags & MS_RDONLY) + return -EROFS; + + if (copy_from_user(&input, (struct ext3_new_group_input *)arg, + sizeof(input))) + return -EFAULT; + + err = ext3_group_add(sb, &input); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + + default: return -ENOTTY; } --- linux-2.6.8-rc1/fs/ext3/Makefile 2003-07-27 12:14:40.000000000 -0700 +++ 25/fs/ext3/Makefile 2004-07-13 17:09:35.000000000 -0700 @@ -5,7 +5,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o + ioctl.o namei.o super.o symlink.o hash.o resize.o ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/ext3/resize.c 2004-07-13 17:09:36.000000000 -0700 @@ -0,0 +1,951 @@ +/* + * linux/fs/ext3/resize.c + * + * Support for resizing an ext3 filesystem while it is mounted. + * + * Copyright (C) 2001, 2002 Andreas Dilger + * + * This could probably be made into a module, because it is not often in use. + */ + +#include + +#define EXT3FS_DEBUG + +#include +#include +#include + +#include +#include + + +#define outside(b, first, last) ((b) < (first) || (b) >= (last)) +#define inside(b, first, last) ((b) >= (first) && (b) < (last)) + +static int verify_group_input(struct super_block *sb, + struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + unsigned start = le32_to_cpu(es->s_blocks_count); + unsigned end = start + input->blocks_count; + unsigned group = input->group; + unsigned itend = input->inode_table + EXT3_SB(sb)->s_itb_per_group; + unsigned overhead = ext3_bg_has_super(sb, group) ? + (1 + ext3_bg_num_gdb(sb, group) + + le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; + unsigned metaend = start + overhead; + struct buffer_head *bh; + int free_blocks_count; + int err = -EINVAL; + + input->free_blocks_count = free_blocks_count = + input->blocks_count - 2 - overhead - sbi->s_itb_per_group; + + if (test_opt(sb, DEBUG)) + printk("EXT3-fs: adding %s group %u: %u blocks " + "(%d free, %u reserved)\n", + ext3_bg_has_super(sb, input->group) ? "normal" : + "no-super", input->group, input->blocks_count, + free_blocks_count, input->reserved_blocks); + + if (group != sbi->s_groups_count) + ext3_warning(sb, __FUNCTION__, + "Cannot add at group %u (only %lu groups)", + input->group, sbi->s_groups_count); + else if ((start - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb)) + ext3_warning(sb, __FUNCTION__, "Last group not full"); + else if (input->reserved_blocks > input->blocks_count / 5) + ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)", + input->reserved_blocks); + else if (free_blocks_count < 0) + ext3_warning(sb, __FUNCTION__, "Bad blocks count %u", + input->blocks_count); + else if (!(bh = sb_bread(sb, end - 1))) + ext3_warning(sb, __FUNCTION__, "Cannot read last block (%u)", + end - 1); + else if (outside(input->block_bitmap, start, end)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap not in group (block %u)", + input->block_bitmap); + else if (outside(input->inode_bitmap, start, end)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap not in group (block %u)", + input->inode_bitmap); + else if (outside(input->inode_table, start, end) || + outside(itend - 1, start, end)) + ext3_warning(sb, __FUNCTION__, + "Inode table not in group (blocks %u-%u)", + input->inode_table, itend - 1); + else if (input->inode_bitmap == input->block_bitmap) + ext3_warning(sb, __FUNCTION__, + "Block bitmap same as inode bitmap (%u)", + input->block_bitmap); + else if (inside(input->block_bitmap, input->inode_table, itend)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap (%u) in inode table (%u-%u)", + input->block_bitmap, input->inode_table, itend-1); + else if (inside(input->inode_bitmap, input->inode_table, itend)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap (%u) in inode table (%u-%u)", + input->inode_bitmap, input->inode_table, itend-1); + else if (inside(input->block_bitmap, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Block bitmap (%u) in GDT table (%u-%u)", + input->block_bitmap, start, metaend - 1); + else if (inside(input->inode_bitmap, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Inode bitmap (%u) in GDT table (%u-%u)", + input->inode_bitmap, start, metaend - 1); + else if (inside(input->inode_table, start, metaend) || + inside(itend - 1, start, metaend)) + ext3_warning(sb, __FUNCTION__, + "Inode table (%u-%u) overlaps GDT table (%u-%u)", + input->inode_table, itend - 1, start, metaend - 1); + else { + brelse(bh); + err = 0; + } + + return err; +} + +static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, + unsigned long blk) +{ + struct buffer_head *bh; + int err; + + bh = sb_getblk(sb, blk); + set_buffer_uptodate(bh); + if ((err = ext3_journal_get_write_access(handle, bh))) { + brelse(bh); + bh = ERR_PTR(err); + } else + memset(bh->b_data, 0, sb->s_blocksize); + + return bh; +} + +/* + * To avoid calling the atomic setbit hundreds or thousands of times, we only + * need to use it within a single byte (to ensure we get endianness right). + * We can use memset for the rest of the bitmap as there are no other users. + */ +static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) +{ + int i; + + if (start_bit >= end_bit) + return; + + ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); + for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) + ext3_set_bit(i, bitmap); + if (i < end_bit) + memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); +} + +/* + * Set up the block and inode bitmaps, and the inode table for the new group. + * This doesn't need to be part of the main transaction, since we are only + * changing blocks outside the actual filesystem. We still do journaling to + * ensure the recovery is correct in case of a failure just after resize. + * If any part of this fails, we simply abort the resize. + * + * We only pass inode because of the ext3 journal wrappers. + */ +static int setup_new_group_blocks(struct super_block *sb, struct inode *inode, + struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long start = input->group * sbi->s_blocks_per_group + + le32_to_cpu(sbi->s_es->s_first_data_block); + int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0; + unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group); + struct buffer_head *bh; + handle_t *handle; + unsigned long block; + int bit; + int i; + int err = 0, err2; + + handle = ext3_journal_start(inode, reserved_gdb + gdblocks + + 2 + sbi->s_itb_per_group); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + lock_super(sb); + if (input->group != sbi->s_groups_count) { + err = -EBUSY; + goto exit_journal; + } + + if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) { + err = PTR_ERR(bh); + goto exit_journal; + } + + if (ext3_bg_has_super(sb, input->group)) { + ext3_debug("mark backup superblock %#04lx (+0)\n", start); + ext3_set_bit(0, bh->b_data); + } + + /* Copy all of the GDT blocks into the backup in this group */ + for (i = 0, bit = 1, block = start + 1; + i < gdblocks; i++, block++, bit++) { + struct buffer_head *gdb; + + ext3_debug("update backup group %#04lx (+%d)\n", block, bit); + + gdb = sb_getblk(sb, block); + set_buffer_uptodate(gdb); + if ((err = ext3_journal_get_write_access(handle, gdb))) { + brelse(gdb); + goto exit_bh; + } + memcpy(gdb->b_data, sbi->s_group_desc[i], bh->b_size); + ext3_journal_dirty_metadata(handle, gdb); + ext3_set_bit(bit, bh->b_data); + brelse(gdb); + } + + /* Zero out all of the reserved backup group descriptor table blocks */ + for (i = 0, bit = gdblocks + 1, block = start + bit; + i < reserved_gdb; i++, block++, bit++) { + struct buffer_head *gdb; + + ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); + + if (IS_ERR(gdb = bclean(handle, sb, block))) { + err = PTR_ERR(bh); + goto exit_bh; + } + ext3_journal_dirty_metadata(handle, gdb); + ext3_set_bit(bit, bh->b_data); + brelse(gdb); + } + ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, + input->block_bitmap - start); + ext3_set_bit(input->block_bitmap - start, bh->b_data); + ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, + input->inode_bitmap - start); + ext3_set_bit(input->inode_bitmap - start, bh->b_data); + + /* Zero out all of the inode table blocks */ + for (i = 0, block = input->inode_table, bit = block - start; + i < sbi->s_itb_per_group; i++, bit++, block++) { + struct buffer_head *it; + + ext3_debug("clear inode block %#04x (+%ld)\n", block, bit); + if (IS_ERR(it = bclean(handle, sb, block))) { + err = PTR_ERR(it); + goto exit_bh; + } + ext3_journal_dirty_metadata(handle, it); + brelse(it); + ext3_set_bit(bit, bh->b_data); + } + mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), + bh->b_data); + ext3_journal_dirty_metadata(handle, bh); + brelse(bh); + + /* Mark unused entries in inode bitmap used */ + ext3_debug("clear inode bitmap %#04x (+%ld)\n", + input->inode_bitmap, input->inode_bitmap - start); + if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) { + err = PTR_ERR(bh); + goto exit_journal; + } + + mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb), + bh->b_data); + ext3_journal_dirty_metadata(handle, bh); +exit_bh: + brelse(bh); + +exit_journal: + unlock_super(sb); + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + + return err; +} + +/* + * Iterate through the groups which hold BACKUP superblock/GDT copies in an + * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before + * calling this for the first time. In a sparse filesystem it will be the + * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... + * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... + */ +unsigned ext3_list_backups(struct super_block *sb, unsigned *three, + unsigned *five, unsigned *seven) +{ + unsigned *min = three; + int mult = 3; + unsigned ret; + + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + ret = *min; + *min += 1; + return ret; + } + + if (*five < *min) { + min = five; + mult = 5; + } + if (*seven < *min) { + min = seven; + mult = 7; + } + + ret = *min; + *min *= mult; + + return ret; +} + +/* + * Check that all of the backup GDT blocks are held in the primary GDT block. + * It is assumed that they are stored in group order. Returns the number of + * groups in current filesystem that have BACKUPS, or -ve error code. + */ +static int verify_reserved_gdb(struct super_block *sb, + struct buffer_head *primary) +{ + const unsigned long blk = primary->b_blocknr; + const unsigned long end = EXT3_SB(sb)->s_groups_count; + unsigned three = 1; + unsigned five = 5; + unsigned seven = 7; + unsigned grp; + __u32 *p = (__u32 *)primary->b_data; + int gdbackups = 0; + + while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { + if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ + ext3_warning(sb, __FUNCTION__, + "reserved GDT %ld missing grp %d (%ld)\n", + blk, grp, + grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); + return -EINVAL; + } + if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) + return -EFBIG; + } + + return gdbackups; +} + +/* + * Called when we need to bring a reserved group descriptor table block into + * use from the resize inode. The primary copy of the new GDT block currently + * is an indirect block (under the double indirect block in the resize inode). + * The new backup GDT blocks will be stored as leaf blocks in this indirect + * block, in group order. Even though we know all the block numbers we need, + * we check to ensure that the resize inode has actually reserved these blocks. + * + * Don't need to update the block bitmaps because the blocks are still in use. + * + * We get all of the error cases out of the way, so that we are sure to not + * fail once we start modifying the data on disk, because JBD has no rollback. + */ +static int add_new_gdb(handle_t *handle, struct inode *inode, + struct ext3_new_group_data *input, + struct buffer_head **primary) +{ + struct super_block *sb = inode->i_sb; + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); + unsigned long gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; + struct buffer_head **o_group_desc, **n_group_desc; + struct buffer_head *dind; + int gdbackups; + struct ext3_iloc iloc; + __u32 *data; + int err; + + if (test_opt(sb, DEBUG)) + printk("EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", + gdb_num); + + /* + * If we are not using the primary superblock/GDT copy don't resize, + * because the user tools have no way of handling this. Probably a + * bad time to do it anyways. + */ + if (EXT3_SB(sb)->s_sbh->b_blocknr != + le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { + ext3_warning(sb, __FUNCTION__, + "won't resize using backup superblock at %llu\n", + (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); + return -EPERM; + } + + *primary = sb_bread(sb, gdblock); + if (!*primary) + return -EIO; + + if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { + err = gdbackups; + goto exit_bh; + } + + data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + dind = sb_bread(sb, le32_to_cpu(*data)); + if (!dind) { + err = -EIO; + goto exit_bh; + } + + data = (__u32 *)dind->b_data; + if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { + ext3_warning(sb, __FUNCTION__, + "new group %u GDT block %lu not reserved\n", + input->group, gdblock); + err = -EINVAL; + goto exit_dind; + } + + if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) + goto exit_dind; + + if ((err = ext3_journal_get_write_access(handle, *primary))) + goto exit_sbh; + + if ((err = ext3_journal_get_write_access(handle, dind))) + goto exit_primary; + + /* ext3_reserve_inode_write() gets a reference on the iloc */ + if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + goto exit_dindj; + + n_group_desc = (struct buffer_head **)kmalloc((gdb_num + 1) * + sizeof(struct buffer_head *), GFP_KERNEL); + if (!n_group_desc) { + err = -ENOMEM; + ext3_warning (sb, __FUNCTION__, + "not enough memory for %lu groups", gdb_num + 1); + goto exit_inode; + } + + /* + * Finally, we have all of the possible failures behind us... + * + * Remove new GDT block from inode double-indirect block and clear out + * the new GDT block for use (which also "frees" the backup GDT blocks + * from the reserved inode). We don't need to change the bitmaps for + * these blocks, because they are marked as in-use from being in the + * reserved inode, and will become GDT blocks (primary and backup). + */ + data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; + ext3_journal_dirty_metadata(handle, dind); + brelse(dind); + inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; + ext3_mark_iloc_dirty(handle, inode, &iloc); + memset((*primary)->b_data, 0, sb->s_blocksize); + ext3_journal_dirty_metadata(handle, *primary); + + o_group_desc = EXT3_SB(sb)->s_group_desc; + memcpy(n_group_desc, o_group_desc, + EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); + n_group_desc[gdb_num] = *primary; + EXT3_SB(sb)->s_group_desc = n_group_desc; + EXT3_SB(sb)->s_gdb_count++; + kfree(o_group_desc); + + es->s_reserved_gdt_blocks = + cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1); + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + + return 0; + +exit_inode: + //ext3_journal_release_buffer(handle, iloc.bh); + brelse(iloc.bh); +exit_dindj: + //ext3_journal_release_buffer(handle, dind); +exit_primary: + //ext3_journal_release_buffer(handle, *primary); +exit_sbh: + //ext3_journal_release_buffer(handle, *primary); +exit_dind: + brelse(dind); +exit_bh: + brelse(*primary); + + ext3_debug("leaving with error %d\n", err); + return err; +} + +/* + * Called when we are adding a new group which has a backup copy of each of + * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. + * We need to add these reserved backup GDT blocks to the resize inode, so + * that they are kept for future resizing and not allocated to files. + * + * Each reserved backup GDT block will go into a different indirect block. + * The indirect blocks are actually the primary reserved GDT blocks, + * so we know in advance what their block numbers are. We only get the + * double-indirect block to verify it is pointing to the primary reserved + * GDT blocks so we don't overwrite a data block by accident. The reserved + * backup GDT blocks are stored in their reserved primary GDT block. + */ +static int reserve_backup_gdb(handle_t *handle, struct inode *inode, + struct ext3_new_group_data *input) +{ + struct super_block *sb = inode->i_sb; + int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); + struct buffer_head **primary; + struct buffer_head *dind; + struct ext3_iloc iloc; + unsigned long blk; + __u32 *data, *end; + int gdbackups = 0; + int res, i; + int err; + + primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL); + if (!primary) + return -ENOMEM; + + data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; + dind = sb_bread(sb, le32_to_cpu(*data)); + if (!dind) { + err = -EIO; + goto exit_free; + } + + blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; + data = (__u32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count; + end = (__u32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); + + /* Get each reserved primary GDT block and verify it holds backups */ + for (res = 0; res < reserved_gdb; res++, blk++) { + if (le32_to_cpu(*data) != blk) { + ext3_warning(sb, __FUNCTION__, + "reserved block %lu not at offset %ld\n", + blk, (long)(data - (__u32 *)dind->b_data)); + err = -EINVAL; + goto exit_bh; + } + primary[res] = sb_bread(sb, blk); + if (!primary[res]) { + err = -EIO; + goto exit_bh; + } + if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) { + brelse(primary[res]); + err = gdbackups; + goto exit_bh; + } + if (++data >= end) + data = (__u32 *)dind->b_data; + } + + for (i = 0; i < reserved_gdb; i++) { + if ((err = ext3_journal_get_write_access(handle, primary[i]))) { + /* + int j; + for (j = 0; j < i; j++) + ext3_journal_release_buffer(handle, primary[j]); + */ + goto exit_bh; + } + } + + if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) + goto exit_bh; + + /* + * Finally we can add each of the reserved backup GDT blocks from + * the new group to its reserved primary GDT block. + */ + blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); + for (i = 0; i < reserved_gdb; i++) { + int err2; + data = (__u32 *)primary[i]->b_data; + /* printk("reserving backup %lu[%u] = %lu\n", + primary[i]->b_blocknr, gdbackups, + blk + primary[i]->b_blocknr); */ + data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); + err2 = ext3_journal_dirty_metadata(handle, primary[i]); + if (!err) + err = err2; + } + inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; + ext3_mark_iloc_dirty(handle, inode, &iloc); + +exit_bh: + while (--res >= 0) + brelse(primary[res]); + brelse(dind); + +exit_free: + kfree(primary); + + return err; +} + +/* + * Update the backup copies of the ext3 metadata. These don't need to be part + * of the main resize transaction, because e2fsck will re-write them if there + * is a problem (basically only OOM will cause a problem). However, we + * _should_ update the backups if possible, in case the primary gets trashed + * for some reason and we need to run e2fsck from a backup superblock. The + * important part is that the new block and inode counts are in the backup + * superblocks, and the location of the new group metadata in the GDT backups. + * + * We do not need lock_super() for this, because these blocks are not + * otherwise touched by the filesystem code when it is mounted. We don't + * need to worry about last changing from sbi->s_groups_count, because the + * worst that can happen is that we do not copy the full number of backups + * at this time. The resize which changed s_groups_count will backup again. + * + * We only pass inode because of the ext3 journal wrappers. + */ +static void update_backups(struct super_block *sb, struct inode *inode, + int blk_off, char *data, int size) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + const unsigned long last = sbi->s_groups_count; + const int bpg = EXT3_BLOCKS_PER_GROUP(sb); + unsigned three = 1; + unsigned five = 5; + unsigned seven = 7; + unsigned group; + int rest = sb->s_blocksize - size; + handle_t *handle; + int err = 0, err2; + + handle = ext3_journal_start(inode, EXT3_MAX_TRANS_DATA); + if (IS_ERR(handle)) { + group = 1; + err = PTR_ERR(handle); + goto exit_err; + } + + while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { + struct buffer_head *bh; + + /* Out of journal space, and can't get more - abort - so sad */ + if (handle->h_buffer_credits == 0 && + ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && + (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) + break; + + bh = sb_getblk(sb, group * bpg + blk_off); + set_buffer_uptodate(bh); + ext3_debug(sb, __FUNCTION__, "update metadata backup %#04lx\n", + bh->b_blocknr); + if ((err = ext3_journal_get_write_access(handle, bh))) + break; + memcpy(bh->b_data, data, size); + if (rest) + memset(bh->b_data + size, 0, rest); + ext3_journal_dirty_metadata(handle, bh); + brelse(bh); + } + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + + /* + * Ugh! Need to have e2fsck write the backup copies. It is too + * late to revert the resize, we shouldn't fail just because of + * the backup copies (they are only needed in case of corruption). + * + * However, if we got here we have a journal problem too, so we + * can't really start a transaction to mark the superblock. + * Chicken out and just set the flag on the hope it will be written + * to disk, and if not - we will simply wait until next fsck. + */ +exit_err: + if (err) { + ext3_warning(sb, __FUNCTION__, + "can't update backup for group %d (err %d), " + "forcing fsck on next reboot\n", group, err); + sbi->s_mount_state &= ~EXT3_VALID_FS; + sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS); + mark_buffer_dirty(sbi->s_sbh); + } +} + +/* Add group descriptor data to an existing or new group descriptor block. + * Ensure we handle all possible error conditions _before_ we start modifying + * the filesystem, because we cannot abort the transaction and not have it + * write the data to disk. + * + * If we are on a GDT block boundary, we need to get the reserved GDT block. + * Otherwise, we may need to add backup GDT blocks for a sparse group. + * + * We only need to hold the superblock lock while we are actually adding + * in the new group's counts to the superblock. Prior to that we have + * not really "added" the group at all. We re-check that we are still + * adding in the last group in case things have changed since verifying. + */ +int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + int reserved_gdb = ext3_bg_has_super(sb, input->group) ? + le16_to_cpu(es->s_reserved_gdt_blocks) : 0; + struct buffer_head *primary = NULL; + struct ext3_group_desc *gdp; + struct inode *inode = NULL; + struct inode bogus; + handle_t *handle; + int gdb_off, gdb_num; + int err, err2; + + gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); + gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb); + + if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { + ext3_warning(sb, __FUNCTION__, + "Can't resize non-sparse filesystem further\n"); + return -EPERM; + } + + if (reserved_gdb || gdb_off == 0) { + if (!EXT3_HAS_COMPAT_FEATURE(sb, + EXT3_FEATURE_COMPAT_RESIZE_INODE)){ + ext3_warning(sb, __FUNCTION__, + "No reserved GDT blocks, can't resize\n"); + return -EPERM; + } + inode = iget(sb, EXT3_RESIZE_INO); + if (!inode || is_bad_inode(inode)) { + ext3_warning(sb, __FUNCTION__, + "Error opening resize inode\n"); + iput(inode); + return -ENOENT; + } + } else { + /* Used only for ext3 journal wrapper functions to get sb */ + inode = &bogus; + bogus.i_sb = sb; + } + + if ((err = verify_group_input(sb, input))) + goto exit_put; + + if ((err = setup_new_group_blocks(sb, inode, input))) + goto exit_put; + + /* + * We will always be modifying at least the superblock and a GDT + * block. If we are adding a group past the last current GDT block, + * we will also modify the inode and the dindirect block. If we + * are adding a group with superblock/GDT backups we will also + * modify each of the reserved GDT dindirect blocks. + */ + handle = ext3_journal_start(inode, ext3_bg_has_super(sb, input->group) ? + 3 + reserved_gdb : 4); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + goto exit_put; + } + + lock_super(sb); + if (input->group != EXT3_SB(sb)->s_groups_count) { + ext3_warning(sb, __FUNCTION__, + "multiple resizers run on filesystem!\n"); + goto exit_journal; + } + + if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh))) + goto exit_journal; + + /* + * We will only either add reserved group blocks to a backup group + * or remove reserved blocks for the first group in a new group block. + * Doing both would be mean more complex code, and sane people don't + * use non-sparse filesystems anymore. This is already checked above. + */ + if (gdb_off) { + primary = sbi->s_group_desc[gdb_num]; + if ((err = ext3_journal_get_write_access(handle, primary))) + goto exit_journal; + + if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) && + (err = reserve_backup_gdb(handle, inode, input))) + goto exit_journal; + } else if ((err = add_new_gdb(handle, inode, input, &primary))) + goto exit_journal; + + /* Finally update group descriptor block for new group */ + gdp = (struct ext3_group_desc *)primary->b_data + gdb_off; + + gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); + gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); + gdp->bg_inode_table = cpu_to_le32(input->inode_table); + gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); + gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); + + EXT3_SB(sb)->s_groups_count++; + ext3_journal_dirty_metadata(handle, primary); + + /* Update superblock with new block counts */ + es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + + input->blocks_count); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) + + input->free_blocks_count); + es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) + + input->reserved_blocks); + es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + + EXT3_INODES_PER_GROUP(sb)); + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + + EXT3_INODES_PER_GROUP(sb)); + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + sb->s_dirt = 1; + +exit_journal: + unlock_super(sb); + handle->h_sync = 1; + if ((err2 = ext3_journal_stop(handle)) && !err) + err = err2; + if (!err) { + update_backups(sb, inode, sbi->s_sbh->b_blocknr, (char *)es, + sizeof(struct ext3_super_block)); + update_backups(sb, inode, primary->b_blocknr, primary->b_data, + primary->b_size); + } +exit_put: + if (inode != &bogus) + iput(inode); + return err; +} /* ext3_group_add */ + +/* Extend the filesystem to the new number of blocks specified. This entry + * point is only used to extend the current filesystem to the end of the last + * existing group. It can be accessed via ioctl, or by "remount,resize=" + * for emergencies (because it has no dependencies on reserved blocks). + * + * If we _really_ wanted, we could use default values to call ext3_group_add() + * allow the "remount" trick to work for arbitrary resizing, assuming enough + * GDT blocks are reserved to grow to the desired size. + */ +int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, + unsigned long n_blocks_count) +{ + unsigned long o_blocks_count; + unsigned long o_groups_count; + unsigned long last; + int add; + struct inode *inode; + struct buffer_head * bh; + handle_t *handle; + int err; + + o_blocks_count = le32_to_cpu(es->s_blocks_count); + o_groups_count = EXT3_SB(sb)->s_groups_count; + + if (test_opt(sb, DEBUG)) + printk("EXT3-fs: extending last group from %lu to %lu blocks\n", + o_blocks_count, n_blocks_count); + + if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) + return 0; + + if (n_blocks_count < o_blocks_count) { + ext3_warning(sb, __FUNCTION__, + "can't shrink FS - resize aborted"); + return -EBUSY; + } + + /* Handle the remaining blocks in the last group only. */ + last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb); + + if (last == 0) { + ext3_warning(sb, __FUNCTION__, + "need to use ext2online to resize further\n"); + return -EPERM; + } + + add = EXT3_BLOCKS_PER_GROUP(sb) - last; + + if (o_blocks_count + add > n_blocks_count) + add = n_blocks_count - o_blocks_count; + + if (o_blocks_count + add < n_blocks_count) + ext3_warning(sb, __FUNCTION__, + "will only finish group (%lu blocks, %u new)", + o_blocks_count + add, add); + + /* See if the device is actually as big as what was requested */ + bh = sb_bread(sb, o_blocks_count + add -1); + if (!bh) { + ext3_warning(sb, __FUNCTION__, + "can't read last block, resize aborted"); + return -ENOSPC; + } + brelse(bh); + + /* Get a bogus inode to "free" the new blocks in this group. */ + if (!(inode = new_inode(sb))) { + ext3_warning(sb, __FUNCTION__, + "error getting dummy resize inode"); + return -ENOMEM; + } + inode->i_ino = 0; + + EXT3_I(inode)->i_state = EXT3_STATE_RESIZE; + + /* We will update the superblock, one block bitmap, and + * one group descriptor via ext3_free_blocks(). + */ + handle = ext3_journal_start(inode, 3); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + ext3_warning(sb, __FUNCTION__, "error %d on journal start",err); + goto exit_put; + } + + lock_super(sb); + if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { + ext3_warning(sb, __FUNCTION__, + "multiple resizers run on filesystem!\n"); + err = -EBUSY; + goto exit_put; + } + + if ((err = ext3_journal_get_write_access(handle, + EXT3_SB(sb)->s_sbh))) { + ext3_warning(sb, __FUNCTION__, + "error %d on journal write access", err); + unlock_super(sb); + ext3_journal_stop(handle); + goto exit_put; + } + es->s_blocks_count = cpu_to_le32(o_blocks_count + add); + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + sb->s_dirt = 1; + unlock_super(sb); + ext3_debug("freeing blocks %ld through %ld\n", o_blocks_count, + o_blocks_count + add); + ext3_free_blocks(handle, inode, o_blocks_count, add); + ext3_debug("freed blocks %ld through %ld\n", o_blocks_count, + o_blocks_count + add); + if ((err = ext3_journal_stop(handle))) + goto exit_put; + if (test_opt(sb, DEBUG)) + printk("EXT3-fs: extended group to %u blocks\n", + le32_to_cpu(es->s_blocks_count)); + update_backups(sb, inode, EXT3_SB(sb)->s_sbh->b_blocknr, (char *)es, + sizeof(struct ext3_super_block)); +exit_put: + iput(inode); + + return err; +} /* ext3_group_extend */ --- linux-2.6.8-rc1/fs/ext3/super.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ext3/super.c 2004-07-13 17:09:35.000000000 -0700 @@ -493,10 +493,9 @@ static void destroy_inodecache(void) printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n"); } -#ifdef CONFIG_EXT3_FS_POSIX_ACL - static void ext3_clear_inode(struct inode *inode) { +#ifdef CONFIG_EXT3_FS_POSIX_ACL if (EXT3_I(inode)->i_acl && EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { posix_acl_release(EXT3_I(inode)->i_acl); @@ -507,11 +506,10 @@ static void ext3_clear_inode(struct inod posix_acl_release(EXT3_I(inode)->i_default_acl); EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; } -} - -#else -# define ext3_clear_inode NULL #endif + if (!is_bad_inode(inode)) + ext3_discard_reservation(inode); +} #ifdef CONFIG_QUOTA @@ -561,7 +559,6 @@ static struct super_operations ext3_sops .read_inode = ext3_read_inode, .write_inode = ext3_write_inode, .dirty_inode = ext3_dirty_inode, - .put_inode = ext3_put_inode, .delete_inode = ext3_delete_inode, .put_super = ext3_put_super, .write_super = ext3_write_super, @@ -582,12 +579,13 @@ enum { Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_reservation, Opt_noreservation, Opt_noload, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, - Opt_ignore, Opt_err, + Opt_ignore, Opt_barrier, Opt_err, Opt_resize, }; static match_table_t tokens = { @@ -614,6 +612,8 @@ static match_table_t tokens = { {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_reservation, "reservation"}, + {Opt_noreservation, "noreservation"}, {Opt_noload, "noload"}, {Opt_commit, "commit=%u"}, {Opt_journal_update, "journal=update"}, @@ -632,7 +632,9 @@ static match_table_t tokens = { {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_ignore, "usrquota"}, - {Opt_err, NULL} + {Opt_barrier, "barrier=%u"}, + {Opt_err, NULL}, + {Opt_resize, "resize"}, }; static unsigned long get_sb_block(void **data) @@ -656,7 +658,7 @@ static unsigned long get_sb_block(void * } static int parse_options (char * options, struct super_block *sb, - unsigned long * inum, int is_remount) + unsigned long * inum, unsigned long *n_blocks_count, int is_remount) { struct ext3_sb_info *sbi = EXT3_SB(sb); char * p; @@ -767,6 +769,12 @@ static int parse_options (char * options printk("EXT3 (no)acl options not supported\n"); break; #endif + case Opt_reservation: + set_opt(sbi->s_mount_opt, RESERVATION); + break; + case Opt_noreservation: + clear_opt(sbi->s_mount_opt, RESERVATION); + break; case Opt_journal_update: /* @@@ FIXME */ /* Eventually we will want to be able to create @@ -897,8 +905,25 @@ clear_qf_name: case Opt_abort: set_opt(sbi->s_mount_opt, ABORT); break; + case Opt_barrier: + if (match_int(&args[0], &option)) + return 0; + if (option) + set_opt(sbi->s_mount_opt, BARRIER); + else + clear_opt(sbi->s_mount_opt, BARRIER); + break; case Opt_ignore: break; + case Opt_resize: + if (!n_blocks_count) { + printk("EXT3-fs: resize option only available " + "for remount\n"); + return 0; + } + match_int(&args[0], &option); + *n_blocks_count = option; + break; default: printk (KERN_ERR "EXT3-fs: Unrecognized mount option \"%s\" " @@ -1288,7 +1313,9 @@ static int ext3_fill_super (struct super sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); - if (!parse_options ((char *) data, sb, &journal_inum, 0)) + set_opt(sbi->s_mount_opt, RESERVATION); + + if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0)) goto failed_mount; sb->s_flags |= MS_ONE_SECOND; @@ -1462,6 +1489,14 @@ static int ext3_fill_super (struct super sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); + /* per fileystem reservation list head & lock */ + spin_lock_init(&sbi->s_rsv_window_lock); + INIT_LIST_HEAD(&sbi->s_rsv_window_head.rsv_list); + sbi->s_rsv_window_head.rsv_start = 0; + sbi->s_rsv_window_head.rsv_end = 0; + sbi->s_rsv_window_head.rsv_alloc_hit = 0; + atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0); + /* * set up enough so that it can read an inode */ @@ -1599,16 +1634,23 @@ out_fail: * initial mount, once the journal has been initialised but before we've * done any recovery; and again on any subsequent remount. */ -static void ext3_init_journal_params(struct ext3_sb_info *sbi, - journal_t *journal) +static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) { + struct ext3_sb_info *sbi = EXT3_SB(sb); + if (sbi->s_commit_interval) journal->j_commit_interval = sbi->s_commit_interval; /* We could also set up an ext3-specific default for the commit * interval here, but for now we'll just fall back to the jbd * default. */ -} + spin_lock(&journal->j_state_lock); + if (test_opt(sb, BARRIER)) + journal->j_flags |= JFS_BARRIER; + else + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); +} static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum) { @@ -1646,7 +1688,7 @@ static journal_t *ext3_get_journal(struc return NULL; } journal->j_private = sb; - ext3_init_journal_params(EXT3_SB(sb), journal); + ext3_init_journal_params(sb, journal); return journal; } @@ -1731,7 +1773,7 @@ static journal_t *ext3_get_dev_journal(s goto out_journal; } EXT3_SB(sb)->journal_bdev = bdev; - ext3_init_journal_params(EXT3_SB(sb), journal); + ext3_init_journal_params(sb, journal); return journal; out_journal: journal_destroy(journal); @@ -2013,11 +2055,12 @@ int ext3_remount (struct super_block * s struct ext3_super_block * es; struct ext3_sb_info *sbi = EXT3_SB(sb); unsigned long tmp; + unsigned long n_blocks_count = 0; /* * Allow the "check" option to be passed as a remount option. */ - if (!parse_options(data, sb, &tmp, 1)) + if (!parse_options(data, sb, &tmp, &n_blocks_count, 1)) return -EINVAL; if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) @@ -2028,9 +2071,10 @@ int ext3_remount (struct super_block * s es = sbi->s_es; - ext3_init_journal_params(sbi, sbi->s_journal); + ext3_init_journal_params(sb, sbi->s_journal); - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || + n_blocks_count > le32_to_cpu(es->s_blocks_count)) { if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) return -EROFS; @@ -2069,6 +2113,8 @@ int ext3_remount (struct super_block * s */ ext3_clear_journal_err(sb, es); sbi->s_mount_state = le16_to_cpu(es->s_state); + if ((ret = ext3_group_extend(sb, es, n_blocks_count))) + return ret; if (!ext3_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } --- linux-2.6.8-rc1/fs/ext3/xattr.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ext3/xattr.c 2004-07-13 17:09:29.000000000 -0700 @@ -786,8 +786,7 @@ ext3_xattr_set_handle2(handle_t *handle, EXT3_SB(sb)->s_es->s_first_data_block) + EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb); - int block = ext3_new_block(handle, inode, goal, - NULL, NULL, &error); + int block = ext3_new_block(handle, inode, goal, &error); if (error) goto cleanup; ea_idebug(inode, "creating block %d", block); --- linux-2.6.8-rc1/fs/fs-writeback.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/fs-writeback.c 2004-07-13 17:35:42.000000000 -0700 @@ -213,8 +213,9 @@ __sync_single_inode(struct inode *inode, } else if (inode->i_state & I_DIRTY) { /* * Someone redirtied the inode while were writing back - * the pages: nothing to do. + * the pages. */ + list_move(&inode->i_list, &sb->s_dirty); } else if (atomic_read(&inode->i_count)) { /* * The inode is clean, inuse @@ -303,14 +304,20 @@ sync_sb_inodes(struct super_block *sb, s long pages_skipped; if (bdi->memory_backed) { + list_move(&inode->i_list, &sb->s_dirty); if (sb == blockdev_superblock) { /* * Dirty memory-backed blockdev: the ramdisk - * driver does this. + * driver does this. Skip just this inode */ - list_move(&inode->i_list, &sb->s_dirty); continue; } + /* + * Dirty memory-backed inode against a filesystem other + * than the kernel-internal bdev filesystem. Skip the + * entire superblock. + */ + break; } if (wbc->nonblocking && bdi_write_congested(bdi)) { @@ -391,6 +398,7 @@ writeback_inodes(struct writeback_contro { struct super_block *sb; + might_sleep(); spin_lock(&inode_lock); spin_lock(&sb_lock); restart: --- linux-2.6.8-rc1/fs/hfsplus/inode.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/hfsplus/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -342,7 +342,7 @@ struct inode *hfsplus_new_inode(struct s HFSPLUS_I(inode).cached_start = 0; HFSPLUS_I(inode).cached_blocks = 0; HFSPLUS_I(inode).phys_size = 0; - HFSPLUS_I(inode).rsrc_inode = 0; + HFSPLUS_I(inode).rsrc_inode = NULL; if (S_ISDIR(inode->i_mode)) { inode->i_size = 2; HFSPLUS_SB(sb).folder_count++; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hostfs/hostfs.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,79 @@ +#ifndef __UM_FS_HOSTFS +#define __UM_FS_HOSTFS + +#include "os.h" + +/* These are exactly the same definitions as in fs.h, but the names are + * changed so that this file can be included in both kernel and user files. + */ + +#define HOSTFS_ATTR_MODE 1 +#define HOSTFS_ATTR_UID 2 +#define HOSTFS_ATTR_GID 4 +#define HOSTFS_ATTR_SIZE 8 +#define HOSTFS_ATTR_ATIME 16 +#define HOSTFS_ATTR_MTIME 32 +#define HOSTFS_ATTR_CTIME 64 +#define HOSTFS_ATTR_ATIME_SET 128 +#define HOSTFS_ATTR_MTIME_SET 256 +#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ +#define HOSTFS_ATTR_ATTR_FLAG 1024 + +struct hostfs_iattr { + unsigned int ia_valid; + mode_t ia_mode; + uid_t ia_uid; + gid_t ia_gid; + loff_t ia_size; + struct timespec ia_atime; + struct timespec ia_mtime; + struct timespec ia_ctime; + unsigned int ia_attr_flags; +}; + +extern int stat_file(const char *path, unsigned long long *inode_out, + int *mode_out, int *nlink_out, int *uid_out, int *gid_out, + unsigned long long *size_out, struct timespec *atime_out, + struct timespec *mtime_out, struct timespec *ctime_out, + int *blksize_out, unsigned long long *blocks_out); +extern int access_file(char *path, int r, int w, int x); +extern int open_file(char *path, int r, int w, int append); +extern int file_type(const char *path, int *rdev); +extern void *open_dir(char *path, int *err_out); +extern char *read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out); +extern void close_file(void *stream); +extern void close_dir(void *stream); +extern int read_file(int fd, unsigned long long *offset, char *buf, int len); +extern int write_file(int fd, unsigned long long *offset, const char *buf, + int len); +extern int lseek_file(int fd, long long offset, int whence); +extern int file_create(char *name, int ur, int uw, int ux, int gr, + int gw, int gx, int or, int ow, int ox); +extern int set_attr(const char *file, struct hostfs_iattr *attrs); +extern int make_symlink(const char *from, const char *to); +extern int unlink_file(const char *file); +extern int do_mkdir(const char *file, int mode); +extern int do_rmdir(const char *file); +extern int do_mknod(const char *file, int mode, int dev); +extern int link_file(const char *from, const char *to); +extern int do_readlink(char *file, char *buf, int size); +extern int rename_file(char *from, char *to); +extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, + long long *bfree_out, long long *bavail_out, + long long *files_out, long long *ffree_out, + void *fsid_out, int fsid_size, long *namelen_out, + long *spare_out); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hostfs/hostfs_kern.c 2004-07-13 17:09:47.000000000 -0700 @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + * + * Ported the filesystem routines to 2.5. + * 2003-02-10 Petr Baudis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hostfs.h" +#include "kern_util.h" +#include "kern.h" +#include "user_util.h" +#include "2_5compat.h" +#include "init.h" + +struct hostfs_inode_info { + char *host_filename; + int fd; + int mode; + struct inode vfs_inode; +}; + +static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) +{ + return(list_entry(inode, struct hostfs_inode_info, vfs_inode)); +} + +#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode) + +int hostfs_d_delete(struct dentry *dentry) +{ + return(1); +} + +struct dentry_operations hostfs_dentry_ops = { + .d_delete = hostfs_d_delete, +}; + +/* Changed in hostfs_args before the kernel starts running */ +static char *root_ino = "/"; +static int append = 0; + +#define HOSTFS_SUPER_MAGIC 0x00c0ffee + +static struct inode_operations hostfs_iops; +static struct inode_operations hostfs_dir_iops; +static struct address_space_operations hostfs_link_aops; + +#ifndef MODULE +static int __init hostfs_args(char *options, int *add) +{ + char *ptr; + + ptr = strchr(options, ','); + if(ptr != NULL) + *ptr++ = '\0'; + if(*options != '\0') + root_ino = options; + + options = ptr; + while(options){ + ptr = strchr(options, ','); + if(ptr != NULL) + *ptr++ = '\0'; + if(*options != '\0'){ + if(!strcmp(options, "append")) + append = 1; + else printf("hostfs_args - unsupported option - %s\n", + options); + } + options = ptr; + } + return(0); +} + +__uml_setup("hostfs=", hostfs_args, +"hostfs=,,...\n" +" This is used to set hostfs parameters. The root directory argument\n" +" is used to confine all hostfs mounts to within the specified directory\n" +" tree on the host. If this isn't specified, then a user inside UML can\n" +" mount anything on the host that's accessible to the user that's running\n" +" it.\n" +" The only flag currently supported is 'append', which specifies that all\n" +" files opened by hostfs will be opened in append mode.\n\n" +); +#endif + +static char *dentry_name(struct dentry *dentry, int extra) +{ + struct dentry *parent; + char *root, *name; + int len; + + len = 0; + parent = dentry; + while(parent->d_parent != parent){ + len += parent->d_name.len + 1; + parent = parent->d_parent; + } + + root = HOSTFS_I(parent->d_inode)->host_filename; + len += strlen(root); + name = kmalloc(len + extra + 1, GFP_KERNEL); + if(name == NULL) return(NULL); + + name[len] = '\0'; + parent = dentry; + while(parent->d_parent != parent){ + len -= parent->d_name.len + 1; + name[len] = '/'; + strncpy(&name[len + 1], parent->d_name.name, + parent->d_name.len); + parent = parent->d_parent; + } + strncpy(name, root, strlen(root)); + return(name); +} + +static char *inode_name(struct inode *ino, int extra) +{ + struct dentry *dentry; + + dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); + return(dentry_name(dentry, extra)); +} + +static int read_name(struct inode *ino, char *name) +{ + /* The non-int inode fields are copied into ints by stat_file and + * then copied into the inode because passing the actual pointers + * in and having them treated as int * breaks on big-endian machines + */ + int err; + int i_mode, i_nlink, i_blksize; + unsigned long long i_size; + unsigned long long i_ino; + unsigned long long i_blocks; + + err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, + &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, + &ino->i_ctime, &i_blksize, &i_blocks); + if(err) + return(err); + + ino->i_ino = i_ino; + ino->i_mode = i_mode; + ino->i_nlink = i_nlink; + ino->i_size = i_size; + ino->i_blksize = i_blksize; + ino->i_blocks = i_blocks; + if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid())) + ino->i_uid = 0; + return(0); +} + +static char *follow_link(char *link) +{ + int len, n; + char *name, *resolved, *end; + + len = 64; + while(1){ + n = -ENOMEM; + name = kmalloc(len, GFP_KERNEL); + if(name == NULL) + goto out; + + n = do_readlink(link, name, len); + if(n < len) + break; + len *= 2; + kfree(name); + } + if(n < 0) + goto out_free; + + if(*name == '/') + return(name); + + end = strrchr(link, '/'); + if(end == NULL) + return(name); + + *(end + 1) = '\0'; + len = strlen(link) + strlen(name) + 1; + + resolved = kmalloc(len, GFP_KERNEL); + if(resolved == NULL){ + n = -ENOMEM; + goto out_free; + } + + sprintf(resolved, "%s%s", link, name); + kfree(name); + kfree(link); + return(resolved); + + out_free: + kfree(name); + out: + return(ERR_PTR(n)); +} + +static int read_inode(struct inode *ino) +{ + char *name; + int err = 0; + + /* Unfortunately, we are called from iget() when we don't have a dentry + * allocated yet. + */ + if(list_empty(&ino->i_dentry)) + goto out; + + err = -ENOMEM; + name = inode_name(ino, 0); + if(name == NULL) + goto out; + + if(file_type(name, NULL) == OS_TYPE_SYMLINK){ + name = follow_link(name); + if(IS_ERR(name)){ + err = PTR_ERR(name); + goto out; + } + } + + err = read_name(ino, name); + kfree(name); + out: + return(err); +} + +int hostfs_statfs(struct super_block *sb, struct kstatfs *sf) +{ + /* do_statfs uses struct statfs64 internally, but the linux kernel + * struct statfs still has 32-bit versions for most of these fields, + * so we convert them here + */ + int err; + long long f_blocks; + long long f_bfree; + long long f_bavail; + long long f_files; + long long f_ffree; + + err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename, + &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, + &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), + &sf->f_namelen, sf->f_spare); + if(err) return(err); + sf->f_blocks = f_blocks; + sf->f_bfree = f_bfree; + sf->f_bavail = f_bavail; + sf->f_files = f_files; + sf->f_ffree = f_ffree; + sf->f_type = HOSTFS_SUPER_MAGIC; + return(0); +} + +static struct inode *hostfs_alloc_inode(struct super_block *sb) +{ + struct hostfs_inode_info *hi; + + hi = kmalloc(sizeof(*hi), GFP_KERNEL); + if(hi == NULL) + return(NULL); + + *hi = ((struct hostfs_inode_info) { .host_filename = NULL, + .fd = -1, + .mode = 0 }); + inode_init_once(&hi->vfs_inode); + return(&hi->vfs_inode); +} + +static void hostfs_delete_inode(struct inode *inode) +{ + if(HOSTFS_I(inode)->fd != -1) { + close_file(&HOSTFS_I(inode)->fd); + printk("Closing host fd in .delete_inode\n"); + HOSTFS_I(inode)->fd = -1; + } + clear_inode(inode); +} + +static void hostfs_destroy_inode(struct inode *inode) +{ + if(HOSTFS_I(inode)->host_filename) + kfree(HOSTFS_I(inode)->host_filename); + + if(HOSTFS_I(inode)->fd != -1) { + close_file(&HOSTFS_I(inode)->fd); + printk("Closing host fd in .destroy_inode\n"); + } + + kfree(HOSTFS_I(inode)); +} + +static void hostfs_read_inode(struct inode *inode) +{ + read_inode(inode); +} + +static struct super_operations hostfs_sbops = { + .alloc_inode = hostfs_alloc_inode, + .drop_inode = generic_delete_inode, + .delete_inode = hostfs_delete_inode, + .destroy_inode = hostfs_destroy_inode, + .read_inode = hostfs_read_inode, + .statfs = hostfs_statfs, +}; + +int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + void *dir; + char *name; + unsigned long long next, ino; + int error, len; + + name = dentry_name(file->f_dentry, 0); + if(name == NULL) return(-ENOMEM); + dir = open_dir(name, &error); + kfree(name); + if(dir == NULL) return(-error); + next = file->f_pos; + while((name = read_dir(dir, &next, &ino, &len)) != NULL){ + error = (*filldir)(ent, name, len, file->f_pos, + ino, DT_UNKNOWN); + if(error) break; + file->f_pos = next; + } + close_dir(dir); + return(0); +} + +int hostfs_file_open(struct inode *ino, struct file *file) +{ + char *name; + int mode = 0, r = 0, w = 0, fd; + + mode = file->f_mode & (FMODE_READ | FMODE_WRITE); + if((mode & HOSTFS_I(ino)->mode) == mode) + return(0); + + /* The file may already have been opened, but with the wrong access, + * so this resets things and reopens the file with the new access. + */ + if(HOSTFS_I(ino)->fd != -1){ + close_file(&HOSTFS_I(ino)->fd); + HOSTFS_I(ino)->fd = -1; + } + + HOSTFS_I(ino)->mode |= mode; + if(HOSTFS_I(ino)->mode & FMODE_READ) + r = 1; + if(HOSTFS_I(ino)->mode & FMODE_WRITE) + w = 1; + if(w) + r = 1; + + name = dentry_name(file->f_dentry, 0); + if(name == NULL) + return(-ENOMEM); + + fd = open_file(name, r, w, append); + kfree(name); + if(fd < 0) return(fd); + FILE_HOSTFS_I(file)->fd = fd; + + return(0); +} + +int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return(0); +} + +static struct file_operations hostfs_file_fops = { + .llseek = generic_file_llseek, + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .open = hostfs_file_open, + .release = NULL, + .fsync = hostfs_fsync, +}; + +static struct file_operations hostfs_dir_fops = { + .readdir = hostfs_readdir, + .read = generic_read_dir, +}; + +int hostfs_writepage(struct page *page, struct writeback_control *wbc) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + char *buffer; + unsigned long long base; + int count = PAGE_CACHE_SIZE; + int end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int err; + + if (page->index >= end_index) + count = inode->i_size & (PAGE_CACHE_SIZE-1); + + buffer = kmap(page); + base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; + + err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); + if(err != count){ + ClearPageUptodate(page); + goto out; + } + + if (base > inode->i_size) + inode->i_size = base; + + if (PageError(page)) + ClearPageError(page); + err = 0; + + out: + kunmap(page); + + unlock_page(page); + return err; +} + +int hostfs_readpage(struct file *file, struct page *page) +{ + char *buffer; + long long start; + int err = 0; + + start = (long long) page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, + PAGE_CACHE_SIZE); + if(err < 0) goto out; + + memset(&buffer[err], 0, PAGE_CACHE_SIZE - err); + + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + err = 0; + out: + kunmap(page); + unlock_page(page); + return(err); +} + +int hostfs_prepare_write(struct file *file, struct page *page, + unsigned int from, unsigned int to) +{ + char *buffer; + long long start, tmp; + int err; + + start = (long long) page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + if(from != 0){ + tmp = start; + err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer, + from); + if(err < 0) goto out; + } + if(to != PAGE_CACHE_SIZE){ + start += to; + err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to, + PAGE_CACHE_SIZE - to); + if(err < 0) goto out; + } + err = 0; + out: + kunmap(page); + return(err); +} + +int hostfs_commit_write(struct file *file, struct page *page, unsigned from, + unsigned to) +{ + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + char *buffer; + long long start; + int err = 0; + + start = (long long) (page->index << PAGE_CACHE_SHIFT) + from; + buffer = kmap(page); + err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, + to - from); + if(err > 0) err = 0; + if(!err && (start > inode->i_size)) + inode->i_size = start; + + kunmap(page); + return(err); +} + +static struct address_space_operations hostfs_aops = { + .writepage = hostfs_writepage, + .readpage = hostfs_readpage, +/* .set_page_dirty = __set_page_dirty_nobuffers, */ + .prepare_write = hostfs_prepare_write, + .commit_write = hostfs_commit_write +}; + +static int init_inode(struct inode *inode, struct dentry *dentry) +{ + char *name; + int type, err = -ENOMEM, rdev; + + if(dentry){ + name = dentry_name(dentry, 0); + if(name == NULL) + goto out; + type = file_type(name, &rdev); + kfree(name); + } + else type = OS_TYPE_DIR; + + err = 0; + if(type == OS_TYPE_SYMLINK) + inode->i_op = &page_symlink_inode_operations; + else if(type == OS_TYPE_DIR) + inode->i_op = &hostfs_dir_iops; + else inode->i_op = &hostfs_iops; + + if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; + else inode->i_fop = &hostfs_file_fops; + + if(type == OS_TYPE_SYMLINK) + inode->i_mapping->a_ops = &hostfs_link_aops; + else inode->i_mapping->a_ops = &hostfs_aops; + + switch (type) { + case OS_TYPE_CHARDEV: + init_special_inode(inode, S_IFCHR, rdev); + break; + case OS_TYPE_BLOCKDEV: + init_special_inode(inode, S_IFBLK, rdev); + break; + case OS_TYPE_FIFO: + init_special_inode(inode, S_IFIFO, 0); + break; + case OS_TYPE_SOCK: + init_special_inode(inode, S_IFSOCK, 0); + break; + } + out: + return(err); +} + +int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + struct inode *inode; + char *name; + int error, fd; + + error = -ENOMEM; + inode = iget(dir->i_sb, 0); + if(inode == NULL) goto out; + + error = init_inode(inode, dentry); + if(error) + goto out_put; + + error = -ENOMEM; + name = dentry_name(dentry, 0); + if(name == NULL) + goto out_put; + + fd = file_create(name, + mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, + mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, + mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); + if(fd < 0) + error = fd; + else error = read_name(inode, name); + + kfree(name); + if(error) + goto out_put; + + HOSTFS_I(inode)->fd = fd; + HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE; + d_instantiate(dentry, inode); + return(0); + + out_put: + iput(inode); + out: + return(error); +} + +struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, + struct nameidata *nd) +{ + struct inode *inode; + char *name; + int err; + + err = -ENOMEM; + inode = iget(ino->i_sb, 0); + if(inode == NULL) + goto out; + + err = init_inode(inode, dentry); + if(err) + goto out_put; + + err = -ENOMEM; + name = dentry_name(dentry, 0); + if(name == NULL) + goto out_put; + + err = read_name(inode, name); + kfree(name); + if(err == -ENOENT){ + iput(inode); + inode = NULL; + } + else if(err) + goto out_put; + + d_add(dentry, inode); + dentry->d_op = &hostfs_dentry_ops; + return(NULL); + + out_put: + iput(inode); + out: + return(ERR_PTR(err)); +} + +static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) +{ + char *file; + int len; + + file = inode_name(ino, dentry->d_name.len + 1); + if(file == NULL) return(NULL); + strcat(file, "/"); + len = strlen(file); + strncat(file, dentry->d_name.name, dentry->d_name.len); + file[len + dentry->d_name.len] = '\0'; + return(file); +} + +int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) +{ + char *from_name, *to_name; + int err; + + if((from_name = inode_dentry_name(ino, from)) == NULL) + return(-ENOMEM); + to_name = dentry_name(to, 0); + if(to_name == NULL){ + kfree(from_name); + return(-ENOMEM); + } + err = link_file(to_name, from_name); + kfree(from_name); + kfree(to_name); + return(err); +} + +int hostfs_unlink(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + if(append) + return(-EPERM); + + err = unlink_file(file); + kfree(file); + return(err); +} + +int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = make_symlink(file, to); + kfree(file); + return(err); +} + +int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = do_mkdir(file, mode); + kfree(file); + return(err); +} + +int hostfs_rmdir(struct inode *ino, struct dentry *dentry) +{ + char *file; + int err; + + if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); + err = do_rmdir(file); + kfree(file); + return(err); +} + +int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode *inode; + char *name; + int err = -ENOMEM; + + inode = iget(dir->i_sb, 0); + if(inode == NULL) + goto out; + + err = init_inode(inode, dentry); + if(err) + goto out_put; + + err = -ENOMEM; + name = dentry_name(dentry, 0); + if(name == NULL) + goto out_put; + + init_special_inode(inode, mode, dev); + err = do_mknod(name, mode, dev); + if(err) + goto out_free; + + err = read_name(inode, name); + kfree(name); + if(err) + goto out_put; + + d_instantiate(dentry, inode); + return(0); + + out_free: + kfree(name); + out_put: + iput(inode); + out: + return(err); +} + +int hostfs_rename(struct inode *from_ino, struct dentry *from, + struct inode *to_ino, struct dentry *to) +{ + char *from_name, *to_name; + int err; + + if((from_name = inode_dentry_name(from_ino, from)) == NULL) + return(-ENOMEM); + if((to_name = inode_dentry_name(to_ino, to)) == NULL){ + kfree(from_name); + return(-ENOMEM); + } + err = rename_file(from_name, to_name); + kfree(from_name); + kfree(to_name); + return(err); +} + +void hostfs_truncate(struct inode *ino) +{ + not_implemented(); +} + +int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) +{ + char *name; + int r = 0, w = 0, x = 0, err; + + if(desired & MAY_READ) r = 1; + if(desired & MAY_WRITE) w = 1; + if(desired & MAY_EXEC) x = 1; + name = inode_name(ino, 0); + if(name == NULL) return(-ENOMEM); + err = access_file(name, r, w, x); + kfree(name); + if(!err) err = vfs_permission(ino, desired); + return(err); +} + +int hostfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct hostfs_iattr attrs; + char *name; + int err; + + if(append) + attr->ia_valid &= ~ATTR_SIZE; + + attrs.ia_valid = 0; + if(attr->ia_valid & ATTR_MODE){ + attrs.ia_valid |= HOSTFS_ATTR_MODE; + attrs.ia_mode = attr->ia_mode; + } + if(attr->ia_valid & ATTR_UID){ + if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && + (attr->ia_uid == 0)) + attr->ia_uid = getuid(); + attrs.ia_valid |= HOSTFS_ATTR_UID; + attrs.ia_uid = attr->ia_uid; + } + if(attr->ia_valid & ATTR_GID){ + if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && + (attr->ia_gid == 0)) + attr->ia_gid = getuid(); + attrs.ia_valid |= HOSTFS_ATTR_GID; + attrs.ia_gid = attr->ia_gid; + } + if(attr->ia_valid & ATTR_SIZE){ + attrs.ia_valid |= HOSTFS_ATTR_SIZE; + attrs.ia_size = attr->ia_size; + } + if(attr->ia_valid & ATTR_ATIME){ + attrs.ia_valid |= HOSTFS_ATTR_ATIME; + attrs.ia_atime = attr->ia_atime; + } + if(attr->ia_valid & ATTR_MTIME){ + attrs.ia_valid |= HOSTFS_ATTR_MTIME; + attrs.ia_mtime = attr->ia_mtime; + } + if(attr->ia_valid & ATTR_CTIME){ + attrs.ia_valid |= HOSTFS_ATTR_CTIME; + attrs.ia_ctime = attr->ia_ctime; + } + if(attr->ia_valid & ATTR_ATIME_SET){ + attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; + } + if(attr->ia_valid & ATTR_MTIME_SET){ + attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; + } + name = dentry_name(dentry, 0); + if(name == NULL) return(-ENOMEM); + err = set_attr(name, &attrs); + kfree(name); + if(err) + return(err); + + return(inode_setattr(dentry->d_inode, attr)); +} + +int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + generic_fillattr(dentry->d_inode, stat); + return(0); +} + +static struct inode_operations hostfs_iops = { + .create = hostfs_create, + .link = hostfs_link, + .unlink = hostfs_unlink, + .symlink = hostfs_symlink, + .mkdir = hostfs_mkdir, + .rmdir = hostfs_rmdir, + .mknod = hostfs_mknod, + .rename = hostfs_rename, + .truncate = hostfs_truncate, + .permission = hostfs_permission, + .setattr = hostfs_setattr, + .getattr = hostfs_getattr, +}; + +static struct inode_operations hostfs_dir_iops = { + .create = hostfs_create, + .lookup = hostfs_lookup, + .link = hostfs_link, + .unlink = hostfs_unlink, + .symlink = hostfs_symlink, + .mkdir = hostfs_mkdir, + .rmdir = hostfs_rmdir, + .mknod = hostfs_mknod, + .rename = hostfs_rename, + .truncate = hostfs_truncate, + .permission = hostfs_permission, + .setattr = hostfs_setattr, + .getattr = hostfs_getattr, +}; + +int hostfs_link_readpage(struct file *file, struct page *page) +{ + char *buffer, *name; + long long start; + int err; + + start = page->index << PAGE_CACHE_SHIFT; + buffer = kmap(page); + name = inode_name(page->mapping->host, 0); + if(name == NULL) return(-ENOMEM); + err = do_readlink(name, buffer, PAGE_CACHE_SIZE); + kfree(name); + if(err == PAGE_CACHE_SIZE) + err = -E2BIG; + else if(err > 0){ + flush_dcache_page(page); + SetPageUptodate(page); + if (PageError(page)) ClearPageError(page); + err = 0; + } + kunmap(page); + unlock_page(page); + return(err); +} + +static struct address_space_operations hostfs_link_aops = { + .readpage = hostfs_link_readpage, +}; + +static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) +{ + struct inode *root_inode; + char *name, *data = d; + int err; + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = HOSTFS_SUPER_MAGIC; + sb->s_op = &hostfs_sbops; + + if((data == NULL) || (*data == '\0')) + data = root_ino; + + err = -ENOMEM; + name = kmalloc(strlen(data) + 1, GFP_KERNEL); + if(name == NULL) + goto out; + + strcpy(name, data); + + root_inode = iget(sb, 0); + if(root_inode == NULL) + goto out_free; + + err = init_inode(root_inode, NULL); + if(err) + goto out_put; + + HOSTFS_I(root_inode)->host_filename = name; + + err = -ENOMEM; + sb->s_root = d_alloc_root(root_inode); + if(sb->s_root == NULL) + goto out_put; + + err = read_inode(root_inode); + if(err) + goto out_put; + + return(0); + + out_put: + iput(root_inode); + out_free: + kfree(name); + out: + return(err); +} + +static struct super_block *hostfs_read_sb(struct file_system_type *type, + int flags, const char *dev_name, + void *data) +{ + return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common)); +} + +static struct file_system_type hostfs_type = { + .owner = THIS_MODULE, + .name = "hostfs", + .get_sb = hostfs_read_sb, + .kill_sb = kill_anon_super, + .fs_flags = 0, +}; + +static int __init init_hostfs(void) +{ + return(register_filesystem(&hostfs_type)); +} + +static void __exit exit_hostfs(void) +{ + unregister_filesystem(&hostfs_type); +} + +module_init(init_hostfs) +module_exit(exit_hostfs) +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hostfs/hostfs_user.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hostfs.h" +#include "kern_util.h" +#include "user.h" + +int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, + int *nlink_out, int *uid_out, int *gid_out, + unsigned long long *size_out, struct timespec *atime_out, + struct timespec *mtime_out, struct timespec *ctime_out, + int *blksize_out, unsigned long long *blocks_out) +{ + struct stat64 buf; + + if(lstat64(path, &buf) < 0) + return(-errno); + + /* See the Makefile for why STAT64_INO_FIELD is passed in + * by the build + */ + if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD; + if(mode_out != NULL) *mode_out = buf.st_mode; + if(nlink_out != NULL) *nlink_out = buf.st_nlink; + if(uid_out != NULL) *uid_out = buf.st_uid; + if(gid_out != NULL) *gid_out = buf.st_gid; + if(size_out != NULL) *size_out = buf.st_size; + if(atime_out != NULL) { + atime_out->tv_sec = buf.st_atime; + atime_out->tv_nsec = 0; + } + if(mtime_out != NULL) { + mtime_out->tv_sec = buf.st_mtime; + mtime_out->tv_nsec = 0; + } + if(ctime_out != NULL) { + ctime_out->tv_sec = buf.st_ctime; + ctime_out->tv_nsec = 0; + } + if(blksize_out != NULL) *blksize_out = buf.st_blksize; + if(blocks_out != NULL) *blocks_out = buf.st_blocks; + return(0); +} + +int file_type(const char *path, int *rdev) +{ + struct stat64 buf; + + if(lstat64(path, &buf) < 0) + return(-errno); + if(rdev != NULL) + *rdev = buf.st_rdev; + + if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); + else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); + else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); + else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); + else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO); + else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK); + else return(OS_TYPE_FILE); +} + +int access_file(char *path, int r, int w, int x) +{ + int mode = 0; + + if(r) mode = R_OK; + if(w) mode |= W_OK; + if(x) mode |= X_OK; + if(access(path, mode) != 0) return(-errno); + else return(0); +} + +int open_file(char *path, int r, int w, int append) +{ + int mode = 0, fd; + + if(r && !w) + mode = O_RDONLY; + else if(!r && w) + mode = O_WRONLY; + else if(r && w) + mode = O_RDWR; + else panic("Impossible mode in open_file"); + + if(append) + mode |= O_APPEND; + fd = open64(path, mode); + if(fd < 0) return(-errno); + else return(fd); +} + +void *open_dir(char *path, int *err_out) +{ + DIR *dir; + + dir = opendir(path); + *err_out = errno; + if(dir == NULL) return(NULL); + return(dir); +} + +char *read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out) +{ + DIR *dir = stream; + struct dirent *ent; + + seekdir(dir, *pos); + ent = readdir(dir); + if(ent == NULL) return(NULL); + *len_out = strlen(ent->d_name); + *ino_out = ent->d_ino; + *pos = telldir(dir); + return(ent->d_name); +} + +int read_file(int fd, unsigned long long *offset, char *buf, int len) +{ + int n; + + n = pread64(fd, buf, len, *offset); + if(n < 0) return(-errno); + *offset += n; + return(n); +} + +int write_file(int fd, unsigned long long *offset, const char *buf, int len) +{ + int n; + + n = pwrite64(fd, buf, len, *offset); + if(n < 0) return(-errno); + *offset += n; + return(n); +} + +int lseek_file(int fd, long long offset, int whence) +{ + int ret; + + ret = lseek64(fd, offset, whence); + if(ret < 0) return(-errno); + return(0); +} + +void close_file(void *stream) +{ + close(*((int *) stream)); +} + +void close_dir(void *stream) +{ + closedir(stream); +} + +int file_create(char *name, int ur, int uw, int ux, int gr, + int gw, int gx, int or, int ow, int ox) +{ + int mode, fd; + + mode = 0; + mode |= ur ? S_IRUSR : 0; + mode |= uw ? S_IWUSR : 0; + mode |= ux ? S_IXUSR : 0; + mode |= gr ? S_IRGRP : 0; + mode |= gw ? S_IWGRP : 0; + mode |= gx ? S_IXGRP : 0; + mode |= or ? S_IROTH : 0; + mode |= ow ? S_IWOTH : 0; + mode |= ox ? S_IXOTH : 0; + fd = open64(name, O_CREAT | O_RDWR, mode); + if(fd < 0) + return(-errno); + return(fd); +} + +int set_attr(const char *file, struct hostfs_iattr *attrs) +{ + struct utimbuf buf; + int err, ma; + + if(attrs->ia_valid & HOSTFS_ATTR_MODE){ + if(chmod(file, attrs->ia_mode) != 0) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_UID){ + if(chown(file, attrs->ia_uid, -1)) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_GID){ + if(chown(file, -1, attrs->ia_gid)) return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_SIZE){ + if(truncate(file, attrs->ia_size)) return(-errno); + } + ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET; + if((attrs->ia_valid & ma) == ma){ + buf.actime = attrs->ia_atime.tv_sec; + buf.modtime = attrs->ia_mtime.tv_sec; + if(utime(file, &buf) != 0) return(-errno); + } + else { + struct timespec ts; + + if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &ts, NULL, NULL, NULL); + if(err != 0) + return(err); + buf.actime = attrs->ia_atime.tv_sec; + buf.modtime = ts.tv_sec; + if(utime(file, &buf) != 0) + return(-errno); + } + if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, + NULL, &ts, NULL, NULL, NULL, NULL); + if(err != 0) + return(err); + buf.actime = ts.tv_sec; + buf.modtime = attrs->ia_mtime.tv_sec; + if(utime(file, &buf) != 0) + return(-errno); + } + } + if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; + if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ + err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, + &attrs->ia_atime, &attrs->ia_mtime, NULL, + NULL, NULL); + if(err != 0) return(err); + } + return(0); +} + +int make_symlink(const char *from, const char *to) +{ + int err; + + err = symlink(to, from); + if(err) return(-errno); + return(0); +} + +int unlink_file(const char *file) +{ + int err; + + err = unlink(file); + if(err) return(-errno); + return(0); +} + +int do_mkdir(const char *file, int mode) +{ + int err; + + err = mkdir(file, mode); + if(err) return(-errno); + return(0); +} + +int do_rmdir(const char *file) +{ + int err; + + err = rmdir(file); + if(err) return(-errno); + return(0); +} + +int do_mknod(const char *file, int mode, int dev) +{ + int err; + + err = mknod(file, mode, dev); + if(err) return(-errno); + return(0); +} + +int link_file(const char *to, const char *from) +{ + int err; + + err = link(to, from); + if(err) return(-errno); + return(0); +} + +int do_readlink(char *file, char *buf, int size) +{ + int n; + + n = readlink(file, buf, size); + if(n < 0) + return(-errno); + if(n < size) + buf[n] = '\0'; + return(n); +} + +int rename_file(char *from, char *to) +{ + int err; + + err = rename(from, to); + if(err < 0) return(-errno); + return(0); +} + +int do_statfs(char *root, long *bsize_out, long long *blocks_out, + long long *bfree_out, long long *bavail_out, + long long *files_out, long long *ffree_out, + void *fsid_out, int fsid_size, long *namelen_out, + long *spare_out) +{ + struct statfs64 buf; + int err; + + err = statfs64(root, &buf); + if(err < 0) return(-errno); + *bsize_out = buf.f_bsize; + *blocks_out = buf.f_blocks; + *bfree_out = buf.f_bfree; + *bavail_out = buf.f_bavail; + *files_out = buf.f_files; + *ffree_out = buf.f_ffree; + memcpy(fsid_out, &buf.f_fsid, + sizeof(buf.f_fsid) > fsid_size ? fsid_size : + sizeof(buf.f_fsid)); + *namelen_out = buf.f_namelen; + spare_out[0] = buf.f_spare[0]; + spare_out[1] = buf.f_spare[1]; + spare_out[2] = buf.f_spare[2]; + spare_out[3] = buf.f_spare[3]; + spare_out[4] = buf.f_spare[4]; + spare_out[5] = buf.f_spare[5]; + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hostfs/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,26 @@ +# +# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino +# to __st_ino. It stayed in the same place, so as long as the correct name +# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa. + +STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \ + echo __)st_ino + +hostfs-objs := hostfs_kern.o hostfs_user.o + +obj-y = +obj-$(CONFIG_HOSTFS) += hostfs.o + +SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) + +USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< --- linux-2.6.8-rc1/fs/hpfs/buffer.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/hpfs/buffer.c 2004-07-13 17:09:13.000000000 -0700 @@ -73,7 +73,7 @@ void *hpfs_map_4sectors(struct super_blo if (secno & 3) { printk("HPFS: hpfs_map_4sectors: unaligned read\n"); - return 0; + return NULL; } qbh->data = data = (char *)kmalloc(2048, GFP_NOFS); @@ -126,7 +126,7 @@ void *hpfs_get_4sectors(struct super_blo if (secno & 3) { printk("HPFS: hpfs_get_4sectors: unaligned read\n"); - return 0; + return NULL; } /*return hpfs_map_4sectors(s, secno, qbh, 0);*/ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hppfs/hppfs_kern.c 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,811 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "os.h" + +static int init_inode(struct inode *inode, struct dentry *dentry); + +struct hppfs_data { + struct list_head list; + char contents[PAGE_SIZE - sizeof(struct list_head)]; +}; + +struct hppfs_private { + struct file proc_file; + int host_fd; + loff_t len; + struct hppfs_data *contents; +}; + +struct hppfs_inode_info { + struct dentry *proc_dentry; + struct inode vfs_inode; +}; + +static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) +{ + return(list_entry(inode, struct hppfs_inode_info, vfs_inode)); +} + +#define HPPFS_SUPER_MAGIC 0xb00000ee + +static struct super_operations hppfs_sbops; + +static int is_pid(struct dentry *dentry) +{ + struct super_block *sb; + int i; + + sb = dentry->d_sb; + if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root)) + return(0); + + for(i = 0; i < dentry->d_name.len; i++){ + if(!isdigit(dentry->d_name.name[i])) + return(0); + } + return(1); +} + +static char *dentry_name(struct dentry *dentry, int extra) +{ + struct dentry *parent; + char *root, *name; + const char *seg_name; + int len, seg_len; + + len = 0; + parent = dentry; + while(parent->d_parent != parent){ + if(is_pid(parent)) + len += strlen("pid") + 1; + else len += parent->d_name.len + 1; + parent = parent->d_parent; + } + + root = "proc"; + len += strlen(root); + name = kmalloc(len + extra + 1, GFP_KERNEL); + if(name == NULL) return(NULL); + + name[len] = '\0'; + parent = dentry; + while(parent->d_parent != parent){ + if(is_pid(parent)){ + seg_name = "pid"; + seg_len = strlen("pid"); + } + else { + seg_name = parent->d_name.name; + seg_len = parent->d_name.len; + } + + len -= seg_len + 1; + name[len] = '/'; + strncpy(&name[len + 1], seg_name, seg_len); + parent = parent->d_parent; + } + strncpy(name, root, strlen(root)); + return(name); +} + +struct dentry_operations hppfs_dentry_ops = { +}; + +static int file_removed(struct dentry *dentry, const char *file) +{ + char *host_file; + int extra, fd; + + extra = 0; + if(file != NULL) extra += strlen(file) + 1; + + host_file = dentry_name(dentry, extra + strlen("/remove")); + if(host_file == NULL){ + printk("file_removed : allocation failed\n"); + return(-ENOMEM); + } + + if(file != NULL){ + strcat(host_file, "/"); + strcat(host_file, file); + } + strcat(host_file, "/remove"); + + fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); + kfree(host_file); + if(fd > 0){ + os_close_file(fd); + return(1); + } + return(0); +} + +static void hppfs_read_inode(struct inode *ino) +{ + struct inode *proc_ino; + + if(HPPFS_I(ino)->proc_dentry == NULL) + return; + + proc_ino = HPPFS_I(ino)->proc_dentry->d_inode; + ino->i_uid = proc_ino->i_uid; + ino->i_gid = proc_ino->i_gid; + ino->i_atime = proc_ino->i_atime; + ino->i_mtime = proc_ino->i_mtime; + ino->i_ctime = proc_ino->i_ctime; + ino->i_ino = proc_ino->i_ino; + ino->i_mode = proc_ino->i_mode; + ino->i_nlink = proc_ino->i_nlink; + ino->i_size = proc_ino->i_size; + ino->i_blksize = proc_ino->i_blksize; + ino->i_blocks = proc_ino->i_blocks; +} + +static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, + struct nameidata *nd) +{ + struct dentry *proc_dentry, *new, *parent; + struct inode *inode; + int err, deleted; + + deleted = file_removed(dentry, NULL); + if(deleted < 0) + return(ERR_PTR(deleted)); + else if(deleted) + return(ERR_PTR(-ENOENT)); + + err = -ENOMEM; + parent = HPPFS_I(ino)->proc_dentry; + down(&parent->d_inode->i_sem); + proc_dentry = d_lookup(parent, &dentry->d_name); + if(proc_dentry == NULL){ + proc_dentry = d_alloc(parent, &dentry->d_name); + if(proc_dentry == NULL){ + up(&parent->d_inode->i_sem); + goto out; + } + new = (*parent->d_inode->i_op->lookup)(parent->d_inode, + proc_dentry, NULL); + if(new){ + dput(proc_dentry); + proc_dentry = new; + } + } + up(&parent->d_inode->i_sem); + + if(IS_ERR(proc_dentry)) + return(proc_dentry); + + inode = iget(ino->i_sb, 0); + if(inode == NULL) + goto out_dput; + + err = init_inode(inode, proc_dentry); + if(err) + goto out_put; + + hppfs_read_inode(inode); + + d_add(dentry, inode); + dentry->d_op = &hppfs_dentry_ops; + return(NULL); + + out_put: + iput(inode); + out_dput: + dput(proc_dentry); + out: + return(ERR_PTR(err)); +} + +static struct inode_operations hppfs_file_iops = { +}; + +static ssize_t read_proc(struct file *file, char *buf, ssize_t count, + loff_t *ppos, int is_user) +{ + ssize_t (*read)(struct file *, char *, size_t, loff_t *); + ssize_t n; + + read = file->f_dentry->d_inode->i_fop->read; + + if(!is_user) + set_fs(KERNEL_DS); + + n = (*read)(file, buf, count, &file->f_pos); + + if(!is_user) + set_fs(USER_DS); + + if(ppos) *ppos = file->f_pos; + return(n); +} + +static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count) +{ + ssize_t n; + int cur, err; + char *new_buf; + + n = -ENOMEM; + new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if(new_buf == NULL){ + printk("hppfs_read_file : kmalloc failed\n"); + goto out; + } + n = 0; + while(count > 0){ + cur = min_t(ssize_t, count, PAGE_SIZE); + err = os_read_file(fd, new_buf, cur); + if(err < 0){ + printk("hppfs_read : read failed, errno = %d\n", + count); + n = err; + goto out_free; + } + else if(err == 0) + break; + + if(copy_to_user(buf, new_buf, err)){ + n = -EFAULT; + goto out_free; + } + n += err; + count -= err; + } + out_free: + kfree(new_buf); + out: + return(n); +} + +static ssize_t hppfs_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + struct hppfs_private *hppfs = file->private_data; + struct hppfs_data *data; + loff_t off; + int err; + + if(hppfs->contents != NULL){ + if(*ppos >= hppfs->len) return(0); + + data = hppfs->contents; + off = *ppos; + while(off >= sizeof(data->contents)){ + data = list_entry(data->list.next, struct hppfs_data, + list); + off -= sizeof(data->contents); + } + + if(off + count > hppfs->len) + count = hppfs->len - off; + copy_to_user(buf, &data->contents[off], count); + *ppos += count; + } + else if(hppfs->host_fd != -1){ + err = os_seek_file(hppfs->host_fd, *ppos); + if(err){ + printk("hppfs_read : seek failed, errno = %d\n", err); + return(err); + } + count = hppfs_read_file(hppfs->host_fd, buf, count); + if(count > 0) + *ppos += count; + } + else count = read_proc(&hppfs->proc_file, buf, count, ppos, 1); + + return(count); +} + +static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, + loff_t *ppos) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = &data->proc_file; + ssize_t (*write)(struct file *, const char *, size_t, loff_t *); + int err; + + write = proc_file->f_dentry->d_inode->i_fop->write; + + proc_file->f_pos = file->f_pos; + err = (*write)(proc_file, buf, len, &proc_file->f_pos); + file->f_pos = proc_file->f_pos; + + return(err); +} + +static int open_host_sock(char *host_file, int *filter_out) +{ + char *end; + int fd; + + end = &host_file[strlen(host_file)]; + strcpy(end, "/rw"); + *filter_out = 1; + fd = os_connect_socket(host_file); + if(fd > 0) + return(fd); + + strcpy(end, "/r"); + *filter_out = 0; + fd = os_connect_socket(host_file); + return(fd); +} + +static void free_contents(struct hppfs_data *head) +{ + struct hppfs_data *data; + struct list_head *ele, *next; + + if(head == NULL) return; + + list_for_each_safe(ele, next, &head->list){ + data = list_entry(ele, struct hppfs_data, list); + kfree(data); + } + kfree(head); +} + +static struct hppfs_data *hppfs_get_data(int fd, int filter, + struct file *proc_file, + struct file *hppfs_file, + loff_t *size_out) +{ + struct hppfs_data *data, *new, *head; + int n, err; + + err = -ENOMEM; + data = kmalloc(sizeof(*data), GFP_KERNEL); + if(data == NULL){ + printk("hppfs_get_data : head allocation failed\n"); + goto failed; + } + + INIT_LIST_HEAD(&data->list); + + head = data; + *size_out = 0; + + if(filter){ + while((n = read_proc(proc_file, data->contents, + sizeof(data->contents), NULL, 0)) > 0) + os_write_file(fd, data->contents, n); + err = os_shutdown_socket(fd, 0, 1); + if(err){ + printk("hppfs_get_data : failed to shut down " + "socket\n"); + goto failed_free; + } + } + while(1){ + n = os_read_file(fd, data->contents, sizeof(data->contents)); + if(n < 0){ + err = n; + printk("hppfs_get_data : read failed, errno = %d\n", + err); + goto failed_free; + } + else if(n == 0) + break; + + *size_out += n; + + if(n < sizeof(data->contents)) + break; + + new = kmalloc(sizeof(*data), GFP_KERNEL); + if(new == 0){ + printk("hppfs_get_data : data allocation failed\n"); + err = -ENOMEM; + goto failed_free; + } + + INIT_LIST_HEAD(&new->list); + list_add(&new->list, &data->list); + data = new; + } + return(head); + + failed_free: + free_contents(head); + failed: + return(ERR_PTR(err)); +} + +static struct hppfs_private *hppfs_data(void) +{ + struct hppfs_private *data; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if(data == NULL) + return(data); + + *data = ((struct hppfs_private ) { .host_fd = -1, + .len = -1, + .contents = NULL } ); + return(data); +} + +static int file_mode(int fmode) +{ + if(fmode == (FMODE_READ | FMODE_WRITE)) + return(O_RDWR); + if(fmode == FMODE_READ) + return(O_RDONLY); + if(fmode == FMODE_WRITE) + return(O_WRONLY); + return(0); +} + +static int hppfs_open(struct inode *inode, struct file *file) +{ + struct hppfs_private *data; + struct dentry *proc_dentry; + char *host_file; + int err, fd, type, filter; + + err = -ENOMEM; + data = hppfs_data(); + if(data == NULL) + goto out; + + host_file = dentry_name(file->f_dentry, strlen("/rw")); + if(host_file == NULL) + goto out_free2; + + proc_dentry = HPPFS_I(inode)->proc_dentry; + + /* XXX This isn't closed anywhere */ + err = open_private_file(&data->proc_file, proc_dentry, + file_mode(file->f_mode)); + if(err) + goto out_free1; + + type = os_file_type(host_file); + if(type == OS_TYPE_FILE){ + fd = os_open_file(host_file, of_read(OPENFLAGS()), 0); + if(fd >= 0) + data->host_fd = fd; + else printk("hppfs_open : failed to open '%s', errno = %d\n", + host_file, -fd); + + data->contents = NULL; + } + else if(type == OS_TYPE_DIR){ + fd = open_host_sock(host_file, &filter); + if(fd > 0){ + data->contents = hppfs_get_data(fd, filter, + &data->proc_file, + file, &data->len); + if(!IS_ERR(data->contents)) + data->host_fd = fd; + } + else printk("hppfs_open : failed to open a socket in " + "'%s', errno = %d\n", host_file, -fd); + } + kfree(host_file); + + file->private_data = data; + return(0); + + out_free1: + kfree(host_file); + out_free2: + free_contents(data->contents); + kfree(data); + out: + return(err); +} + +static int hppfs_dir_open(struct inode *inode, struct file *file) +{ + struct hppfs_private *data; + struct dentry *proc_dentry; + int err; + + err = -ENOMEM; + data = hppfs_data(); + if(data == NULL) + goto out; + + proc_dentry = HPPFS_I(inode)->proc_dentry; + err = open_private_file(&data->proc_file, proc_dentry, + file_mode(file->f_mode)); + if(err) + goto out_free; + + file->private_data = data; + return(0); + + out_free: + kfree(data); + out: + return(err); +} + +static loff_t hppfs_llseek(struct file *file, loff_t off, int where) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = &data->proc_file; + loff_t (*llseek)(struct file *, loff_t, int); + loff_t ret; + + llseek = proc_file->f_dentry->d_inode->i_fop->llseek; + if(llseek != NULL){ + ret = (*llseek)(proc_file, off, where); + if(ret < 0) + return(ret); + } + + return(default_llseek(file, off, where)); +} + +static struct file_operations hppfs_file_fops = { + .owner = NULL, + .llseek = hppfs_llseek, + .read = hppfs_read, + .write = hppfs_write, + .open = hppfs_open, +}; + +struct hppfs_dirent { + void *vfs_dirent; + filldir_t filldir; + struct dentry *dentry; +}; + +static int hppfs_filldir(void *d, const char *name, int size, + loff_t offset, ino_t inode, unsigned int type) +{ + struct hppfs_dirent *dirent = d; + + if(file_removed(dirent->dentry, name)) + return(0); + + return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, + inode, type)); +} + +static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) +{ + struct hppfs_private *data = file->private_data; + struct file *proc_file = &data->proc_file; + int (*readdir)(struct file *, void *, filldir_t); + struct hppfs_dirent dirent = ((struct hppfs_dirent) + { .vfs_dirent = ent, + .filldir = filldir, + .dentry = file->f_dentry } ); + int err; + + readdir = proc_file->f_dentry->d_inode->i_fop->readdir; + + proc_file->f_pos = file->f_pos; + err = (*readdir)(proc_file, &dirent, hppfs_filldir); + file->f_pos = proc_file->f_pos; + + return(err); +} + +static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return(0); +} + +static struct file_operations hppfs_dir_fops = { + .owner = NULL, + .readdir = hppfs_readdir, + .open = hppfs_dir_open, + .fsync = hppfs_fsync, +}; + +static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf) +{ + sf->f_blocks = 0; + sf->f_bfree = 0; + sf->f_bavail = 0; + sf->f_files = 0; + sf->f_ffree = 0; + sf->f_type = HPPFS_SUPER_MAGIC; + return(0); +} + +static struct inode *hppfs_alloc_inode(struct super_block *sb) +{ + struct hppfs_inode_info *hi; + + hi = kmalloc(sizeof(*hi), GFP_KERNEL); + if(hi == NULL) + return(NULL); + + *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL }); + inode_init_once(&hi->vfs_inode); + return(&hi->vfs_inode); +} + +void hppfs_delete_inode(struct inode *ino) +{ + clear_inode(ino); +} + +static void hppfs_destroy_inode(struct inode *inode) +{ + kfree(HPPFS_I(inode)); +} + +static struct super_operations hppfs_sbops = { + .alloc_inode = hppfs_alloc_inode, + .destroy_inode = hppfs_destroy_inode, + .read_inode = hppfs_read_inode, + .delete_inode = hppfs_delete_inode, + .statfs = hppfs_statfs, +}; + +static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct file proc_file; + struct dentry *proc_dentry; + int (*readlink)(struct dentry *, char *, int); + int err, n; + + proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + err = open_private_file(&proc_file, proc_dentry, O_RDONLY); + if(err) + return(err); + + readlink = proc_dentry->d_inode->i_op->readlink; + n = (*readlink)(proc_dentry, buffer, buflen); + + close_private_file(&proc_file); + + return(n); +} + +static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct file proc_file; + struct dentry *proc_dentry; + int (*follow_link)(struct dentry *, struct nameidata *); + int err, n; + + proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; + err = open_private_file(&proc_file, proc_dentry, O_RDONLY); + if(err) + return(err); + + follow_link = proc_dentry->d_inode->i_op->follow_link; + n = (*follow_link)(proc_dentry, nd); + + close_private_file(&proc_file); + + return(n); +} + +static struct inode_operations hppfs_dir_iops = { + .lookup = hppfs_lookup, +}; + +static struct inode_operations hppfs_link_iops = { + .readlink = hppfs_readlink, + .follow_link = hppfs_follow_link, +}; + +static int init_inode(struct inode *inode, struct dentry *dentry) +{ + if(S_ISDIR(dentry->d_inode->i_mode)){ + inode->i_op = &hppfs_dir_iops; + inode->i_fop = &hppfs_dir_fops; + } + else if(S_ISLNK(dentry->d_inode->i_mode)){ + inode->i_op = &hppfs_link_iops; + inode->i_fop = &hppfs_file_fops; + } + else { + inode->i_op = &hppfs_file_iops; + inode->i_fop = &hppfs_file_fops; + } + + HPPFS_I(inode)->proc_dentry = dentry; + + return(0); +} + +static int hppfs_fill_super(struct super_block *sb, void *d, int silent) +{ + struct inode *root_inode; + struct file_system_type *procfs; + struct super_block *proc_sb; + int err; + + err = -ENOENT; + procfs = get_fs_type("proc"); + if(procfs == NULL) + goto out; + + if(list_empty(&procfs->fs_supers)) + goto out; + + proc_sb = list_entry(procfs->fs_supers.next, struct super_block, + s_instances); + + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = HPPFS_SUPER_MAGIC; + sb->s_op = &hppfs_sbops; + + root_inode = iget(sb, 0); + if(root_inode == NULL) + goto out; + + err = init_inode(root_inode, proc_sb->s_root); + if(err) + goto out_put; + + err = -ENOMEM; + sb->s_root = d_alloc_root(root_inode); + if(sb->s_root == NULL) + goto out_put; + + hppfs_read_inode(root_inode); + + return(0); + + out_put: + iput(root_inode); + out: + return(err); +} + +static struct super_block *hppfs_read_super(struct file_system_type *type, + int flags, const char *dev_name, + void *data) +{ + return(get_sb_nodev(type, flags, data, hppfs_fill_super)); +} + +static struct file_system_type hppfs_type = { + .owner = THIS_MODULE, + .name = "hppfs", + .get_sb = hppfs_read_super, + .kill_sb = kill_anon_super, + .fs_flags = 0, +}; + +static int __init init_hppfs(void) +{ + return(register_filesystem(&hppfs_type)); +} + +static void __exit exit_hppfs(void) +{ + unregister_filesystem(&hppfs_type); +} + +module_init(init_hppfs) +module_exit(exit_hppfs) +MODULE_LICENSE("GPL"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/fs/hppfs/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,19 @@ +# +# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +hppfs-objs := hppfs_kern.o + +obj-y = +obj-$(CONFIG_HPPFS) += hppfs.o + +clean: + +modules: + +fastdep: + +dep: + +archmrproper: clean --- linux-2.6.8-rc1/fs/hugetlbfs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/hugetlbfs/inode.c 2004-07-13 17:35:08.000000000 -0700 @@ -52,6 +52,12 @@ static int hugetlbfs_file_mmap(struct fi loff_t len, vma_len; int ret; + if ((vma->vm_flags & (VM_MAYSHARE | VM_WRITE)) == VM_WRITE) + return -EINVAL; + + if (vma->vm_pgoff & (HPAGE_SIZE / PAGE_SIZE - 1)) + return -EINVAL; + if (vma->vm_start & ~HPAGE_MASK) return -EINVAL; @@ -67,10 +73,19 @@ static int hugetlbfs_file_mmap(struct fi file_accessed(file); vma->vm_flags |= VM_HUGETLB | VM_RESERVED; vma->vm_ops = &hugetlb_vm_ops; + + ret = -ENOMEM; + len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); + if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) + goto out; + ret = hugetlb_prefault(mapping, vma); - len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); - if (ret == 0 && inode->i_size < len) + if (ret) + goto out; + + if (inode->i_size < len) inode->i_size = len; +out: up(&inode->i_sem); return ret; @@ -196,6 +211,7 @@ static void hugetlbfs_delete_inode(struc hlist_del_init(&inode->i_hash); list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -238,6 +254,7 @@ static void hugetlbfs_forget_inode(struc hlist_del_init(&inode->i_hash); out_truncate: list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -278,16 +295,16 @@ hugetlb_vmtruncate_list(struct prio_tree unsigned long v_length; unsigned long v_offset; - h_vm_pgoff = vma->vm_pgoff << (HPAGE_SHIFT - PAGE_SHIFT); - v_length = vma->vm_end - vma->vm_start; + h_vm_pgoff = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT); v_offset = (h_pgoff - h_vm_pgoff) << HPAGE_SHIFT; - /* * Is this VMA fully outside the truncation point? */ if (h_vm_pgoff >= h_pgoff) v_offset = 0; + v_length = vma->vm_end - vma->vm_start; + zap_hugepage_range(vma, vma->vm_start + v_offset, v_length - v_offset); @@ -717,8 +734,11 @@ static unsigned long hugetlbfs_counter(v static int can_do_hugetlb_shm(void) { - return likely(capable(CAP_IPC_LOCK) || - in_group_p(sysctl_hugetlb_shm_group)); + if (capable(CAP_IPC_LOCK)) + return 1; + if (sysctl_hugetlb_shm_group == 0) + return 0; + return in_group_p(sysctl_hugetlb_shm_group); } struct file *hugetlb_zero_setup(size_t size) --- linux-2.6.8-rc1/fs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/inode.c 2004-07-13 17:09:51.000000000 -0700 @@ -196,7 +196,7 @@ void inode_init_once(struct inode *inode sema_init(&inode->i_sem, 1); init_rwsem(&inode->i_alloc_sem); INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); - spin_lock_init(&inode->i_data.tree_lock); + rwlock_init(&inode->i_data.tree_lock); spin_lock_init(&inode->i_data.i_mmap_lock); atomic_set(&inode->i_data.truncate_count, 0); INIT_LIST_HEAD(&inode->i_data.private_list); @@ -243,6 +243,7 @@ void __iget(struct inode * inode) */ void clear_inode(struct inode *inode) { + might_sleep(); invalidate_inode_buffers(inode); if (inode->i_data.nrpages) @@ -295,7 +296,7 @@ static void dispose_list(struct list_hea /* * Invalidate all inodes for a device. */ -static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose) +static int invalidate_list(struct list_head *head, struct list_head *dispose) { struct list_head *next; int busy = 0, count = 0; @@ -308,12 +309,11 @@ static int invalidate_list(struct list_h next = next->next; if (tmp == head) break; - inode = list_entry(tmp, struct inode, i_list); - if (inode->i_sb != sb) - continue; + inode = list_entry(tmp, struct inode, i_sb_list); invalidate_inode_buffers(inode); if (!atomic_read(&inode->i_count)) { hlist_del_init(&inode->i_hash); + list_del(&inode->i_sb_list); list_move(&inode->i_list, dispose); inode->i_state |= I_FREEING; count++; @@ -349,10 +349,7 @@ int invalidate_inodes(struct super_block down(&iprune_sem); spin_lock(&inode_lock); - busy = invalidate_list(&inode_in_use, sb, &throw_away); - busy |= invalidate_list(&inode_unused, sb, &throw_away); - busy |= invalidate_list(&sb->s_dirty, sb, &throw_away); - busy |= invalidate_list(&sb->s_io, sb, &throw_away); + busy = invalidate_list(&sb->s_inodes, &throw_away); spin_unlock(&inode_lock); dispose_list(&throw_away); @@ -452,6 +449,7 @@ static void prune_icache(int nr_to_scan) continue; } hlist_del_init(&inode->i_hash); + list_del_init(&inode->i_sb_list); list_move(&inode->i_list, &freeable); inode->i_state |= I_FREEING; nr_pruned++; @@ -562,6 +560,7 @@ struct inode *new_inode(struct super_blo spin_lock(&inode_lock); inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); inode->i_ino = ++last_ino; inode->i_state = 0; spin_unlock(&inode_lock); @@ -610,6 +609,7 @@ static struct inode * get_new_inode(stru inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); hlist_add_head(&inode->i_hash, head); inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); @@ -658,6 +658,7 @@ static struct inode * get_new_inode_fast inode->i_ino = ino; inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); + list_add(&inode->i_sb_list, &sb->s_inodes); hlist_add_head(&inode->i_hash, head); inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); @@ -994,6 +995,7 @@ void generic_delete_inode(struct inode * struct super_operations *op = inode->i_sb->s_op; list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state|=I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1039,6 +1041,7 @@ static void generic_forget_inode(struct hlist_del_init(&inode->i_hash); } list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); inode->i_state|=I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); @@ -1227,36 +1230,23 @@ EXPORT_SYMBOL(inode_needs_sync); /* Function back in dquot.c */ int remove_inode_dquot_ref(struct inode *, int, struct list_head *); -void remove_dquot_ref(struct super_block *sb, int type, struct list_head *tofree_head) +void remove_dquot_ref(struct super_block *sb, int type, + struct list_head *tofree_head) { struct inode *inode; - struct list_head *act_head; if (!sb->dq_op) return; /* nothing to do */ spin_lock(&inode_lock); /* This lock is for inodes code */ - /* We hold dqptr_sem so we are safe against the quota code */ - list_for_each(act_head, &inode_in_use) { - inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && !IS_NOQUOTA(inode)) - remove_inode_dquot_ref(inode, type, tofree_head); - } - list_for_each(act_head, &inode_unused) { - inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && !IS_NOQUOTA(inode)) - remove_inode_dquot_ref(inode, type, tofree_head); - } - list_for_each(act_head, &sb->s_dirty) { - inode = list_entry(act_head, struct inode, i_list); - if (!IS_NOQUOTA(inode)) - remove_inode_dquot_ref(inode, type, tofree_head); - } - list_for_each(act_head, &sb->s_io) { - inode = list_entry(act_head, struct inode, i_list); + /* + * We don't have to lock against quota code - test IS_QUOTAINIT is + * just for speedup... + */ + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) if (!IS_NOQUOTA(inode)) remove_inode_dquot_ref(inode, type, tofree_head); - } + spin_unlock(&inode_lock); } --- linux-2.6.8-rc1/fs/isofs/compress.c 2003-06-14 12:17:58.000000000 -0700 +++ 25/fs/isofs/compress.c 2004-07-13 17:09:13.000000000 -0700 @@ -114,7 +114,7 @@ static int zisofs_readpage(struct file * blockendptr = blockptr + 4; indexblocks = ((blockptr^blockendptr) >> bufshift) ? 2 : 1; - ptrbh[0] = ptrbh[1] = 0; + ptrbh[0] = ptrbh[1] = NULL; if ( isofs_get_blocks(inode, blockptr >> bufshift, ptrbh, indexblocks) != indexblocks ) { if ( ptrbh[0] ) brelse(ptrbh[0]); --- linux-2.6.8-rc1/fs/jbd/checkpoint.c 2003-07-13 21:44:35.000000000 -0700 +++ 25/fs/jbd/checkpoint.c 2004-07-13 17:35:41.000000000 -0700 @@ -132,6 +132,7 @@ static int __cleanup_transaction(journal { struct journal_head *jh, *next_jh, *last_jh; struct buffer_head *bh; + unsigned char nr_buffers = 1; int ret = 0; assert_spin_locked(&journal->j_list_lock); @@ -185,9 +186,15 @@ static int __cleanup_transaction(journal journal_remove_journal_head(bh); __brelse(bh); ret = 1; + nr_buffers++; } else { jbd_unlock_bh_state(bh); } + if (nr_buffers == 0) { + spin_lock(&journal->j_list_lock); + cpu_relax(); + goto out_return_1; + } jh = next_jh; } while (jh != last_jh); @@ -455,9 +462,8 @@ int cleanup_journal_tail(journal_t *jour * * Find all the written-back checkpoint buffers in the journal and release them. * - * Called with the journal locked. - * Called with j_list_lock held. - * Returns number of bufers reaped (for debug) + * Called with j_list_lock held, drops it. + * Returns number of bufers reaped */ int __journal_clean_checkpoint_list(journal_t *journal) @@ -467,7 +473,7 @@ int __journal_clean_checkpoint_list(jour transaction = journal->j_checkpoint_transactions; if (transaction == 0) - goto out; + goto out_unlock; last_transaction = transaction->t_cpprev; next_transaction = transaction; @@ -484,13 +490,41 @@ int __journal_clean_checkpoint_list(jour do { jh = next_jh; next_jh = jh->b_cpnext; - /* Use trylock because of the ranknig */ + /* Use trylock because of the ranking */ if (jbd_trylock_bh_state(jh2bh(jh))) ret += __try_to_free_cp_buf(jh); } while (jh != last_jh); } +#ifdef CONFIG_PREEMPT + /* + * This is potentially sucky: semi-quadratic performance if + * there are a lot of dirty buffers. So only do it if the user + * has chosen a preemptible kernel. If !CONFIG_PREEMPT we're + * optimimising for straight-line performance, after all. + * We don't test cond_resched() here because another CPU could + * be waiting on j_list_lock() while holding a different lock. + */ + if ((ret & 127) == 127) { + spin_unlock(&journal->j_list_lock); + /* + * We need to schedule away. Rotate both this + * transaction's buffer list and the checkpoint list to + * try to avoid quadratic behaviour. + */ + jh = transaction->t_checkpoint_list; + if (jh) + transaction->t_checkpoint_list = jh->b_cpnext; + + transaction = journal->j_checkpoint_transactions; + if (transaction) + journal->j_checkpoint_transactions = + transaction->t_cpnext; + return ret; + } +#endif } while (transaction != last_transaction); -out: +out_unlock: + spin_unlock(&journal->j_list_lock); return ret; } --- linux-2.6.8-rc1/fs/jbd/commit.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jbd/commit.c 2004-07-13 17:35:41.000000000 -0700 @@ -114,6 +114,7 @@ void journal_commit_transaction(journal_ int space_left = 0; int first_tag = 0; int tag_flag; + int nr_buffers = 0; int i; /* @@ -208,9 +209,16 @@ void journal_commit_transaction(journal_ * checkpoint lists. We do this *before* commit because it potentially * frees some memory */ - spin_lock(&journal->j_list_lock); - __journal_clean_checkpoint_list(journal); - spin_unlock(&journal->j_list_lock); + spin_unlock(&journal->j_state_lock); + { + int nr_cleaned; + + do { + spin_lock(&journal->j_list_lock); + nr_cleaned = __journal_clean_checkpoint_list(journal); + } while (nr_cleaned); + } + spin_lock(&journal->j_state_lock); jbd_debug (3, "JBD: commit phase 1\n"); @@ -262,8 +270,10 @@ write_out_data: __journal_file_buffer(jh, commit_transaction, BJ_Locked); jbd_unlock_bh_state(bh); - if (need_resched()) { + nr_buffers++; + if ((nr_buffers & 15) == 0 || need_resched()) { spin_unlock(&journal->j_list_lock); + cpu_relax(); goto write_out_data; } } else { @@ -288,8 +298,10 @@ write_out_data: jbd_unlock_bh_state(bh); journal_remove_journal_head(bh); put_bh(bh); - if (need_resched()) { + nr_buffers++; + if ((nr_buffers & 15) == 0 || need_resched()) { spin_unlock(&journal->j_list_lock); + cpu_relax(); goto write_out_data; } } @@ -333,7 +345,8 @@ write_out_data: jbd_unlock_bh_state(bh); } put_bh(bh); - if (need_resched()) { + nr_buffers++; + if ((nr_buffers & 15) == 0 || need_resched()) { spin_unlock(&journal->j_list_lock); cond_resched(); spin_lock(&journal->j_list_lock); @@ -639,10 +652,38 @@ wait_for_iobuf: JBUFFER_TRACE(descriptor, "write commit block"); { struct buffer_head *bh = jh2bh(descriptor); + int ret; + int barrier_done = 0; set_buffer_dirty(bh); - sync_dirty_buffer(bh); - if (unlikely(!buffer_uptodate(bh))) + if (journal->j_flags & JFS_BARRIER) { + set_buffer_ordered(bh); + barrier_done = 1; + } + ret = sync_dirty_buffer(bh); + /* is it possible for another commit to fail at roughly + * the same time as this one? If so, we don't want to + * trust the barrier flag in the super, but instead want + * to remember if we sent a barrier request + */ + if (ret == -EOPNOTSUPP && barrier_done) { + char b[BDEVNAME_SIZE]; + + printk(KERN_WARNING + "JBD: barrier-based sync failed on %s - " + "disabling barriers\n", + bdevname(journal->j_dev, b)); + spin_lock(&journal->j_state_lock); + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); + + /* And try again, without the barrier */ + clear_buffer_ordered(bh); + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + ret = sync_dirty_buffer(bh); + } + if (unlikely(ret == -EIO)) err = -EIO; put_bh(bh); /* One for getblk() */ journal_put_journal_head(descriptor); --- linux-2.6.8-rc1/fs/jbd/journal.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jbd/journal.c 2004-07-13 17:09:28.000000000 -0700 @@ -1714,9 +1714,17 @@ repeat: if (buffer_jbd(bh)) { jh = bh2jh(bh); } else { - J_ASSERT_BH(bh, - (atomic_read(&bh->b_count) > 0) || - (bh->b_page && bh->b_page->mapping)); + if (!(atomic_read(&bh->b_count) > 0 || + (bh->b_page && bh->b_page->mapping))) { + printk(KERN_EMERG "%s: bh->b_count=%d\n", + __FUNCTION__, atomic_read(&bh->b_count)); + printk(KERN_EMERG "%s: bh->b_page=%p\n", + __FUNCTION__, bh->b_page); + if (bh->b_page) + printk(KERN_EMERG "%s: " + "bh->b_page->mapping=%p\n", + __FUNCTION__, bh->b_page->mapping); + } if (!new_jh) { jbd_unlock_bh_journal_head(bh); --- linux-2.6.8-rc1/fs/jbd/recovery.c 2004-04-03 20:39:13.000000000 -0800 +++ 25/fs/jbd/recovery.c 2004-07-13 17:35:40.000000000 -0700 @@ -354,6 +354,8 @@ static int do_one_pass(journal_t *journa struct buffer_head * obh; struct buffer_head * nbh; + cond_resched(); /* We're under lock_kernel() */ + /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of * the log. */ --- linux-2.6.8-rc1/fs/jbd/revoke.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jbd/revoke.c 2004-07-13 17:09:51.000000000 -0700 @@ -332,6 +332,7 @@ int journal_revoke(handle_t *handle, uns struct block_device *bdev; int err; + might_sleep(); if (bh_in) BUFFER_TRACE(bh_in, "enter"); --- linux-2.6.8-rc1/fs/jbd/transaction.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jbd/transaction.c 2004-07-13 17:09:28.000000000 -0700 @@ -940,7 +940,6 @@ out: int journal_dirty_data(handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; - int need_brelse = 0; struct journal_head *jh; if (is_handle_aborted(handle)) @@ -1025,24 +1024,6 @@ int journal_dirty_data(handle_t *handle, goto no_journal; } - /* - * This buffer may be undergoing writeout in commit. We - * can't return from here and let the caller dirty it - * again because that can cause the write-out loop in - * commit to never terminate. - */ - if (buffer_dirty(bh)) { - get_bh(bh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - need_brelse = 1; - sync_dirty_buffer(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - /* The buffer may become locked again at any - time if it is redirtied */ - } - /* journal_clean_data_list() may have got there first */ if (jh->b_transaction != NULL) { JBUFFER_TRACE(jh, "unfile from commit"); @@ -1072,10 +1053,6 @@ int journal_dirty_data(handle_t *handle, no_journal: spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); - if (need_brelse) { - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - } JBUFFER_TRACE(jh, "exit"); journal_put_journal_head(jh); return 0; --- linux-2.6.8-rc1/fs/jffs/jffs_fm.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jffs/jffs_fm.c 2004-07-13 17:09:13.000000000 -0700 @@ -114,10 +114,9 @@ void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc) { if (fmc) { - struct jffs_fm *cur; struct jffs_fm *next = fmc->head; - - while ((cur = next)) { + while (next) { + struct jffs_fm *cur = next; next = next->next; jffs_free_fm(cur); } --- linux-2.6.8-rc1/fs/jfs/file.c 2003-10-17 15:58:04.000000000 -0700 +++ 25/fs/jfs/file.c 2004-07-13 17:09:22.000000000 -0700 @@ -65,11 +65,13 @@ static int jfs_open(struct inode *inode, if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE && (inode->i_size == 0)) { struct jfs_inode_info *ji = JFS_IP(inode); + spin_lock_irq(&ji->ag_lock); if (ji->active_ag == -1) { ji->active_ag = ji->agno; atomic_inc( &JFS_SBI(inode->i_sb)->bmap->db_active[ji->agno]); } + spin_unlock_irq(&ji->ag_lock); } return 0; @@ -78,11 +80,13 @@ static int jfs_release(struct inode *ino { struct jfs_inode_info *ji = JFS_IP(inode); + spin_lock_irq(&ji->ag_lock); if (ji->active_ag != -1) { struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap; atomic_dec(&bmap->db_active[ji->active_ag]); ji->active_ag = -1; } + spin_unlock_irq(&ji->ag_lock); return 0; } --- linux-2.6.8-rc1/fs/jfs/jfs_dmap.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/jfs/jfs_dmap.c 2004-07-13 17:09:22.000000000 -0700 @@ -1204,6 +1204,12 @@ static int dbAllocNext(struct bmap * bmp s8 *leaf; u32 mask; + if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocNext: Corrupt dmap page"); + return -EIO; + } + /* pick up a pointer to the leaves of the dmap tree. */ leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx); @@ -1327,7 +1333,15 @@ dbAllocNear(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks, int l2nb, s64 * results) { int word, lword, rc; - s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx); + s8 *leaf; + + if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocNear: Corrupt dmap page"); + return -EIO; + } + + leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx); /* determine the word within the dmap that holds the hint * (i.e. blkno). also, determine the last word in the dmap @@ -1489,6 +1503,13 @@ dbAllocAG(struct bmap * bmp, int agno, s dcp = (struct dmapctl *) mp->data; budmin = dcp->budmin; + if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: Corrupt dmapctl page"); + release_metapage(mp); + return -EIO; + } + /* search the subtree(s) of the dmap control page that describes * the allocation group, looking for sufficient free space. to begin, * determine how many allocation groups are represented in a dmap @@ -1697,6 +1718,13 @@ static int dbFindCtl(struct bmap * bmp, dcp = (struct dmapctl *) mp->data; budmin = dcp->budmin; + if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbFindCtl: Corrupt dmapctl page"); + release_metapage(mp); + return -EIO; + } + /* search the tree within the dmap control page for * sufficent free space. if sufficient free space is found, * dbFindLeaf() returns the index of the leaf at which @@ -2459,6 +2487,13 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, i return -EIO; dcp = (struct dmapctl *) mp->data; + if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAdjCtl: Corrupt dmapctl page"); + release_metapage(mp); + return -EIO; + } + /* determine the leaf number corresponding to the block and * the index within the dmap control tree. */ --- linux-2.6.8-rc1/fs/jfs/jfs_extent.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/jfs_extent.c 2004-07-13 17:09:22.000000000 -0700 @@ -553,6 +553,7 @@ extBalloc(struct inode *ip, s64 hint, s6 if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) { ag = BLKTOAG(daddr, sbi); + spin_lock_irq(&ji->ag_lock); if (ji->active_ag == -1) { atomic_inc(&bmp->db_active[ag]); ji->active_ag = ag; @@ -561,6 +562,7 @@ extBalloc(struct inode *ip, s64 hint, s6 atomic_inc(&bmp->db_active[ag]); ji->active_ag = ag; } + spin_unlock_irq(&ji->ag_lock); } return (0); --- linux-2.6.8-rc1/fs/jfs/jfs_imap.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/jfs_imap.c 2004-07-13 17:09:22.000000000 -0700 @@ -1280,6 +1280,7 @@ int diFree(struct inode *ip) * to be freed by the transaction; */ tid = txBegin(ipimap->i_sb, COMMIT_FORCE); + down(&JFS_IP(ipimap)->commit_sem); /* acquire tlock of the iag page of the freed ixad * to force the page NOHOMEOK (even though no data is @@ -1312,6 +1313,7 @@ int diFree(struct inode *ip) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); + up(&JFS_IP(ipimap)->commit_sem); /* unlock the AG inode map information */ AG_UNLOCK(imap, agno); @@ -2622,10 +2624,13 @@ diNewIAG(struct inomap * imap, int *iagn */ #endif /* _STILL_TO_PORT */ tid = txBegin(sb, COMMIT_FORCE); + down(&JFS_IP(ipimap)->commit_sem); /* update the inode map addressing structure to point to it */ if ((rc = xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) { + txEnd(tid); + up(&JFS_IP(ipimap)->commit_sem); /* Free the blocks allocated for the iag since it was * not successfully added to the inode map */ @@ -2650,6 +2655,7 @@ diNewIAG(struct inomap * imap, int *iagn rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); + up(&JFS_IP(ipimap)->commit_sem); duplicateIXtree(sb, blkno, xlen, &xaddr); --- linux-2.6.8-rc1/fs/jfs/jfs_incore.h 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/jfs/jfs_incore.h 2004-07-13 17:09:22.000000000 -0700 @@ -53,6 +53,7 @@ struct jfs_inode_info { lid_t blid; /* lid of pseudo buffer? */ lid_t atlhead; /* anonymous tlock list head */ lid_t atltail; /* anonymous tlock list tail */ + spinlock_t ag_lock; /* protects active_ag */ struct list_head anon_inode_list; /* inodes having anonymous txns */ /* * rdwrlock serializes xtree between reads & writes and synchronizes --- linux-2.6.8-rc1/fs/jfs/jfs_metapage.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/jfs_metapage.c 2004-07-13 17:09:22.000000000 -0700 @@ -225,8 +225,16 @@ struct metapage *__get_metapage(struct i if (absolute) mapping = inode->i_sb->s_bdev->bd_inode->i_mapping; - else + else { + /* + * If an nfs client tries to read an inode that is larger + * than any existing inodes, we may try to read past the + * end of the inode map + */ + if ((lblock << inode->i_blkbits) >= inode->i_size) + return NULL; mapping = inode->i_mapping; + } hash_ptr = meta_hash(mapping, lblock); again: --- linux-2.6.8-rc1/fs/jfs/jfs_xtree.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/jfs_xtree.c 2004-07-13 17:09:22.000000000 -0700 @@ -1071,8 +1071,10 @@ xtSplitUp(tid_t tid, */ /* get/pin the parent page */ XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc); - if (rc) - goto errout2; + if (rc) { + XT_PUTPAGE(rcmp); + return rc; + } /* * The new key entry goes ONE AFTER the index of parent entry, @@ -1106,8 +1108,10 @@ xtSplitUp(tid_t tid, rc = (sp->header.flag & BT_ROOT) ? xtSplitRoot(tid, ip, split, &rmp) : xtSplitPage(tid, ip, split, &rmp, &rbn); - if (rc) - goto errout1; + if (rc) { + XT_PUTPAGE(smp); + return rc; + } XT_PUTPAGE(smp); /* keep new child page pinned */ @@ -1170,19 +1174,6 @@ xtSplitUp(tid_t tid, XT_PUTPAGE(rmp); return 0; - - /* - * If something fails in the above loop we were already walking back - * up the tree and the tree is now inconsistent. - * release all pages we're holding. - */ - errout1: - XT_PUTPAGE(smp); - - errout2: - XT_PUTPAGE(rcmp); - - return rc; } @@ -3504,7 +3495,17 @@ s64 xtTruncate(tid_t tid, struct inode * * a page that was formerly to the right, let's make sure that the * next pointer is zero. */ - p->header.next = 0; + if (p->header.next) { + if (log) + /* + * Make sure this change to the header is logged. + * If we really truncate this leaf, the flag + * will be changed to tlckTRUNCATE + */ + tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW); + BT_MARK_DIRTY(mp, ip); + p->header.next = 0; + } freed = 0; --- linux-2.6.8-rc1/fs/jfs/namei.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/namei.c 2004-07-13 17:09:22.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) International Business Machines Corp., 2000-2003 + * Copyright (C) International Business Machines Corp., 2000-2004 * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -18,6 +18,7 @@ */ #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -43,6 +44,7 @@ extern int jfs_init_acl(struct inode *, */ struct inode_operations jfs_dir_inode_operations; struct file_operations jfs_dir_operations; +struct dentry_operations jfs_ci_dentry_operations; static s64 commitZeroLink(tid_t, struct inode *); @@ -1422,7 +1424,15 @@ static struct dentry *jfs_lookup(struct return ERR_PTR(-EACCES); } - return d_splice_alias(ip, dentry); + if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2) + dentry->d_op = &jfs_ci_dentry_operations; + + dentry = d_splice_alias(ip, dentry); + + if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) + dentry->d_op = &jfs_ci_dentry_operations; + + return dentry; } struct dentry *jfs_get_parent(struct dentry *dentry) @@ -1476,3 +1486,46 @@ struct file_operations jfs_dir_operation .readdir = jfs_readdir, .fsync = jfs_fsync, }; + +static int jfs_ci_hash(struct dentry *dir, struct qstr *this) +{ + unsigned long hash; + int i; + + hash = init_name_hash(); + for (i=0; i < this->len; i++) + hash = partial_name_hash(tolower(this->name[i]), hash); + this->hash = end_name_hash(hash); + + return 0; +} + +static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b) +{ + int i, result = 1; + + if (a->len != b->len) + goto out; + for (i=0; i < a->len; i++) { + if (tolower(a->name[i]) != tolower(b->name[i])) + goto out; + } + result = 0; + + /* + * We want creates to preserve case. A negative dentry, a, that + * has a different case than b may cause a new entry to be created + * with the wrong case. Since we can't tell if a comes from a negative + * dentry, we blindly replace it with b. This should be harmless if + * a is not a negative dentry. + */ + memcpy((unsigned char *)a->name, b->name, a->len); +out: + return result; +} + +struct dentry_operations jfs_ci_dentry_operations = +{ + .d_hash = jfs_ci_hash, + .d_compare = jfs_ci_compare, +}; --- linux-2.6.8-rc1/fs/jfs/super.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/jfs/super.c 2004-07-13 17:09:22.000000000 -0700 @@ -82,6 +82,8 @@ extern void jfs_write_inode(struct inode extern struct dentry *jfs_get_parent(struct dentry *dentry); extern int jfs_extendfs(struct super_block *, s64, int); +extern struct dentry_operations jfs_ci_dentry_operations; + #ifdef PROC_FS_JFS /* see jfs_debug.h */ extern void jfs_proc_init(void); extern void jfs_proc_clean(void); @@ -141,10 +143,13 @@ static void jfs_destroy_inode(struct ino { struct jfs_inode_info *ji = JFS_IP(inode); + spin_lock_irq(&ji->ag_lock); if (ji->active_ag != -1) { struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap; atomic_dec(&bmap->db_active[ji->active_ag]); + ji->active_ag = -1; } + spin_unlock_irq(&ji->ag_lock); #ifdef CONFIG_JFS_POSIX_ACL if (ji->i_acl != JFS_ACL_NOT_CACHED) { @@ -443,6 +448,9 @@ static int jfs_fill_super(struct super_b if (!sb->s_root) goto out_no_root; + if (sbi->mntflag & JFS_OS2) + sb->s_root->d_op = &jfs_ci_dentry_operations; + /* logical blocks are represented by 40 bits in pxd_t, etc. */ sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; #if BITS_PER_LONG == 32 @@ -559,6 +567,7 @@ static void init_once(void *foo, kmem_ca init_rwsem(&jfs_ip->rdwrlock); init_MUTEX(&jfs_ip->commit_sem); init_rwsem(&jfs_ip->xattr_sem); + spin_lock_init(&jfs_ip->ag_lock); jfs_ip->active_ag = -1; #ifdef CONFIG_JFS_POSIX_ACL jfs_ip->i_acl = JFS_ACL_NOT_CACHED; --- linux-2.6.8-rc1/fs/Kconfig 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/Kconfig 2004-07-13 17:35:10.000000000 -0700 @@ -552,7 +552,7 @@ endmenu menu "DOS/FAT/NT Filesystems" config FAT_FS - tristate "DOS FAT fs support" + tristate select NLS help If you want to use one of the FAT-based file systems (the MS-DOS, @@ -595,7 +595,7 @@ config FAT_FS config MSDOS_FS tristate "MSDOS fs support" - depends on FAT_FS + select FAT_FS help This allows you to mount MSDOS partitions of your hard drive (unless they are compressed; to access compressed MSDOS partitions under @@ -624,7 +624,7 @@ config MSDOS_FS config VFAT_FS tristate "VFAT (Windows-95) fs support" - depends on FAT_FS + select FAT_FS help This option provides support for normal Windows file systems with long filenames. That includes non-compressed FAT-based file systems --- linux-2.6.8-rc1/fs/lockd/clntlock.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/lockd/clntlock.c 2004-07-13 17:09:40.000000000 -0700 @@ -146,7 +146,7 @@ void nlmclnt_mark_reclaim(struct nlm_hos inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic != NFS_SUPER_MAGIC) continue; - if (fl->fl_u.nfs_fl.host != host) + if (fl->fl_u.nfs_fl.owner->host != host) continue; if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) continue; @@ -215,7 +215,7 @@ restart: inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic != NFS_SUPER_MAGIC) continue; - if (fl->fl_u.nfs_fl.host != host) + if (fl->fl_u.nfs_fl.owner->host != host) continue; if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM)) continue; --- linux-2.6.8-rc1/fs/lockd/clntproc.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/lockd/clntproc.c 2004-07-13 17:09:40.000000000 -0700 @@ -27,6 +27,7 @@ static int nlmclnt_unlock(struct nlm_rqs static void nlmclnt_unlock_callback(struct rpc_task *); static void nlmclnt_cancel_callback(struct rpc_task *); static int nlm_stat_to_errno(u32 stat); +static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); /* * Cookie counter for NLM requests @@ -41,11 +42,83 @@ static inline void nlmclnt_next_cookie(s nlm_cookie++; } +static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner) +{ + atomic_inc(&lockowner->count); + return lockowner; +} + +static void nlm_put_lockowner(struct nlm_lockowner *lockowner) +{ + if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock)) + return; + list_del(&lockowner->list); + spin_unlock(&lockowner->host->h_lock); + nlm_release_host(lockowner->host); + kfree(lockowner); +} + +static inline int nlm_pidbusy(struct nlm_host *host, uint32_t pid) +{ + struct nlm_lockowner *lockowner; + list_for_each_entry(lockowner, &host->h_lockowners, list) { + if (lockowner->pid == pid) + return -EBUSY; + } + return 0; +} + +static inline uint32_t __nlm_alloc_pid(struct nlm_host *host) +{ + uint32_t res; + do { + res = host->h_pidcount++; + } while (nlm_pidbusy(host, res) < 0); + return res; +} + +static struct nlm_lockowner *__nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner) +{ + struct nlm_lockowner *lockowner; + list_for_each_entry(lockowner, &host->h_lockowners, list) { + if (lockowner->owner != owner) + continue; + return nlm_get_lockowner(lockowner); + } + return NULL; +} + +static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_t owner) +{ + struct nlm_lockowner *res, *new = NULL; + + spin_lock(&host->h_lock); + res = __nlm_find_lockowner(host, owner); + if (res == NULL) { + spin_unlock(&host->h_lock); + new = (struct nlm_lockowner *)kmalloc(sizeof(*new), GFP_KERNEL); + spin_lock(&host->h_lock); + res = __nlm_find_lockowner(host, owner); + if (res == NULL && new != NULL) { + res = new; + atomic_set(&new->count, 1); + new->owner = owner; + new->pid = __nlm_alloc_pid(host); + new->host = nlm_get_host(host); + list_add(&new->list, &host->h_lockowners); + new = NULL; + } + } + spin_unlock(&host->h_lock); + if (new != NULL) + kfree(new); + return res; +} + /* * Initialize arguments for TEST/LOCK/UNLOCK/CANCEL calls */ -static inline void -nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) +static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; @@ -60,6 +133,14 @@ nlmclnt_setlockargs(struct nlm_rqst *req locks_copy_lock(&lock->fl, fl); } +static void nlmclnt_release_lockargs(struct nlm_rqst *req) +{ + struct file_lock *fl = &req->a_args.lock.fl; + + if (fl->fl_ops && fl->fl_ops->fl_release_private) + fl->fl_ops->fl_release_private(fl); +} + /* * Initialize arguments for GRANTED call. The nlm_rqst structure * has been cleared already. @@ -77,8 +158,10 @@ nlmclnt_setgrantargs(struct nlm_rqst *ca if (lock->oh.len > NLMCLNT_OHSIZE) { void *data = kmalloc(lock->oh.len, GFP_KERNEL); - if (!data) + if (!data) { + nlmclnt_freegrantargs(call); return 0; + } call->a_args.lock.oh.data = (u8 *) data; } @@ -89,12 +172,15 @@ nlmclnt_setgrantargs(struct nlm_rqst *ca void nlmclnt_freegrantargs(struct nlm_rqst *call) { + struct file_lock *fl = &call->a_args.lock.fl; /* * Check whether we allocated memory for the owner. */ if (call->a_args.lock.oh.data != (u8 *) call->a_owner) { kfree(call->a_args.lock.oh.data); } + if (fl->fl_ops && fl->fl_ops->fl_release_private) + fl->fl_ops->fl_release_private(fl); } /* @@ -165,6 +251,8 @@ nlmclnt_proc(struct inode *inode, int cm } call->a_host = host; + nlmclnt_locks_init_private(fl, host); + /* Set up the argument struct */ nlmclnt_setlockargs(call, fl); @@ -179,9 +267,6 @@ nlmclnt_proc(struct inode *inode, int cm else status = -EINVAL; - if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) - kfree(call); - out_restore: spin_lock_irqsave(¤t->sighand->siglock, flags); current->blocked = oldset; @@ -382,7 +467,9 @@ nlmclnt_test(struct nlm_rqst *req, struc { int status; - if ((status = nlmclnt_call(req, NLMPROC_TEST)) < 0) + status = nlmclnt_call(req, NLMPROC_TEST); + nlmclnt_release_lockargs(req); + if (status < 0) return status; status = req->a_res.status; @@ -391,10 +478,9 @@ nlmclnt_test(struct nlm_rqst *req, struc } if (status == NLM_LCK_DENIED) { /* * Report the conflicting lock back to the application. - * FIXME: Is it OK to report the pid back as well? */ locks_copy_lock(fl, &req->a_res.lock.fl); - /* fl->fl_pid = 0; */ + fl->fl_pid = 0; } else { return nlm_stat_to_errno(req->a_res.status); } @@ -402,18 +488,42 @@ nlmclnt_test(struct nlm_rqst *req, struc return 0; } -static -void nlmclnt_insert_lock_callback(struct file_lock *fl) +static int nlmclnt_locks_same_owner(struct file_lock *fl1, struct file_lock *fl2) { - nlm_get_host(fl->fl_u.nfs_fl.host); + return fl1->fl_u.nfs_fl.owner == fl2->fl_u.nfs_fl.owner; } -static -void nlmclnt_remove_lock_callback(struct file_lock *fl) + +static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) { - if (fl->fl_u.nfs_fl.host) { - nlm_release_host(fl->fl_u.nfs_fl.host); - fl->fl_u.nfs_fl.host = NULL; - } + memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl)); + nlm_get_lockowner(new->fl_u.nfs_fl.owner); +} + +static void nlmclnt_locks_release_private(struct file_lock *fl) +{ + nlm_put_lockowner(fl->fl_u.nfs_fl.owner); + fl->fl_ops = NULL; +} + +static void nlmclnt_steal_locks(struct file_lock *fl, fl_owner_t owner) +{ + locks_remove_posix(fl->fl_file, owner); +} + +static struct file_lock_operations nlmclnt_lock_ops = { + .fl_compare_owner = nlmclnt_locks_same_owner, + .fl_copy_lock = nlmclnt_locks_copy_lock, + .fl_release_private = nlmclnt_locks_release_private, + .fl_steal_locks = nlmclnt_steal_locks, +}; + +static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) +{ + BUG_ON(fl->fl_ops != NULL); + fl->fl_u.nfs_fl.state = 0; + fl->fl_u.nfs_fl.flags = 0; + fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); + fl->fl_ops = &nlmclnt_lock_ops; } /* @@ -446,7 +556,8 @@ nlmclnt_lock(struct nlm_rqst *req, struc if (!host->h_monitored && nsm_monitor(host) < 0) { printk(KERN_NOTICE "lockd: failed to monitor %s\n", host->h_name); - return -ENOLCK; + status = -ENOLCK; + goto out; } do { @@ -456,18 +567,17 @@ nlmclnt_lock(struct nlm_rqst *req, struc status = nlmclnt_block(host, fl, &resp->status); } if (status < 0) - return status; + goto out; } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); if (resp->status == NLM_LCK_GRANTED) { fl->fl_u.nfs_fl.state = host->h_state; fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED; - fl->fl_u.nfs_fl.host = host; - fl->fl_insert = nlmclnt_insert_lock_callback; - fl->fl_remove = nlmclnt_remove_lock_callback; } - - return nlm_stat_to_errno(resp->status); + status = nlm_stat_to_errno(resp->status); +out: + nlmclnt_release_lockargs(req); + return status; } /* @@ -527,11 +637,18 @@ nlmclnt_unlock(struct nlm_rqst *req, str fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; if (req->a_flags & RPC_TASK_ASYNC) { - return nlmclnt_async_call(req, NLMPROC_UNLOCK, + status = nlmclnt_async_call(req, NLMPROC_UNLOCK, nlmclnt_unlock_callback); + if (status < 0) { + nlmclnt_release_lockargs(req); + kfree(req); + } + return status; } - if ((status = nlmclnt_call(req, NLMPROC_UNLOCK)) < 0) + status = nlmclnt_call(req, NLMPROC_UNLOCK); + nlmclnt_release_lockargs(req); + if (status < 0) return status; if (resp->status == NLM_LCK_GRANTED) @@ -567,6 +684,7 @@ nlmclnt_unlock_callback(struct rpc_task die: nlm_release_host(req->a_host); + nlmclnt_release_lockargs(req); kfree(req); return; retry_rebind: @@ -605,8 +723,10 @@ nlmclnt_cancel(struct nlm_host *host, st status = nlmclnt_async_call(req, NLMPROC_CANCEL, nlmclnt_cancel_callback); - if (status < 0) + if (status < 0) { + nlmclnt_release_lockargs(req); kfree(req); + } spin_lock_irqsave(¤t->sighand->siglock, flags); current->blocked = oldset; @@ -648,6 +768,7 @@ nlmclnt_cancel_callback(struct rpc_task die: nlm_release_host(req->a_host); + nlmclnt_release_lockargs(req); kfree(req); return; --- linux-2.6.8-rc1/fs/lockd/host.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/lockd/host.c 2004-07-13 17:09:40.000000000 -0700 @@ -119,13 +119,15 @@ nlm_lookup_host(int server, struct socka init_MUTEX(&host->h_sema); host->h_nextrebind = jiffies + NLM_HOST_REBIND; host->h_expires = jiffies + NLM_HOST_EXPIRE; - host->h_count = 1; + atomic_set(&host->h_count, 1); init_waitqueue_head(&host->h_gracewait); host->h_state = 0; /* pseudo NSM state */ host->h_nsmstate = 0; /* real NSM state */ host->h_server = server; host->h_next = nlm_hosts[hash]; nlm_hosts[hash] = host; + INIT_LIST_HEAD(&host->h_lockowners); + spin_lock_init(&host->h_lock); if (++nrhosts > NLM_HOST_MAX) next_gc = 0; @@ -235,7 +237,7 @@ struct nlm_host * nlm_get_host(struct nl { if (host) { dprintk("lockd: get host %s\n", host->h_name); - host->h_count ++; + atomic_inc(&host->h_count); host->h_expires = jiffies + NLM_HOST_EXPIRE; } return host; @@ -246,9 +248,10 @@ struct nlm_host * nlm_get_host(struct nl */ void nlm_release_host(struct nlm_host *host) { - if (host && host->h_count) { + if (host != NULL) { dprintk("lockd: release host %s\n", host->h_name); - host->h_count --; + atomic_dec(&host->h_count); + BUG_ON(atomic_read(&host->h_count) < 0); } } @@ -283,7 +286,7 @@ nlm_shutdown_hosts(void) for (i = 0; i < NLM_HOST_NRHASH; i++) { for (host = nlm_hosts[i]; host; host = host->h_next) { dprintk(" %s (cnt %d use %d exp %ld)\n", - host->h_name, host->h_count, + host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); } } @@ -314,10 +317,10 @@ nlm_gc_hosts(void) for (i = 0; i < NLM_HOST_NRHASH; i++) { q = &nlm_hosts[i]; while ((host = *q) != NULL) { - if (host->h_count || host->h_inuse + if (atomic_read(&host->h_count) || host->h_inuse || time_before(jiffies, host->h_expires)) { dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", - host->h_name, host->h_count, + host->h_name, atomic_read(&host->h_count), host->h_inuse, host->h_expires); q = &host->h_next; continue; @@ -336,6 +339,7 @@ nlm_gc_hosts(void) rpc_destroy_client(host->h_rpcclnt); } } + BUG_ON(!list_empty(&host->h_lockowners)); kfree(host); nrhosts--; } --- linux-2.6.8-rc1/fs/lockd/svc4proc.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/fs/lockd/svc4proc.c 2004-07-13 17:09:40.000000000 -0700 @@ -55,6 +55,7 @@ nlm4svc_retrieve_args(struct svc_rqst *r /* Set up the missing parts of the file_lock structure */ lock->fl.fl_file = &file->f_file; lock->fl.fl_owner = (fl_owner_t) host; + lock->fl.fl_ops = &nlmsvc_lock_operations; } return 0; --- linux-2.6.8-rc1/fs/lockd/svclock.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/lockd/svclock.c 2004-07-13 17:09:40.000000000 -0700 @@ -194,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqs /* Set notifier function for VFS, and init args */ block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked; + block->b_call.a_args.lock.fl.fl_ops = &nlmsvc_lock_operations; block->b_call.a_args.cookie = *cookie; /* see above */ dprintk("lockd: created block %p...\n", block); @@ -479,6 +480,15 @@ nlmsvc_notify_blocked(struct file_lock * printk(KERN_WARNING "lockd: notification for unknown block!\n"); } +static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) +{ + return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; +} + +struct file_lock_operations nlmsvc_lock_operations = { + .fl_compare_owner = nlmsvc_same_owner, +}; + /* * Try to claim a lock that was previously blocked. * --- linux-2.6.8-rc1/fs/lockd/svcproc.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/fs/lockd/svcproc.c 2004-07-13 17:09:40.000000000 -0700 @@ -84,6 +84,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rq /* Set up the missing parts of the file_lock structure */ lock->fl.fl_file = &file->f_file; lock->fl.fl_owner = (fl_owner_t) host; + lock->fl.fl_ops = &nlmsvc_lock_operations; } return 0; --- linux-2.6.8-rc1/fs/lockd/xdr4.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/fs/lockd/xdr4.c 2004-07-13 17:09:13.000000000 -0700 @@ -191,7 +191,7 @@ nlm4_encode_testres(u32 *p, struct nlm_r dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; + return NULL; *p++ = resp->status; if (resp->status == nlm_lck_denied) { @@ -202,7 +202,7 @@ nlm4_encode_testres(u32 *p, struct nlm_r /* Encode owner handle. */ if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return 0; + return NULL; start = loff_t_to_s64(fl->fl_start); if (fl->fl_end == OFFSET_MAX) --- linux-2.6.8-rc1/fs/locks.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/locks.c 2004-07-13 17:09:39.000000000 -0700 @@ -167,6 +167,11 @@ static inline void locks_free_lock(struc if (!list_empty(&fl->fl_link)) panic("Attempting to free lock on active lock list"); + if (fl->fl_ops && fl->fl_ops->fl_release_private) { + fl->fl_ops->fl_release_private(fl); + fl->fl_ops = NULL; + } + kmem_cache_free(filelock_cache, fl); } @@ -186,6 +191,7 @@ void locks_init_lock(struct file_lock *f fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; } EXPORT_SYMBOL(locks_init_lock); @@ -220,7 +226,9 @@ void locks_copy_lock(struct file_lock *n new->fl_notify = fl->fl_notify; new->fl_insert = fl->fl_insert; new->fl_remove = fl->fl_remove; - new->fl_u = fl->fl_u; + new->fl_ops = fl->fl_ops; + if (fl->fl_ops && fl->fl_ops->fl_copy_lock) + fl->fl_ops->fl_copy_lock(new, fl); } EXPORT_SYMBOL(locks_copy_lock); @@ -324,6 +332,7 @@ static int flock_to_posix_lock(struct fi fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; return assign_type(fl, l->l_type); } @@ -364,6 +373,7 @@ static int flock64_to_posix_lock(struct fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; switch (l->l_type) { case F_RDLCK: @@ -400,6 +410,7 @@ static int lease_alloc(struct file *filp fl->fl_notify = NULL; fl->fl_insert = NULL; fl->fl_remove = NULL; + fl->fl_ops = NULL; *flp = fl; return 0; @@ -414,14 +425,15 @@ static inline int locks_overlap(struct f } /* - * Check whether two locks have the same owner. The apparently superfluous - * check for fl_pid enables us to distinguish between locks set by lockd. + * Check whether two locks have the same owner. */ static inline int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) { - return (fl1->fl_owner == fl2->fl_owner) && - (fl1->fl_pid == fl2->fl_pid); + if (fl1->fl_ops && fl1->fl_ops->fl_compare_owner) + return fl2->fl_ops == fl1->fl_ops && + fl1->fl_ops->fl_compare_owner(fl1, fl2); + return fl1->fl_owner == fl2->fl_owner; } /* Remove waiter from blocker's block list. @@ -631,24 +643,15 @@ int posix_locks_deadlock(struct file_loc struct file_lock *block_fl) { struct list_head *tmp; - fl_owner_t caller_owner, blocked_owner; - unsigned int caller_pid, blocked_pid; - - caller_owner = caller_fl->fl_owner; - caller_pid = caller_fl->fl_pid; - blocked_owner = block_fl->fl_owner; - blocked_pid = block_fl->fl_pid; next_task: - if (caller_owner == blocked_owner && caller_pid == blocked_pid) + if (posix_same_owner(caller_fl, block_fl)) return 1; list_for_each(tmp, &blocked_list) { struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - if ((fl->fl_owner == blocked_owner) - && (fl->fl_pid == blocked_pid)) { + if (IS_POSIX(fl) && posix_same_owner(fl, block_fl)) { fl = fl->fl_next; - blocked_owner = fl->fl_owner; - blocked_pid = fl->fl_pid; + block_fl = fl; goto next_task; } } @@ -988,6 +991,8 @@ int locks_mandatory_area(int read_write, break; } + if (fl.fl_ops && fl.fl_ops->fl_release_private) + fl.fl_ops->fl_release_private(&fl); return error; } @@ -1422,7 +1427,6 @@ int fcntl_getlk(struct file *filp, struc error = -EFAULT; if (!copy_to_user(l, &flock, sizeof(flock))) error = 0; - out: return error; } @@ -1672,6 +1676,7 @@ void locks_remove_posix(struct file *fil lock.fl_owner = owner; lock.fl_pid = current->tgid; lock.fl_file = filp; + lock.fl_ops = NULL; if (filp->f_op && filp->f_op->lock != NULL) { filp->f_op->lock(filp, F_SETLK, &lock); @@ -1684,13 +1689,15 @@ void locks_remove_posix(struct file *fil lock_kernel(); while (*before != NULL) { struct file_lock *fl = *before; - if (IS_POSIX(fl) && (fl->fl_owner == owner)) { + if (IS_POSIX(fl) && posix_same_owner(fl, &lock)) { locks_delete_lock(before); continue; } before = &fl->fl_next; } unlock_kernel(); + if (lock.fl_ops && lock.fl_ops->fl_release_private) + lock.fl_ops->fl_release_private(&lock); } EXPORT_SYMBOL(locks_remove_posix); @@ -1985,12 +1992,18 @@ EXPORT_SYMBOL(lock_may_write); static inline void __steal_locks(struct file *file, fl_owner_t from) { struct inode *inode = file->f_dentry->d_inode; - struct file_lock *fl = inode->i_flock; + struct file_lock *fl; - while (fl) { - if (fl->fl_file == file && fl->fl_owner == from) +restart: + for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (fl->fl_file == file && fl->fl_owner == from) { + if (fl->fl_ops && fl->fl_ops->fl_steal_locks) { + fl->fl_ops->fl_steal_locks(fl, from); + /* Some filesystems may just drop the lock */ + goto restart; + } fl->fl_owner = current->files; - fl = fl->fl_next; + } } } --- linux-2.6.8-rc1/fs/Makefile 2004-06-15 23:29:43.000000000 -0700 +++ 25/fs/Makefile 2004-07-13 17:09:45.000000000 -0700 @@ -91,3 +91,5 @@ obj-$(CONFIG_JFS_FS) += jfs/ obj-$(CONFIG_XFS_FS) += xfs/ obj-$(CONFIG_AFS_FS) += afs/ obj-$(CONFIG_BEFS_FS) += befs/ +obj-$(CONFIG_HOSTFS) += hostfs/ +obj-$(CONFIG_HPPFS) += hppfs/ --- linux-2.6.8-rc1/fs/minix/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/minix/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -453,7 +453,7 @@ static struct buffer_head * V1_minix_upd raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); if (!raw_inode) - return 0; + return NULL; raw_inode->i_mode = inode->i_mode; raw_inode->i_uid = fs_high2lowuid(inode->i_uid); raw_inode->i_gid = fs_high2lowgid(inode->i_gid); @@ -480,7 +480,7 @@ static struct buffer_head * V2_minix_upd raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); if (!raw_inode) - return 0; + return NULL; raw_inode->i_mode = inode->i_mode; raw_inode->i_uid = fs_high2lowuid(inode->i_uid); raw_inode->i_gid = fs_high2lowgid(inode->i_gid); --- linux-2.6.8-rc1/fs/namei.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/namei.c 2004-07-13 17:09:13.000000000 -0700 @@ -408,7 +408,61 @@ static struct dentry * real_lookup(struc return result; } -static int __vfs_follow_link(struct nameidata *, const char *); +static int __emul_lookup_dentry(const char *, struct nameidata *); + +/* SMP-safe */ +static inline int +walk_init_root(const char *name, struct nameidata *nd) +{ + read_lock(¤t->fs->lock); + if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { + nd->mnt = mntget(current->fs->altrootmnt); + nd->dentry = dget(current->fs->altroot); + read_unlock(¤t->fs->lock); + if (__emul_lookup_dentry(name,nd)) + return 0; + read_lock(¤t->fs->lock); + } + nd->mnt = mntget(current->fs->rootmnt); + nd->dentry = dget(current->fs->root); + read_unlock(¤t->fs->lock); + return 1; +} + +static inline int __vfs_follow_link(struct nameidata *nd, const char *link) +{ + int res = 0; + char *name; + if (IS_ERR(link)) + goto fail; + + if (*link == '/') { + path_release(nd); + if (!walk_init_root(link, nd)) + /* weird __emul_prefix() stuff did it */ + goto out; + } + res = link_path_walk(link, nd); +out: + if (nd->depth || res || nd->last_type!=LAST_NORM) + return res; + /* + * If it is an iterative symlinks resolution in open_namei() we + * have to copy the last component. And all that crap because of + * bloody create() on broken symlinks. Furrfu... + */ + name = __getname(); + if (unlikely(!name)) { + path_release(nd); + return -ENOMEM; + } + strcpy(name, nd->last.name); + nd->last.name = name; + return 0; +fail: + path_release(nd); + return PTR_ERR(link); +} /* * This limits recursive symlink follows to 8, while @@ -869,25 +923,6 @@ set_it: } } -/* SMP-safe */ -static inline int -walk_init_root(const char *name, struct nameidata *nd) -{ - read_lock(¤t->fs->lock); - if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { - nd->mnt = mntget(current->fs->altrootmnt); - nd->dentry = dget(current->fs->altroot); - read_unlock(¤t->fs->lock); - if (__emul_lookup_dentry(name,nd)) - return 0; - read_lock(¤t->fs->lock); - } - nd->mnt = mntget(current->fs->rootmnt); - nd->dentry = dget(current->fs->root); - read_unlock(¤t->fs->lock); - return 1; -} - int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) { int retval; @@ -2221,41 +2256,6 @@ int generic_readlink(struct dentry *dent return res; } -static int __vfs_follow_link(struct nameidata *nd, const char *link) -{ - int res = 0; - char *name; - if (IS_ERR(link)) - goto fail; - - if (*link == '/') { - path_release(nd); - if (!walk_init_root(link, nd)) - /* weird __emul_prefix() stuff did it */ - goto out; - } - res = link_path_walk(link, nd); -out: - if (nd->depth || res || nd->last_type!=LAST_NORM) - return res; - /* - * If it is an iterative symlinks resolution in open_namei() we - * have to copy the last component. And all that crap because of - * bloody create() on broken symlinks. Furrfu... - */ - name = __getname(); - if (unlikely(!name)) { - path_release(nd); - return -ENOMEM; - } - strcpy(name, nd->last.name); - nd->last.name = name; - return 0; -fail: - path_release(nd); - return PTR_ERR(link); -} - int vfs_follow_link(struct nameidata *nd, const char *link) { return __vfs_follow_link(nd, link); --- linux-2.6.8-rc1/fs/namespace.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/namespace.c 2004-07-13 17:35:09.000000000 -0700 @@ -832,14 +832,12 @@ EXPORT_SYMBOL_GPL(do_add_mount); void mark_mounts_for_expiry(struct list_head *mounts) { struct namespace *namespace; - struct list_head graveyard, *_p, *_n; - struct vfsmount *mnt; + struct vfsmount *mnt, *next; + LIST_HEAD(graveyard); if (list_empty(mounts)) return; - INIT_LIST_HEAD(&graveyard); - spin_lock(&vfsmount_lock); /* extract from the expiration list every vfsmount that matches the @@ -848,9 +846,7 @@ void mark_mounts_for_expiry(struct list_ * - still marked for expiry (marked on the last call here; marks are * cleared by mntput()) */ - list_for_each_safe(_p, _n, mounts) { - mnt = list_entry(_p, struct vfsmount, mnt_fslink); - + list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) { if (!xchg(&mnt->mnt_expiry_mark, 1) || atomic_read(&mnt->mnt_count) != 1) continue; @@ -913,8 +909,7 @@ void mark_mounts_for_expiry(struct list_ } mntput(mnt); - } - else { + } else { /* someone brought it back to life whilst we didn't * have any locks held so return it to the expiration * list */ --- linux-2.6.8-rc1/fs/nfsd/nfs4state.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/nfsd/nfs4state.c 2004-07-13 17:09:39.000000000 -0700 @@ -2180,6 +2180,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc goto out; } + locks_init_lock(&file_lock); switch (lock->lk_type) { case NFS4_READ_LT: case NFS4_READW_LT: @@ -2197,9 +2198,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struc file_lock.fl_pid = lockownerid_hashval(lock->lk_stateowner->so_id); file_lock.fl_file = filp; file_lock.fl_flags = FL_POSIX; - file_lock.fl_notify = NULL; - file_lock.fl_insert = NULL; - file_lock.fl_remove = NULL; file_lock.fl_start = lock->lk_offset; if ((lock->lk_length == ~(u64)0) || @@ -2215,6 +2213,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struc */ status = posix_lock_file(filp, &file_lock); + if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) + file_lock.fl_ops->fl_release_private(&file_lock); dprintk("NFSD: nfsd4_lock: posix_test_lock passed. posix_lock_file status %d\n",status); switch (-status) { case 0: /* success! */ @@ -2296,6 +2296,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru } inode = current_fh->fh_dentry->d_inode; + locks_init_lock(&file_lock); switch (lockt->lt_type) { case NFS4_READ_LT: case NFS4_READW_LT: @@ -2381,14 +2382,12 @@ nfsd4_locku(struct svc_rqst *rqstp, stru filp = &stp->st_vfs_file; BUG_ON(!filp); + locks_init_lock(&file_lock); file_lock.fl_type = F_UNLCK; file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner; file_lock.fl_pid = lockownerid_hashval(locku->lu_stateowner->so_id); file_lock.fl_file = filp; file_lock.fl_flags = FL_POSIX; - file_lock.fl_notify = NULL; - file_lock.fl_insert = NULL; - file_lock.fl_remove = NULL; file_lock.fl_start = locku->lu_offset; if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length)) @@ -2401,6 +2400,8 @@ nfsd4_locku(struct svc_rqst *rqstp, stru * Try to unlock the file in the VFS. */ status = posix_lock_file(filp, &file_lock); + if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) + file_lock.fl_ops->fl_release_private(&file_lock); if (status) { printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); goto out_nfserr; --- linux-2.6.8-rc1/fs/nfs/nfs4proc.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/nfs/nfs4proc.c 2004-07-13 17:09:13.000000000 -0700 @@ -387,7 +387,7 @@ retry: fattr->valid = 0; if (sattr->ia_valid & ATTR_SIZE) - nfs4_copy_stateid(&arg.stateid, state, 0); + nfs4_copy_stateid(&arg.stateid, state, NULL); else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); --- linux-2.6.8-rc1/fs/ntfs/ChangeLog 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/ChangeLog 2004-07-13 17:09:23.000000000 -0700 @@ -26,6 +26,14 @@ ToDo/Notes: - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.16 - WIP. + + - Add support for readv/writev and aio_read/aio_write (fs/ntfs/file.c). + This is done by setting the appropriate file operations pointers to + the generic helper functions provided by mm/filemap.c. + - Implement fsync, fdatasync, and msync both for files (fs/ntfs/file.c) + and directories (fs/ntfs/dir.c). + 2.1.15 - Invalidate quotas when (re)mounting read-write. - Add new element itype.index.collation_rule to the ntfs inode --- linux-2.6.8-rc1/fs/ntfs/dir.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/dir.c 2004-07-13 17:09:23.000000000 -0700 @@ -1495,10 +1495,69 @@ static int ntfs_dir_open(struct inode *v return 0; } +#ifdef NTFS_RW + +/** + * ntfs_dir_fsync - sync a directory to disk + * @filp: directory to be synced + * @dentry: dentry describing the directory to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a directory to disk. Used for fsync, fdatasync, and + * msync system calls. This function is based on file.c::ntfs_file_fsync(). + * + * Write the mft record and all associated extent mft records as well as the + * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device. + * + * If @datasync is true, we do not wait on the inode(s) to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. We do write the $BITMAP attribute if it is present + * which is the important one for a directory so things are not too bad. + */ +static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + ntfs_inode *ni = NTFS_I(vi); + int err, ret; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(!S_ISDIR(vi->i_mode)); + if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) + write_inode_now(ni->itype.index.bmp_ino, !datasync); + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_dir_ops = { .llseek = generic_file_llseek, /* Seek inside directory. */ .read = generic_read_dir, /* Return -EISDIR. */ .readdir = ntfs_readdir, /* Read directory contents. */ +#ifdef NTFS_RW + .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ .open = ntfs_dir_open, /* Open directory. */ }; - --- linux-2.6.8-rc1/fs/ntfs/file.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/ntfs/file.c 2004-07-13 17:09:23.000000000 -0700 @@ -48,26 +48,101 @@ static int ntfs_file_open(struct inode * return generic_file_open(vi, filp); } +#ifdef NTFS_RW + +/** + * ntfs_file_fsync - sync a file to disk + * @filp: file to be synced + * @dentry: dentry describing the file to sync + * @datasync: if non-zero only flush user data and not metadata + * + * Data integrity sync of a file to disk. Used for fsync, fdatasync, and msync + * system calls. This function is inspired by fs/buffer.c::file_fsync(). + * + * If @datasync is false, write the mft record and all associated extent mft + * records as well as the $DATA attribute and then sync the block device. + * + * If @datasync is true and the attribute is non-resident, we skip the writing + * of the mft record and all associated extent mft records (this might still + * happen due to the write_inode_now() call). + * + * Also, if @datasync is true, we do not wait on the inode to be written out + * but we always wait on the page cache pages to be written out. + * + * Note: In the past @filp could be NULL so we ignore it as we don't need it + * anyway. + * + * Locking: Caller must hold i_sem on the inode. + * + * TODO: We should probably also write all attribute/index inodes associated + * with this inode but since we have no simple way of getting to them we ignore + * this problem for now. + */ +static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +{ + struct inode *vi = dentry->d_inode; + int err, ret = 0; + + ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); + BUG_ON(S_ISDIR(vi->i_mode)); + if (!datasync || !NInoNonResident(NTFS_I(vi))) + ret = ntfs_write_inode(vi, 1); + write_inode_now(vi, !datasync); + err = sync_blockdev(vi->i_sb->s_bdev); + if (unlikely(err && !ret)) + ret = err; + if (likely(!ret)) + ntfs_debug("Done."); + else + ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " + "%u.", datasync ? "data" : "", vi->i_ino, -ret); + return ret; +} + +#endif /* NTFS_RW */ + struct file_operations ntfs_file_ops = { - .llseek = generic_file_llseek, /* Seek inside file. */ - .read = generic_file_read, /* Read from file. */ + .llseek = generic_file_llseek, /* Seek inside file. */ + .read = generic_file_read, /* Read from file. */ + .aio_read = generic_file_aio_read, /* Async read from file. */ + .readv = generic_file_readv, /* Read from file. */ #ifdef NTFS_RW - .write = generic_file_write, /* Write to a file. */ -#endif - .mmap = generic_file_mmap, /* Mmap file. */ - .sendfile = generic_file_sendfile,/* Zero-copy data send with the - data source being on the - ntfs partition. We don't - need to care about the data - destination. */ - .open = ntfs_file_open, /* Open file. */ + .write = generic_file_write, /* Write to file. */ + .aio_write = generic_file_aio_write, /* Async write to file. */ + .writev = generic_file_writev, /* Write to file. */ + /*.release = ,*/ /* Last file is closed. See + fs/ext2/file.c:: + ext2_release_file() for + how to use this to discard + preallocated space for + write opened files. */ + .fsync = ntfs_file_fsync, /* Sync a file to disk. */ + /*.aio_fsync = ,*/ /* Sync all outstanding async + i/o operations on a + kiocb. */ +#endif /* NTFS_RW */ + /*.ioctl = ,*/ /* Perform function on the + mounted filesystem. */ + .mmap = generic_file_mmap, /* Mmap file. */ + .open = ntfs_file_open, /* Open file. */ + .sendfile = generic_file_sendfile, /* Zero-copy data send with + the data source being on + the ntfs partition. We + do not need to care about + the data destination. */ + /*.sendpage = ,*/ /* Zero-copy data send with + the data destination being + on the ntfs partition. We + do not need to care about + the data source. */ }; struct inode_operations ntfs_file_inode_ops = { #ifdef NTFS_RW .truncate = ntfs_truncate, .setattr = ntfs_setattr, -#endif +#endif /* NTFS_RW */ }; struct file_operations ntfs_empty_file_ops = {}; --- linux-2.6.8-rc1/fs/ntfs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/inode.c 2004-07-13 17:09:23.000000000 -0700 @@ -2314,8 +2314,10 @@ trunc_err: * marking the page (and in this case mft record) dirty but we do not implement * this yet as write_mft_record() largely ignores the @sync parameter and * always performs synchronous writes. + * + * Return 0 on success and -errno on error. */ -void ntfs_write_inode(struct inode *vi, int sync) +int ntfs_write_inode(struct inode *vi, int sync) { ntfs_inode *ni = NTFS_I(vi); #if 0 @@ -2332,7 +2334,7 @@ void ntfs_write_inode(struct inode *vi, */ if (NInoAttr(ni)) { NInoClearDirty(ni); - return; + return 0; } /* Map, pin, and lock the mft record belonging to the inode. */ m = map_mft_record(ni); @@ -2410,7 +2412,7 @@ void ntfs_write_inode(struct inode *vi, if (unlikely(err)) goto err_out; ntfs_debug("Done."); - return; + return 0; #if 0 unm_err_out: unmap_mft_record(ni); @@ -2426,7 +2428,31 @@ err_out: "as bad. You should run chkdsk.", -err); make_bad_inode(vi); } - return; + return err; +} + +/** + * ntfs_write_inode_vfs - write out a dirty inode + * @vi: inode to write out + * @sync: if true, write out synchronously + * + * Write out a dirty inode to disk including any extent inodes if present. + * + * If @sync is true, commit the inode to disk and wait for io completion. This + * is done using write_mft_record(). + * + * If @sync is false, just schedule the write to happen but do not wait for i/o + * completion. In 2.6 kernels, scheduling usually happens just by virtue of + * marking the page (and in this case mft record) dirty but we do not implement + * this yet as write_mft_record() largely ignores the @sync parameter and + * always performs synchronous writes. + * + * This functions does not have a return value which is the required behaviour + * for the VFS super_operations ->dirty_inode function. + */ +void ntfs_write_inode_vfs(struct inode *vi, int sync) +{ + ntfs_write_inode(vi, sync); } #endif /* NTFS_RW */ --- linux-2.6.8-rc1/fs/ntfs/inode.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/inode.h 2004-07-13 17:09:23.000000000 -0700 @@ -285,7 +285,8 @@ extern void ntfs_truncate(struct inode * extern int ntfs_setattr(struct dentry *dentry, struct iattr *attr); -extern void ntfs_write_inode(struct inode *vi, int sync); +extern int ntfs_write_inode(struct inode *vi, int sync); +extern void ntfs_write_inode_vfs(struct inode *vi, int sync); static inline void ntfs_commit_inode(struct inode *vi) { --- linux-2.6.8-rc1/fs/ntfs/Makefile 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/Makefile 2004-07-13 17:09:23.000000000 -0700 @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o c index.o inode.o mft.o mst.o namei.o super.o sysctl.o unistr.o \ upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.15\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.16-WIP\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG --- linux-2.6.8-rc1/fs/ntfs/super.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/ntfs/super.c 2004-07-13 17:09:23.000000000 -0700 @@ -2050,7 +2050,7 @@ struct super_operations ntfs_sops = { #ifdef NTFS_RW //.dirty_inode = NULL, /* VFS: Called from // __mark_inode_dirty(). */ - .write_inode = ntfs_write_inode, /* VFS: Write dirty inode to + .write_inode = ntfs_write_inode_vfs, /* VFS: Write dirty inode to disk. */ //.drop_inode = NULL, /* VFS: Called just after the // inode reference count has --- linux-2.6.8-rc1/fs/proc/base.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/proc/base.c 2004-07-13 17:09:51.000000000 -0700 @@ -1526,6 +1526,7 @@ struct dentry *proc_pid_unhash(struct ta void proc_pid_flush(struct dentry *proc_dentry) { + might_sleep(); if(proc_dentry != NULL) { shrink_dcache_parent(proc_dentry); dput(proc_dentry); --- linux-2.6.8-rc1/fs/proc/proc_misc.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/proc/proc_misc.c 2004-07-13 17:09:29.000000000 -0700 @@ -637,6 +637,36 @@ static void create_seq_entry(char *name, entry->proc_fops = f; } +#ifdef CONFIG_LOCKMETER +extern ssize_t get_lockmeter_info(char *, size_t, loff_t *); +extern ssize_t put_lockmeter_info(const char *, size_t); +extern int get_lockmeter_info_size(void); + +/* + * This function accesses lock metering information. + */ +static ssize_t read_lockmeter(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return get_lockmeter_info(buf, count, ppos); +} + +/* + * Writing to /proc/lockmeter resets the counters + */ +static ssize_t write_lockmeter(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return put_lockmeter_info(buf, count); +} + +static struct file_operations proc_lockmeter_operations = { + NULL, /* lseek */ + read: read_lockmeter, + write: write_lockmeter, +}; +#endif /* CONFIG_LOCKMETER */ + void __init proc_misc_init(void) { struct proc_dir_entry *entry; @@ -701,6 +731,13 @@ void __init proc_misc_init(void) if (entry) entry->proc_fops = &proc_sysrq_trigger_operations; #endif +#ifdef CONFIG_LOCKMETER + entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL); + if (entry) { + entry->proc_fops = &proc_lockmeter_operations; + entry->size = get_lockmeter_info_size(); + } +#endif #ifdef CONFIG_PPC32 { extern struct file_operations ppc_htab_operations; --- linux-2.6.8-rc1/fs/qnx4/inode.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/qnx4/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -232,8 +232,8 @@ unsigned long qnx4_block_map( struct ino int ix; long offset, i_xblk; unsigned long block = 0; - struct buffer_head *bh = 0; - struct qnx4_xblk *xblk = 0; + struct buffer_head *bh = NULL; + struct qnx4_xblk *xblk = NULL; struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); @@ -269,7 +269,7 @@ unsigned long qnx4_block_map( struct ino i_xblk = le32_to_cpu(xblk->xblk_next_xblk); ix = 0; brelse( bh ); - bh = 0; + bh = NULL; } } if ( bh ) --- linux-2.6.8-rc1/fs/reiserfs/do_balan.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/do_balan.c 2004-07-13 17:09:13.000000000 -0700 @@ -169,8 +169,8 @@ static int balance_leaf_when_delete (str if ( PATH_H_POSITION (tb->tb_path, 1) == 0 && 1 < B_NR_ITEMS(tb->FR[0]) ) replace_key(tb, tb->CFL[0],tb->lkey[0],tb->FR[0],1); - leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, 0); - leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, 0); + leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, NULL); + leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, NULL); reiserfs_invalidate_buffer (tb, tbS0); reiserfs_invalidate_buffer (tb, tb->R[0]); @@ -178,8 +178,8 @@ static int balance_leaf_when_delete (str return 0; } /* all contents of all the 3 buffers will be in R[0] */ - leaf_move_items (LEAF_FROM_S_TO_R, tb, n, -1, 0); - leaf_move_items (LEAF_FROM_L_TO_R, tb, B_NR_ITEMS(tb->L[0]), -1, 0); + leaf_move_items (LEAF_FROM_S_TO_R, tb, n, -1, NULL); + leaf_move_items (LEAF_FROM_L_TO_R, tb, B_NR_ITEMS(tb->L[0]), -1, NULL); /* right_delimiting_key is correct in R[0] */ replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0); @@ -854,7 +854,7 @@ static int balance_leaf (struct tree_bal /* Insert part of the item into S_new[i] before 0-th item */ bi.tb = tb; bi.bi_bh = S_new[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; if ( (old_len - sbytes[i]) > zeros_num ) { @@ -882,7 +882,7 @@ static int balance_leaf (struct tree_bal /* Insert new item into S_new[i] */ bi.tb = tb; bi.bi_bh = S_new[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; leaf_insert_into_buf (&bi, item_pos - n + snum[i] - 1, ih, body, zeros_num); @@ -927,7 +927,7 @@ static int balance_leaf (struct tree_bal /* Paste given directory entry to directory item */ bi.tb = tb; bi.bi_bh = S_new[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; leaf_paste_in_buffer (&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, tb->insert_size[0], body,zeros_num); @@ -965,7 +965,7 @@ static int balance_leaf (struct tree_bal /* Append part of body into S_new[0] */ bi.tb = tb; bi.bi_bh = S_new[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; if ( n_rem > zeros_num ) { @@ -1021,7 +1021,7 @@ static int balance_leaf (struct tree_bal /* paste into item */ bi.tb = tb; bi.bi_bh = S_new[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; leaf_paste_in_buffer(&bi, item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_num); @@ -1196,11 +1196,11 @@ struct buffer_head * get_FEB (struct tre bi.tb = tb; bi.bi_bh = first_b = tb->FEB[i]; - bi.bi_parent = 0; + bi.bi_parent = NULL; bi.bi_position = 0; make_empty_node (&bi); set_buffer_uptodate(first_b); - tb->FEB[i] = 0; + tb->FEB[i] = NULL; tb->used[i] = first_b; return(first_b); --- linux-2.6.8-rc1/fs/reiserfs/file.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/file.c 2004-07-13 17:09:31.000000000 -0700 @@ -89,15 +89,16 @@ static int reiserfs_sync_file( ) { struct inode * p_s_inode = p_s_dentry->d_inode; int n_err; - - reiserfs_write_lock(p_s_inode->i_sb); + int barrier_done; if (!S_ISREG(p_s_inode->i_mode)) BUG (); - n_err = sync_mapping_buffers(p_s_inode->i_mapping) ; - reiserfs_commit_for_inode(p_s_inode) ; + reiserfs_write_lock(p_s_inode->i_sb); + barrier_done = reiserfs_commit_for_inode(p_s_inode); reiserfs_write_unlock(p_s_inode->i_sb); + if (barrier_done != 1) + blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL); return ( n_err < 0 ) ? -EIO : 0; } @@ -832,7 +833,7 @@ int reiserfs_prepare_file_region_for_wri struct item_head *ih = NULL; // pointer to item head that we are going to deal with struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. - __u32 * item=0; // pointer to item we are going to deal with + __u32 * item=NULL; // pointer to item we are going to deal with int item_pos=-1; /* Position in indirect item */ --- linux-2.6.8-rc1/fs/reiserfs/fix_node.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/fix_node.c 2004-07-13 17:09:13.000000000 -0700 @@ -2445,12 +2445,12 @@ int fix_nodes (int n_op_mode, reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->CFR[i]); } - brelse (p_s_tb->L[i]);p_s_tb->L[i] = 0; - brelse (p_s_tb->R[i]);p_s_tb->R[i] = 0; - brelse (p_s_tb->FL[i]);p_s_tb->FL[i] = 0; - brelse (p_s_tb->FR[i]);p_s_tb->FR[i] = 0; - brelse (p_s_tb->CFL[i]);p_s_tb->CFL[i] = 0; - brelse (p_s_tb->CFR[i]);p_s_tb->CFR[i] = 0; + brelse (p_s_tb->L[i]);p_s_tb->L[i] = NULL; + brelse (p_s_tb->R[i]);p_s_tb->R[i] = NULL; + brelse (p_s_tb->FL[i]);p_s_tb->FL[i] = NULL; + brelse (p_s_tb->FR[i]);p_s_tb->FR[i] = NULL; + brelse (p_s_tb->CFL[i]);p_s_tb->CFL[i] = NULL; + brelse (p_s_tb->CFR[i]);p_s_tb->CFR[i] = NULL; } if (wait_tb_buffers_run) { --- linux-2.6.8-rc1/fs/reiserfs/ibalance.c 2004-05-09 21:07:25.000000000 -0700 +++ 25/fs/reiserfs/ibalance.c 2004-07-13 17:09:13.000000000 -0700 @@ -922,7 +922,7 @@ int balance_internal (struct tree_balanc if ( tb->blknum[h] != 1 ) - reiserfs_panic(0, "balance_internal: One new node required for creating the new root"); + reiserfs_panic(NULL, "balance_internal: One new node required for creating the new root"); /* S[h] = empty buffer from the list FEB. */ tbSh = get_FEB (tb); blkh = B_BLK_HEAD(tbSh); @@ -964,7 +964,7 @@ int balance_internal (struct tree_balanc dest_bi.tb = tb; dest_bi.bi_bh = S_new; - dest_bi.bi_parent = 0; + dest_bi.bi_parent = NULL; dest_bi.bi_position = 0; src_bi.tb = tb; src_bi.bi_bh = tbSh; --- linux-2.6.8-rc1/fs/reiserfs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -556,7 +556,7 @@ int reiserfs_get_block (struct inode * i INITIALIZE_PATH(path); int pos_in_item; struct cpu_key key; - struct buffer_head * bh, * unbh = 0; + struct buffer_head * bh, * unbh = NULL; struct item_head * ih, tmp_ih; __u32 * item; int done; @@ -1394,7 +1394,7 @@ struct inode * reiserfs_iget (struct sup if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) { /* either due to i/o error or a stale NFS handle */ iput (inode); - inode = 0; + inode = NULL; } return inode; } @@ -1558,13 +1558,13 @@ static int reiserfs_new_directory (struc old type (ITEM_VERSION_1). Do not set key (second arg is 0), it is done by reiserfs_new_inode */ if (old_format_only (sb)) { - make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); + make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, INODE_PKEY (dir)->k_dir_id, INODE_PKEY (dir)->k_objectid ); } else { - make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); + make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, INODE_PKEY (dir)->k_dir_id, @@ -1606,7 +1606,7 @@ static int reiserfs_new_symlink (struct le32_to_cpu (ih->ih_key.k_objectid), 1, TYPE_DIRECT, 3/*key length*/); - make_le_item_head (ih, 0, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/); + make_le_item_head (ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/); /* look for place in the tree for new item */ retval = search_item (sb, &key, path); @@ -1701,7 +1701,7 @@ int reiserfs_new_inode (struct reiserfs_ 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_jl = 0; + REISERFS_I(inode)->i_jl = NULL; REISERFS_I(inode)->i_attrs = REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode ); @@ -1710,9 +1710,9 @@ int reiserfs_new_inode (struct reiserfs_ init_rwsem (&REISERFS_I(inode)->xattr_sem); if (old_format_only (sb)) - make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); + make_le_item_head (&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); else - make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); + make_le_item_head (&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); /* key to search for correct place for new stat data */ _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id), --- linux-2.6.8-rc1/fs/reiserfs/item_ops.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/item_ops.c 2004-07-13 17:09:13.000000000 -0700 @@ -549,7 +549,7 @@ static int direntry_create_vi (struct vi if (l + IH_SIZE != vi->vi_item_len + ((is_affected && (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)) ? insert_size : 0) ) { - reiserfs_panic (0, "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item", + reiserfs_panic (NULL, "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item", vn->vn_mode, insert_size); } } --- linux-2.6.8-rc1/fs/reiserfs/journal.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/journal.c 2004-07-13 17:09:33.000000000 -0700 @@ -127,6 +127,12 @@ static int reiserfs_clean_and_file_buffe return 0 ; } +static void disable_barrier(struct super_block *s) +{ + REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH); + printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s)); +} + static struct reiserfs_bitmap_node * allocate_bitmap_node(struct super_block *p_s_sb) { struct reiserfs_bitmap_node *bn ; @@ -640,6 +646,26 @@ static void submit_ordered_buffer(struct submit_bh(WRITE, bh) ; } +static int submit_barrier_buffer(struct buffer_head *bh) { + get_bh(bh) ; + bh->b_end_io = reiserfs_end_ordered_io; + clear_buffer_dirty(bh) ; + if (!buffer_uptodate(bh)) + BUG(); + return submit_bh(WRITE_BARRIER, bh) ; +} + +static void check_barrier_completion(struct super_block *s, + struct buffer_head *bh) { + if (buffer_eopnotsupp(bh)) { + clear_buffer_eopnotsupp(bh); + disable_barrier(s); + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + sync_dirty_buffer(bh); + } +} + #define CHUNK_SIZE 32 struct buffer_chunk { struct buffer_head *bh[CHUNK_SIZE]; @@ -909,6 +935,7 @@ static int flush_commit_list(struct supe int bn ; struct buffer_head *tbh = NULL ; unsigned long trans_id = jl->j_trans_id; + int barrier = 0; reiserfs_check_lock_depth(s, "flush_commit_list") ; @@ -973,7 +1000,20 @@ static int flush_commit_list(struct supe } atomic_dec(&SB_JOURNAL(s)->j_async_throttle); - /* wait on everything written so far before writing the commit */ + /* wait on everything written so far before writing the commit + * if we are in barrier mode, send the commit down now + */ + barrier = reiserfs_barrier_flush(s); + if (barrier) { + int ret; + lock_buffer(jl->j_commit_bh); + ret = submit_barrier_buffer(jl->j_commit_bh); + if (ret == -EOPNOTSUPP) { + set_buffer_uptodate(jl->j_commit_bh); + disable_barrier(s); + barrier = 0; + } + } for (i = 0 ; i < (jl->j_len + 1) ; i++) { bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ; @@ -995,10 +1035,15 @@ static int flush_commit_list(struct supe if (atomic_read(&(jl->j_commit_left)) != 1) BUG(); - if (buffer_dirty(jl->j_commit_bh)) - BUG(); - mark_buffer_dirty(jl->j_commit_bh) ; - sync_dirty_buffer(jl->j_commit_bh) ; + if (!barrier) { + if (buffer_dirty(jl->j_commit_bh)) + BUG(); + mark_buffer_dirty(jl->j_commit_bh) ; + sync_dirty_buffer(jl->j_commit_bh) ; + } else + wait_on_buffer(jl->j_commit_bh); + + check_barrier_completion(s, jl->j_commit_bh); if (!buffer_uptodate(jl->j_commit_bh)) { reiserfs_panic(s, "journal-615: buffer write failed\n") ; } @@ -1098,8 +1143,23 @@ static int _update_journal_header_block( jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ; jh->j_first_unflushed_offset = cpu_to_le32(offset) ; jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ; - set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ; - sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ; + + if (reiserfs_barrier_flush(p_s_sb)) { + int ret; + lock_buffer(SB_JOURNAL(p_s_sb)->j_header_bh); + ret = submit_barrier_buffer(SB_JOURNAL(p_s_sb)->j_header_bh); + if (ret == -EOPNOTSUPP) { + set_buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh); + disable_barrier(p_s_sb); + goto sync; + } + wait_on_buffer(SB_JOURNAL(p_s_sb)->j_header_bh); + check_barrier_completion(p_s_sb, SB_JOURNAL(p_s_sb)->j_header_bh); + } else { +sync: + set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ; + sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ; + } if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) { reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay"); return -EIO ; @@ -3184,11 +3244,16 @@ void reiserfs_update_inode_transaction(s REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ; } -static void __commit_trans_jl(struct inode *inode, unsigned long id, +/* + * returns -1 on error, 0 if no commits/barriers were done and 1 + * if a transaction was actually committed and the barrier was done + */ +static int __commit_trans_jl(struct inode *inode, unsigned long id, struct reiserfs_journal_list *jl) { struct reiserfs_transaction_handle th ; struct super_block *sb = inode->i_sb ; + int ret = 0; /* is it from the current transaction, or from an unknown transaction? */ if (id == SB_JOURNAL(sb)->j_trans_id) { @@ -3210,6 +3275,7 @@ static void __commit_trans_jl(struct ino } journal_end_sync(&th, sb, 1) ; + ret = 1; } else { /* this gets tricky, we have to make sure the journal list in @@ -3218,13 +3284,21 @@ static void __commit_trans_jl(struct ino */ flush_commit_only: if (journal_list_still_alive(inode->i_sb, id)) { + /* + * we only set ret to 1 when we know for sure + * the barrier hasn't been started yet on the commit + * block. + */ + if (atomic_read(&jl->j_commit_left) > 1) + ret = 1; flush_commit_list(sb, jl, 1) ; } } /* otherwise the list is gone, and long since committed */ + return ret; } -void reiserfs_commit_for_inode(struct inode *inode) { +int reiserfs_commit_for_inode(struct inode *inode) { unsigned long id = REISERFS_I(inode)->i_trans_id; struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl; @@ -3237,7 +3311,7 @@ void reiserfs_commit_for_inode(struct in /* jl will be updated in __commit_trans_jl */ } - __commit_trans_jl(inode, id, jl); + return __commit_trans_jl(inode, id, jl); } void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, --- linux-2.6.8-rc1/fs/reiserfs/lbalance.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/lbalance.c 2004-07-13 17:09:13.000000000 -0700 @@ -49,7 +49,7 @@ static void leaf_copy_dir_entries (struc deh_location( &(deh[from + copy_count - 1])); } else { copy_records_len = 0; - records = 0; + records = NULL; } /* when copy last to first, dest buffer can contain 0 items */ @@ -145,7 +145,7 @@ static int leaf_copy_boundary_item (stru else { if (bytes_or_entries == ih_item_len(ih) && is_indirect_le_ih(ih)) if (get_ih_free_space (ih)) - reiserfs_panic (0, "vs-10020: leaf_copy_boundary_item: " + reiserfs_panic (NULL, "vs-10020: leaf_copy_boundary_item: " "last unformatted node must be filled entirely (%h)", ih); } @@ -552,13 +552,13 @@ static void leaf_define_dest_src_infos ( src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0); dest_bi->tb = tb; dest_bi->bi_bh = Snew; - dest_bi->bi_parent = 0; + dest_bi->bi_parent = NULL; dest_bi->bi_position = 0; *first_last = LAST_TO_FIRST; break; default: - reiserfs_panic (0, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode); + reiserfs_panic (NULL, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode); } RFALSE( src_bi->bi_bh == 0 || dest_bi->bi_bh == 0, "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly", @@ -595,7 +595,7 @@ int leaf_shift_left (struct tree_balance int i; /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */ - i = leaf_move_items (LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, 0); + i = leaf_move_items (LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, NULL); if ( shift_num ) { if (B_NR_ITEMS (S0) == 0) { /* number of items in S[0] == 0 */ @@ -648,7 +648,7 @@ int leaf_shift_right( int ret_value; /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */ - ret_value = leaf_move_items (LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, 0); + ret_value = leaf_move_items (LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, NULL); /* replace rkey in CFR[0] by the 0-th key from R[0] */ if (shift_num) { @@ -829,7 +829,7 @@ void leaf_paste_in_buffer (struct buffer #ifdef CONFIG_REISERFS_CHECK if (zeros_number > paste_size) { print_cur_tb ("10177"); - reiserfs_panic ( 0, "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d", + reiserfs_panic ( NULL, "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d", zeros_number, paste_size); } #endif /* CONFIG_REISERFS_CHECK */ --- linux-2.6.8-rc1/fs/reiserfs/namei.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/namei.c 2004-07-13 17:09:13.000000000 -0700 @@ -331,7 +331,7 @@ static struct dentry * reiserfs_lookup ( return ERR_PTR(-ENAMETOOLONG); reiserfs_write_lock(dir->i_sb); - de.de_gen_number_bit_string = 0; + de.de_gen_number_bit_string = NULL; retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path_to_entry, &de); pathrelse (&path_to_entry); if (retval == NAME_FOUND) { @@ -384,7 +384,7 @@ struct dentry *reiserfs_get_parent(struc if (dir->i_nlink == 0) { return ERR_PTR(-ENOENT); } - de.de_gen_number_bit_string = 0; + de.de_gen_number_bit_string = NULL; reiserfs_write_lock(dir->i_sb); retval = reiserfs_find_entry (dir, "..", 2, &path_to_entry, &de); @@ -607,7 +607,7 @@ static int reiserfs_create (struct inode reiserfs_write_lock_xattrs (dir->i_sb); journal_begin(&th, dir->i_sb, jbegin_count) ; - retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode); + retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode); if (locked) reiserfs_write_unlock_xattrs (dir->i_sb); @@ -668,7 +668,7 @@ static int reiserfs_mknod (struct inode journal_begin(&th, dir->i_sb, jbegin_count) ; - retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode); + retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode); if (locked) reiserfs_write_unlock_xattrs (dir->i_sb); @@ -737,7 +737,7 @@ static int reiserfs_mkdir (struct inode */ INC_DIR_INODE_NLINK(dir) - retval = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/, + retval = reiserfs_new_inode (&th, dir, mode, NULL/*symlink*/, old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE, dentry, inode); @@ -805,7 +805,7 @@ static int reiserfs_rmdir (struct inode reiserfs_write_lock(dir->i_sb); journal_begin(&th, dir->i_sb, jbegin_count) ; - de.de_gen_number_bit_string = 0; + de.de_gen_number_bit_string = NULL; if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) { retval = -ENOENT; goto end_rmdir; @@ -886,7 +886,7 @@ static int reiserfs_unlink (struct inode reiserfs_write_lock(dir->i_sb); journal_begin(&th, dir->i_sb, jbegin_count) ; - de.de_gen_number_bit_string = 0; + de.de_gen_number_bit_string = NULL; if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) { retval = -ENOENT; goto end_unlink; @@ -1093,13 +1093,13 @@ static int entry_points_to_object (const if (inode) { if (!de_visible (de->de_deh + de->de_entry_num)) - reiserfs_panic (0, "vs-7042: entry_points_to_object: entry must be visible"); + reiserfs_panic (NULL, "vs-7042: entry_points_to_object: entry must be visible"); return (de->de_objectid == inode->i_ino) ? 1 : 0; } /* this must be added hidden entry */ if (de_visible (de->de_deh + de->de_entry_num)) - reiserfs_panic (0, "vs-7043: entry_points_to_object: entry must be visible"); + reiserfs_panic (NULL, "vs-7043: entry_points_to_object: entry must be visible"); return 1; } @@ -1149,7 +1149,7 @@ static int reiserfs_rename (struct inode // make sure, that oldname still exists and points to an object we // are going to rename - old_de.de_gen_number_bit_string = 0; + old_de.de_gen_number_bit_string = NULL; reiserfs_write_lock(old_dir->i_sb); retval = reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_entry_path, &old_de); @@ -1180,7 +1180,7 @@ static int reiserfs_rename (struct inode /* directory is renamed, its parent directory will be changed, ** so find ".." entry */ - dot_dot_de.de_gen_number_bit_string = 0; + dot_dot_de.de_gen_number_bit_string = NULL; retval = reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de); pathrelse (&dot_dot_entry_path); if (retval != NAME_FOUND) { @@ -1232,7 +1232,7 @@ static int reiserfs_rename (struct inode reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1) ; // look for new name by reiserfs_find_entry - new_de.de_gen_number_bit_string = 0; + new_de.de_gen_number_bit_string = NULL; retval = reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_entry_path, &new_de); // reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from --- linux-2.6.8-rc1/fs/reiserfs/prints.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/prints.c 2004-07-13 17:09:13.000000000 -0700 @@ -631,8 +631,8 @@ void store_print_tb (struct tree_balance tbSh = PATH_H_PBUFFER (tb->tb_path, h); tbFh = PATH_H_PPARENT (tb->tb_path, h); } else { - tbSh = 0; - tbFh = 0; + tbSh = NULL; + tbFh = NULL; } sprintf (print_tb_buf + strlen (print_tb_buf), "* %d * %3lld(%2d) * %3lld(%2d) * %3lld(%2d) * %5lld * %5lld * %5lld * %5lld * %5lld *\n", @@ -695,10 +695,10 @@ static void check_leaf_block_head (struc blkh = B_BLK_HEAD (bh); nr = blkh_nr_item(blkh); if ( nr > (bh->b_size - BLKH_SIZE) / IH_SIZE) - reiserfs_panic (0, "vs-6010: check_leaf_block_head: invalid item number %z", bh); + reiserfs_panic (NULL, "vs-6010: check_leaf_block_head: invalid item number %z", bh); if ( blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr ) - reiserfs_panic (0, "vs-6020: check_leaf_block_head: invalid free space %z", bh); + reiserfs_panic (NULL, "vs-6020: check_leaf_block_head: invalid free space %z", bh); } @@ -708,14 +708,14 @@ static void check_internal_block_head (s blkh = B_BLK_HEAD (bh); if (!(B_LEVEL (bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL (bh) <= MAX_HEIGHT)) - reiserfs_panic (0, "vs-6025: check_internal_block_head: invalid level %z", bh); + reiserfs_panic (NULL, "vs-6025: check_internal_block_head: invalid level %z", bh); if (B_NR_ITEMS (bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE) - reiserfs_panic (0, "vs-6030: check_internal_block_head: invalid item number %z", bh); + reiserfs_panic (NULL, "vs-6030: check_internal_block_head: invalid item number %z", bh); if (B_FREE_SPACE (bh) != bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS (bh) - DC_SIZE * (B_NR_ITEMS (bh) + 1)) - reiserfs_panic (0, "vs-6040: check_internal_block_head: invalid free space %z", bh); + reiserfs_panic (NULL, "vs-6040: check_internal_block_head: invalid free space %z", bh); } --- linux-2.6.8-rc1/fs/reiserfs/procfs.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/reiserfs/procfs.c 2004-07-13 17:09:13.000000000 -0700 @@ -591,7 +591,7 @@ void reiserfs_proc_unregister_global( co int reiserfs_proc_info_global_init( void ) { if( proc_info_root == NULL ) { - proc_info_root = proc_mkdir( proc_info_root_name, 0 ); + proc_info_root = proc_mkdir(proc_info_root_name, NULL); if( proc_info_root ) { proc_info_root -> owner = THIS_MODULE; } else { @@ -608,7 +608,7 @@ int reiserfs_proc_info_global_done( void { if ( proc_info_root != NULL ) { proc_info_root = NULL; - remove_proc_entry( proc_info_root_name, 0 ); + remove_proc_entry(proc_info_root_name, NULL); } return 0; } --- linux-2.6.8-rc1/fs/reiserfs/stree.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/stree.c 2004-07-13 17:09:13.000000000 -0700 @@ -1306,7 +1306,7 @@ int reiserfs_delete_item (struct reiserf copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); s_del_balance.insert_size[0] = n_del_size; - n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, 0); + n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL); if ( n_ret_value != REPEAT_SEARCH ) break; @@ -1446,14 +1446,14 @@ void reiserfs_delete_solid_item (struct } quota_cut_bytes = ih_item_len(PATH_PITEM_HEAD(&path)) ; - retval = fix_nodes (M_DELETE, &tb, NULL, 0); + retval = fix_nodes (M_DELETE, &tb, NULL, NULL); if (retval == REPEAT_SEARCH) { PROC_INFO_INC( th -> t_super, delete_solid_item_restarted ); continue; } if (retval == CARRY_ON) { - do_balance (&tb, 0, 0, M_DELETE); + do_balance (&tb, NULL, NULL, M_DELETE); if (inode) { /* Should we count quota for item? (we don't count quotas for save-links) */ #ifdef REISERQUOTA_DEBUG reiserfs_debug (th->t_super, "reiserquota delete_solid_item(): freeing %u id=%u type=%c", quota_cut_bytes, inode->i_uid, key2type(key)); @@ -1587,7 +1587,7 @@ static void indirect_to_direct_roll_back "vs-5616: appended bytes found"); PATH_LAST_POSITION (path) --; - removed = reiserfs_delete_item (th, path, &tail_key, inode, 0/*unbh not needed*/); + removed = reiserfs_delete_item (th, path, &tail_key, inode, NULL/*unbh not needed*/); RFALSE( removed <= 0 || removed > tail_len, "vs-5617: there was tail %d bytes, removed item length %d bytes", tail_len, removed); @@ -1677,7 +1677,7 @@ int reiserfs_cut_from_item (struct reise s_cut_balance.insert_size[0] = n_cut_size; - n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, 0); + n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL); if ( n_ret_value != REPEAT_SEARCH ) break; @@ -1935,7 +1935,7 @@ static void check_research_for_paste (st if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || op_bytes_number (found_ih, get_last_bh (path)->b_size) != pos_in_item (path)) - reiserfs_panic (0, "PAP-5720: check_research_for_paste: " + reiserfs_panic (NULL, "PAP-5720: check_research_for_paste: " "found direct item %h or position (%d) does not match to key %K", found_ih, pos_in_item (path), p_s_key); } @@ -1943,7 +1943,7 @@ static void check_research_for_paste (st if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || I_UNFM_NUM (found_ih) != pos_in_item (path) || get_ih_free_space (found_ih) != 0) - reiserfs_panic (0, "PAP-5730: check_research_for_paste: " + reiserfs_panic (NULL, "PAP-5730: check_research_for_paste: " "found indirect item (%h) or position (%d) does not match to key (%K)", found_ih, pos_in_item (path), p_s_key); } --- linux-2.6.8-rc1/fs/reiserfs/super.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/super.c 2004-07-13 17:09:31.000000000 -0700 @@ -549,6 +549,13 @@ static const arg_desc_t logging_mode[] = {NULL, 0} }; +/* possible values for -o barrier= */ +static const arg_desc_t barrier_mode[] = { + {"none", 1<= (unsigned int)-1) { @@ -755,7 +764,7 @@ static int reiserfs_parse_options (struc } if ( c == 'w' ) { - char *p=0; + char *p=NULL; int val = simple_strtoul (arg, &p, 0); if ( *p != '\0') { @@ -809,6 +818,23 @@ static void handle_data_mode(struct supe } } +static void handle_barrier_mode(struct super_block *s, unsigned long bits) { + int flush = (1 << REISERFS_BARRIER_FLUSH); + int none = (1 << REISERFS_BARRIER_NONE); + int all_barrier = flush | none; + + if (bits & all_barrier) { + REISERFS_SB(s)->s_mount_opt &= ~all_barrier; + if (bits & flush) { + REISERFS_SB(s)->s_mount_opt |= flush; + printk("reiserfs: enabling write barrier flush mode\n"); + } else if (bits & none) { + REISERFS_SB(s)->s_mount_opt |= none; + printk("reiserfs: write barriers turned off\n"); + } + } +} + static void handle_attrs( struct super_block *s ) { struct reiserfs_super_block * rs; @@ -853,6 +879,8 @@ static int reiserfs_remount (struct supe safe_mask |= 1 << REISERFS_ATTRS; safe_mask |= 1 << REISERFS_XATTRS_USER; safe_mask |= 1 << REISERFS_POSIXACL; + safe_mask |= 1 << REISERFS_BARRIER_FLUSH; + safe_mask |= 1 << REISERFS_BARRIER_NONE; /* Update the bitmask, taking care to keep * the bits we're not allowed to change here */ @@ -899,6 +927,7 @@ static int reiserfs_remount (struct supe } handle_data_mode(s, mount_options); + handle_barrier_mode(s, mount_options); REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ; s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */ journal_begin(&th, s, 10) ; @@ -1412,6 +1441,9 @@ static int reiserfs_fill_super (struct s } else { reiserfs_info (s, "using writeback data mode\n"); } + if (reiserfs_barrier_flush(s)) { + printk("reiserfs: using flush barriers\n"); + } // set_device_ro(s->s_dev, 1) ; if( journal_init(s, jdev_name, old_format, commit_max_age) ) { --- linux-2.6.8-rc1/fs/reiserfs/tail_conversion.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/reiserfs/tail_conversion.c 2004-07-13 17:09:13.000000000 -0700 @@ -223,7 +223,7 @@ int indirect2direct (struct reiserfs_tra /* Set direct item header to insert. */ - make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1, + make_le_item_head (&s_ih, NULL, get_inode_item_key_version (p_s_inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/); /* we want a pointer to the first byte of the tail in the page. --- linux-2.6.8-rc1/fs/super.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/super.c 2004-07-13 17:09:28.000000000 -0700 @@ -68,6 +68,7 @@ static struct super_block *alloc_super(v INIT_LIST_HEAD(&s->s_files); INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); + INIT_LIST_HEAD(&s->s_inodes); init_rwsem(&s->s_umount); sema_init(&s->s_lock, 1); down_write(&s->s_umount); --- linux-2.6.8-rc1/fs/sysfs/bin.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/sysfs/bin.c 2004-07-13 17:09:16.000000000 -0700 @@ -17,8 +17,10 @@ static int fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) { - struct bin_attribute * attr = dentry->d_fsdata; - struct kobject * kobj = dentry->d_parent->d_fsdata; + struct sysfs_dirent * attr_sd = dentry->d_fsdata; + struct bin_attribute * attr = attr_sd->s_element; + struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata; + struct kobject * kobj = kobj_sd->s_element; return attr->read(kobj, buffer, off, count); } @@ -60,8 +62,10 @@ read(struct file * file, char __user * u static int flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) { - struct bin_attribute *attr = dentry->d_fsdata; - struct kobject *kobj = dentry->d_parent->d_fsdata; + struct sysfs_dirent * attr_sd = dentry->d_fsdata; + struct bin_attribute * attr = attr_sd->s_element; + struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata; + struct kobject * kobj = kobj_sd->s_element; return attr->write(kobj, buffer, offset, count); } @@ -95,7 +99,8 @@ static ssize_t write(struct file * file, static int open(struct inode * inode, struct file * file) { struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent); - struct bin_attribute * attr = file->f_dentry->d_fsdata; + struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata; + struct bin_attribute * attr = attr_sd->s_element; int error = -EINVAL; if (!kobj || !attr) @@ -130,8 +135,10 @@ static int open(struct inode * inode, st static int release(struct inode * inode, struct file * file) { - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; - struct bin_attribute * attr = file->f_dentry->d_fsdata; + struct sysfs_dirent * sd = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = sd->s_element; + struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata; + struct bin_attribute * attr = attr_sd->s_element; u8 * buffer = file->private_data; if (kobj) @@ -141,7 +148,7 @@ static int release(struct inode * inode, return 0; } -static struct file_operations bin_fops = { +struct file_operations bin_fops = { .read = read, .write = write, .llseek = generic_file_llseek, @@ -158,31 +165,10 @@ static struct file_operations bin_fops = int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) { - struct dentry * dentry; - struct dentry * parent; - int error = 0; - - if (!kobj || !attr) - return -EINVAL; - - parent = kobj->dentry; - - down(&parent->d_inode->i_sem); - dentry = sysfs_get_dentry(parent,attr->attr.name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *)attr; - error = sysfs_create(dentry, - (attr->attr.mode & S_IALLUGO) | S_IFREG, - NULL); - if (!error) { - dentry->d_inode->i_size = attr->size; - dentry->d_inode->i_fop = &bin_fops; - } - dput(dentry); - } else - error = PTR_ERR(dentry); - up(&parent->d_inode->i_sem); - return error; + if (kobj && kobj->dentry && attr) + return sysfs_add_file(kobj->dentry, &attr->attr, + SYSFS_KOBJ_BIN_ATTR); + return -EINVAL; } --- linux-2.6.8-rc1/fs/sysfs/dir.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/sysfs/dir.c 2004-07-13 17:09:16.000000000 -0700 @@ -12,31 +12,181 @@ DECLARE_RWSEM(sysfs_rename_sem); +struct inode_operations sysfs_dir_inode_operations = { + .lookup = sysfs_lookup, +}; + +struct file_operations sysfs_dir_operations = { + .open = sysfs_dir_open, + .release = sysfs_dir_close, + .llseek = sysfs_dir_lseek, + .read = generic_read_dir, + .readdir = sysfs_readdir, +}; + +static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) +{ + struct sysfs_dirent * sd = dentry->d_fsdata; + + if (sd) { + BUG_ON(sd->s_dentry != dentry); + sd->s_dentry = NULL; + sysfs_put(sd); + } + iput(inode); +} + +static struct dentry_operations sysfs_dentry_ops = { + .d_iput = sysfs_d_iput, +}; + +const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) +{ + struct attribute * attr; + struct bin_attribute * bin_attr; + struct sysfs_symlink * sl; + + if (!sd || !sd->s_element) + BUG(); + + switch (sd->s_type) { + case SYSFS_KOBJECT: + case SYSFS_KOBJ_ATTR_GROUP: + /* Always have a dentry so use that */ + return sd->s_dentry->d_name.name; + + case SYSFS_KOBJ_ATTR: + attr = sd->s_element; + return attr->name; + + case SYSFS_KOBJ_BIN_ATTR: + bin_attr = sd->s_element; + return bin_attr->attr.name; + + case SYSFS_KOBJ_LINK: + sl = sd->s_element; + return sl->link_name; + } + return NULL; +} + +static int init_file(struct inode * inode) +{ + inode->i_size = PAGE_SIZE; + inode->i_fop = &sysfs_file_operations; + return 0; +} + static int init_dir(struct inode * inode) { - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; return 0; } +/* attaches attribute's sysfs_dirent to the dentry corresponding to the + * attribute file + */ +static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) +{ + struct attribute * attr = NULL; + struct bin_attribute * bin_attr = NULL; + int (* init) (struct inode *) = NULL; + int error = 0; + + if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { + bin_attr = sd->s_element; + attr = &bin_attr->attr; + } else { + attr = sd->s_element; + init = init_file; + } + + error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init); + if (error) + return error; + + if (bin_attr) { + dentry->d_inode->i_size = bin_attr->size; + dentry->d_inode->i_fop = &bin_fops; + } + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); + sd->s_dentry = dentry; + d_rehash(dentry); + + return 0; +} + +static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry) +{ + int err = 0; + + err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); + if (!err) { + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata = sysfs_get(sd); + sd->s_dentry = dentry; + d_rehash(dentry); + } + return err; +} + +struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; + struct sysfs_dirent * sd; + int err = 0; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (sd->s_type & SYSFS_NOT_PINNED) { + const unsigned char * name = sysfs_get_name(sd); + + if (strcmp(name, dentry->d_name.name)) + continue; + + if (sd->s_type & SYSFS_KOBJ_LINK) + err = sysfs_attach_link(sd, dentry); + else + err = sysfs_attach_attr(sd, dentry); + break; + } + } + + return ERR_PTR(err); +} static int create_dir(struct kobject * k, struct dentry * p, const char * n, struct dentry ** d) { int error; + umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; down(&p->d_inode->i_sem); *d = sysfs_get_dentry(p,n); if (!IS_ERR(*d)) { - error = sysfs_create(*d, - S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO, - init_dir); + error = sysfs_create(*d, mode, init_dir); if (!error) { - (*d)->d_fsdata = k; - p->d_inode->i_nlink++; + struct sysfs_dirent * sd, * parent_sd; + parent_sd = p->d_fsdata; + sd = sysfs_new_dirent(parent_sd, k, + (parent_sd->s_element == k) ? + SYSFS_KOBJ_ATTR_GROUP : + SYSFS_KOBJECT); + if (sd) { + (*d)->d_fsdata = sysfs_get(sd); + (*d)->d_op = &sysfs_dentry_ops; + p->d_inode->i_nlink++; + sd->s_element = k; + sd->s_dentry = *d; + sd->s_mode = mode; + d_rehash(*d); + } else + error = -ENOMEM; } dput(*d); } else @@ -45,7 +195,6 @@ static int create_dir(struct kobject * k return error; } - int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d) { return create_dir(k,k->dentry,n,d); @@ -79,12 +228,16 @@ int sysfs_create_dir(struct kobject * ko return error; } - static void remove_dir(struct dentry * d) { struct dentry * parent = dget(d->d_parent); + struct sysfs_dirent * sd; + down(&parent->d_inode->i_sem); d_delete(d); + sd = d->d_fsdata; + list_del_init(&sd->s_sibling); + sysfs_put(d->d_fsdata); if (d->d_inode) simple_rmdir(parent->d_inode,d); @@ -106,14 +259,14 @@ void sysfs_remove_subdir(struct dentry * * @kobj: object. * * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. + * the directory before we remove the directory */ void sysfs_remove_dir(struct kobject * kobj) { - struct list_head * node; struct dentry * dentry = dget(kobj->dentry); + struct sysfs_dirent * parent_sd = dentry->d_fsdata; + struct sysfs_dirent * sd, * tmp; if (!dentry) return; @@ -121,38 +274,13 @@ void sysfs_remove_dir(struct kobject * k pr_debug("sysfs %s: removing dir\n",dentry->d_name.name); down(&dentry->d_inode->i_sem); - spin_lock(&dcache_lock); -restart: - node = dentry->d_subdirs.next; - while (node != &dentry->d_subdirs) { - struct dentry * d = list_entry(node,struct dentry,d_child); - - node = node->next; - pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count)); - if (!d_unhashed(d) && (d->d_inode)) { - d = dget_locked(d); - pr_debug("removing"); - - /** - * Unlink and unhash. - */ - __d_drop(d); - spin_unlock(&dcache_lock); - /* release the target kobject in case of - * a symlink - */ - if (S_ISLNK(d->d_inode->i_mode)) - kobject_put(d->d_fsdata); - - simple_unlink(dentry->d_inode,d); - dput(d); - pr_debug(" done\n"); - spin_lock(&dcache_lock); - /* re-acquired dcache_lock, need to restart */ - goto restart; - } - } - spin_unlock(&dcache_lock); + list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) { + if (!sd->s_element) + continue; + list_del_init(&sd->s_sibling); + sysfs_drop_dentry(sd, dentry); + sysfs_put(sd); + } up(&dentry->d_inode->i_sem); remove_dir(dentry); @@ -182,8 +310,10 @@ int sysfs_rename_dir(struct kobject * ko if (!IS_ERR(new_dentry)) { if (!new_dentry->d_inode) { error = kobject_set_name(kobj,new_name); - if (!error) + if (!error) { + d_add(new_dentry, NULL); d_move(kobj->dentry, new_dentry); + } } dput(new_dentry); } @@ -193,6 +323,137 @@ int sysfs_rename_dir(struct kobject * ko return error; } +int sysfs_dir_open(struct inode *inode, struct file *file) +{ + struct dentry * dentry = file->f_dentry; + struct sysfs_dirent * parent_sd = dentry->d_fsdata; + + down(&dentry->d_inode->i_sem); + file->private_data = sysfs_new_dirent(parent_sd, NULL, 0); + up(&dentry->d_inode->i_sem); + + return file->private_data ? 0 : -ENOMEM; + +} + +int sysfs_dir_close(struct inode *inode, struct file *file) +{ + struct dentry * dentry = file->f_dentry; + struct sysfs_dirent * cursor = file->private_data; + + down(&dentry->d_inode->i_sem); + list_del_init(&cursor->s_sibling); + up(&dentry->d_inode->i_sem); + sysfs_put(file->private_data); + + return 0; +} + +/* Relationship between s_mode and the DT_xxx types */ +static inline unsigned char dt_type(struct sysfs_dirent *sd) +{ + return (sd->s_mode >> 12) & 15; +} + +int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct sysfs_dirent * parent_sd = dentry->d_fsdata; + struct sysfs_dirent *cursor = filp->private_data; + struct list_head *p, *q = &cursor->s_sibling; + ino_t ino; + int i = filp->f_pos; + + switch (i) { + case 0: + ino = dentry->d_inode->i_ino; + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) + break; + filp->f_pos++; + i++; + /* fallthrough */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) + break; + filp->f_pos++; + i++; + /* fallthrough */ + default: + if (filp->f_pos == 2) { + list_del(q); + list_add(q, &parent_sd->s_children); + } + for (p=q->next; p!= &parent_sd->s_children; p=p->next) { + struct sysfs_dirent *next; + const char * name; + int len; + + next = list_entry(p, struct sysfs_dirent, + s_sibling); + if (!next->s_element) + continue; + + name = sysfs_get_name(next); + len = strlen(name); + if (next->s_dentry) + ino = next->s_dentry->d_inode->i_ino; + else + ino = iunique(sysfs_sb, 2); + + if (filldir(dirent, name, len, filp->f_pos, ino, + dt_type(next)) < 0) + return 0; + + list_del(q); + list_add(q, p); + p = q; + filp->f_pos++; + } + } + return 0; +} + +loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) +{ + struct dentry * dentry = file->f_dentry; + + down(&dentry->d_inode->i_sem); + switch (origin) { + case 1: + offset += file->f_pos; + case 0: + if (offset >= 0) + break; + default: + up(&file->f_dentry->d_inode->i_sem); + return -EINVAL; + } + if (offset != file->f_pos) { + file->f_pos = offset; + if (file->f_pos >= 2) { + struct sysfs_dirent *sd = dentry->d_fsdata; + struct sysfs_dirent *cursor = file->private_data; + struct list_head *p; + loff_t n = file->f_pos - 2; + + list_del(&cursor->s_sibling); + p = sd->s_children.next; + while (n && p != &sd->s_children) { + struct sysfs_dirent *next; + next = list_entry(p, struct sysfs_dirent, + s_sibling); + if (next->s_element) + n--; + p = p->next; + } + list_add_tail(&cursor->s_sibling, p); + } + } + up(&dentry->d_inode->i_sem); + return offset; +} + EXPORT_SYMBOL(sysfs_create_dir); EXPORT_SYMBOL(sysfs_remove_dir); EXPORT_SYMBOL(sysfs_rename_dir); --- linux-2.6.8-rc1/fs/sysfs/file.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/sysfs/file.c 2004-07-13 17:09:16.000000000 -0700 @@ -9,14 +9,6 @@ #include "sysfs.h" -static struct file_operations sysfs_file_operations; - -static int init_file(struct inode * inode) -{ - inode->i_size = PAGE_SIZE; - inode->i_fop = &sysfs_file_operations; - return 0; -} #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) #define to_sattr(a) container_of(a,struct subsys_attribute,attr) @@ -77,8 +69,10 @@ struct sysfs_buffer { */ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer) { - struct attribute * attr = file->f_dentry->d_fsdata; - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata; + struct attribute * attr = attr_sd->s_element; + struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobj_sd->s_element; struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -135,6 +129,9 @@ static int flush_read_buffer(struct sysf * is in the file's ->d_fsdata. The target object is in the directory's * ->d_fsdata. * + * It is safe to use ->d_parent->d_fsdata as both dentry and the kobject + * are pinned in ->open(). + * * We call fill_read_buffer() to allocate and fill the buffer from the * object's show() method exactly once (if the read is happening from * the beginning of the file). That should fill the entire buffer with @@ -199,8 +196,10 @@ fill_write_buffer(struct sysfs_buffer * static int flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count) { - struct attribute * attr = file->f_dentry->d_fsdata; - struct kobject * kobj = file->f_dentry->d_parent->d_fsdata; + struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata; + struct attribute * attr = attr_sd->s_element; + struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobj_sd->s_element; struct sysfs_ops * ops = buffer->ops; return ops->store(kobj,attr,buffer->page,count); @@ -240,7 +239,8 @@ sysfs_write_file(struct file *file, cons static int check_perm(struct inode * inode, struct file * file) { struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent); - struct attribute * attr = file->f_dentry->d_fsdata; + struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata; + struct attribute * attr = attr_sd->s_element; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error = 0; @@ -321,8 +321,10 @@ static int sysfs_open_file(struct inode static int sysfs_release(struct inode * inode, struct file * filp) { - struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata; - struct attribute * attr = filp->f_dentry->d_fsdata; + struct sysfs_dirent * attr_sd = filp->f_dentry->d_fsdata; + struct attribute * attr = attr_sd->s_element; + struct sysfs_dirent * kobj_sd = filp->f_dentry->d_parent->d_fsdata; + struct kobject * kobj = kobj_sd->s_element; struct sysfs_buffer * buffer = filp->private_data; if (kobj) @@ -337,7 +339,7 @@ static int sysfs_release(struct inode * return 0; } -static struct file_operations sysfs_file_operations = { +struct file_operations sysfs_file_operations = { .read = sysfs_read_file, .write = sysfs_write_file, .llseek = generic_file_llseek, @@ -346,23 +348,20 @@ static struct file_operations sysfs_file }; -int sysfs_add_file(struct dentry * dir, const struct attribute * attr) +int sysfs_add_file(struct dentry * parent, const struct attribute * attr, int t) { - struct dentry * dentry; - int error; + struct sysfs_dirent * sd; + struct sysfs_dirent * parent_sd = parent->d_fsdata; + int error = 0; + + down(&parent->d_inode->i_sem); + sd = sysfs_new_dirent(parent_sd, (void *) attr, t); + if (!sd) + error = -ENOMEM; + else + sd->s_mode = (attr->mode & S_IALLUGO) | S_IFREG ; + up(&parent->d_inode->i_sem); - down(&dir->d_inode->i_sem); - dentry = sysfs_get_dentry(dir,attr->name); - if (!IS_ERR(dentry)) { - error = sysfs_create(dentry, - (attr->mode & S_IALLUGO) | S_IFREG, - init_file); - if (!error) - dentry->d_fsdata = (void *)attr; - dput(dentry); - } else - error = PTR_ERR(dentry); - up(&dir->d_inode->i_sem); return error; } @@ -375,8 +374,8 @@ int sysfs_add_file(struct dentry * dir, int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) { - if (kobj && attr) - return sysfs_add_file(kobj->dentry,attr); + if (kobj && kobj->dentry && attr) + return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR); return -EINVAL; } --- linux-2.6.8-rc1/fs/sysfs/group.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/fs/sysfs/group.c 2004-07-13 17:09:17.000000000 -0700 @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include "sysfs.h" @@ -31,7 +31,7 @@ static int create_files(struct dentry * int error = 0; for (attr = grp->attrs; *attr && !error; attr++) { - error = sysfs_add_file(dir,*attr); + error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR); } if (error) remove_files(dir,grp); @@ -70,11 +70,15 @@ void sysfs_remove_group(struct kobject * else dir = dget(kobj->dentry); - remove_files(dir,grp); - if (grp->name) - sysfs_remove_subdir(dir); - /* release the ref. taken in this routine */ - dput(dir); + if (!IS_ERR(dir)) { + if (dir && dir->d_inode) { + remove_files(dir,grp); + if (grp->name) + sysfs_remove_subdir(dir); + /* release the ref. taken in this routine */ + dput(dir); + } + } } --- linux-2.6.8-rc1/fs/sysfs/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/sysfs/inode.c 2004-07-13 17:09:16.000000000 -0700 @@ -11,6 +11,8 @@ #include #include #include +#include "sysfs.h" + extern struct super_block * sysfs_sb; static struct address_space_operations sysfs_aops = { @@ -66,7 +68,8 @@ int sysfs_create(struct dentry * dentry, error = init(inode); if (!error) { d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ + if (S_ISDIR(mode)) + dget(dentry); /* pin only directory dentry in core */ } else iput(inode); Done: @@ -88,31 +91,51 @@ struct dentry * sysfs_get_dentry(struct return lookup_hash(&qstr,parent); } +static struct sysfs_dirent * sysfs_find_dirent(struct sysfs_dirent * parent_sd, + const char * name) +{ + struct sysfs_dirent *sd; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (sd->s_element) { + if (!strcmp(sysfs_get_name(sd), name)) + return sd; + } + } + return NULL; +} + +/* Unhashes the dentry corresponding to given sysfs_dirent + * Called with parent inode's i_sem held. + */ +void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) +{ + struct dentry * dentry = sd->s_dentry; + + if (dentry) { + spin_lock(&dcache_lock); + dget_locked(dentry); + if (!(d_unhashed(dentry) && dentry->d_inode)) { + __d_drop(dentry); + spin_unlock(&dcache_lock); + simple_unlink(parent->d_inode, dentry); + } else { + spin_unlock(&dcache_lock); + dput(dentry); + } + } +} + void sysfs_hash_and_remove(struct dentry * dir, const char * name) { - struct dentry * victim; + struct sysfs_dirent * sd; down(&dir->d_inode->i_sem); - victim = sysfs_get_dentry(dir,name); - if (!IS_ERR(victim)) { - /* make sure dentry is really there */ - if (victim->d_inode && - (victim->d_parent->d_inode == dir->d_inode)) { - pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, - atomic_read(&victim->d_count)); - - d_drop(victim); - /* release the target kobject in case of - * a symlink - */ - if (S_ISLNK(victim->d_inode->i_mode)) - kobject_put(victim->d_fsdata); - simple_unlink(dir->d_inode,victim); - } - /* - * Drop reference from sysfs_get_dentry() above. - */ - dput(victim); + sd = sysfs_find_dirent(dir->d_fsdata, name); + if (sd) { + list_del_init(&sd->s_sibling); + sysfs_drop_dentry(sd, dir); + sysfs_put(sd); } up(&dir->d_inode->i_sem); } --- linux-2.6.8-rc1/fs/sysfs/mount.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/fs/sysfs/mount.c 2004-07-13 17:09:16.000000000 -0700 @@ -22,6 +22,13 @@ static struct super_operations sysfs_ops .drop_inode = generic_delete_inode, }; +struct sysfs_dirent sysfs_root = { + .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), + .s_children = LIST_HEAD_INIT(sysfs_root.s_children), + .s_element = NULL, + .s_type = SYSFS_ROOT, +}; + static int sysfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; @@ -35,8 +42,8 @@ static int sysfs_fill_super(struct super inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); if (inode) { - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; } else { @@ -50,6 +57,7 @@ static int sysfs_fill_super(struct super iput(inode); return -ENOMEM; } + root->d_fsdata = &sysfs_root; sb->s_root = root; return 0; } --- linux-2.6.8-rc1/fs/sysfs/symlink.c 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/sysfs/symlink.c 2004-07-13 17:09:17.000000000 -0700 @@ -13,7 +13,7 @@ static struct inode_operations sysfs_sym .follow_link = sysfs_follow_link, }; -static int init_symlink(struct inode * inode) +int init_symlink(struct inode * inode) { inode->i_op = &sysfs_symlink_inode_operations; return 0; @@ -53,6 +53,30 @@ static void fill_object_path(struct kobj } } +static int sysfs_add_link(struct sysfs_dirent * parent_sd, char * name, + struct kobject * target) +{ + struct sysfs_dirent * sd; + struct sysfs_symlink * sl; + + sl = kmalloc(sizeof(*sl), GFP_KERNEL); + if (!sl) + return -ENOMEM; + + sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL); + strcpy(sl->link_name, name); + sl->target_kobj = kobject_get(target); + + sd = sysfs_new_dirent(parent_sd, sl, SYSFS_KOBJ_LINK); + if (sd) { + sd->s_mode = S_IFLNK|S_IRWXUGO; + return 0; + } + + kfree(sl); + return -ENOMEM; +} + /** * sysfs_create_link - create symlink between two objects. * @kobj: object whose directory we're creating the link in. @@ -62,21 +86,13 @@ static void fill_object_path(struct kobj int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name) { struct dentry * dentry = kobj->dentry; - struct dentry * d; int error = 0; + if (!name) + return -EINVAL; + down(&dentry->d_inode->i_sem); - d = sysfs_get_dentry(dentry,name); - if (!IS_ERR(d)) { - error = sysfs_create(d, S_IFLNK|S_IRWXUGO, init_symlink); - if (!error) - /* - * associate the link dentry with the target kobject - */ - d->d_fsdata = kobject_get(target); - dput(d); - } else - error = PTR_ERR(d); + error = sysfs_add_link(dentry->d_fsdata, name, target); up(&dentry->d_inode->i_sem); return error; } --- linux-2.6.8-rc1/fs/sysfs/sysfs.h 2004-06-15 23:29:44.000000000 -0700 +++ 25/fs/sysfs/sysfs.h 2004-07-13 17:09:17.000000000 -0700 @@ -1,28 +1,96 @@ +#include extern struct vfsmount * sysfs_mount; +extern struct super_block * sysfs_sb; extern struct inode * sysfs_new_inode(mode_t mode); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); extern struct dentry * sysfs_get_dentry(struct dentry *, const char *); +extern int sysfs_add_file(struct dentry *, const struct attribute *, int); -extern int sysfs_add_file(struct dentry * dir, const struct attribute * attr); extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); extern void sysfs_remove_subdir(struct dentry *); +extern int sysfs_dir_open(struct inode *inode, struct file *file); +extern int sysfs_dir_close(struct inode *inode, struct file *file); +extern loff_t sysfs_dir_lseek(struct file *, loff_t, int); +extern int sysfs_readdir(struct file *, void *, filldir_t); +extern void sysfs_umount_begin(struct super_block *); +extern const unsigned char * sysfs_get_name(struct sysfs_dirent *); +extern struct dentry * sysfs_lookup(struct inode *, struct dentry *, struct nameidata *); +extern void sysfs_drop_dentry(struct sysfs_dirent *, struct dentry *); +extern int sysfs_symlink(struct inode *, struct dentry *, const char *); +extern int init_symlink(struct inode *); extern int sysfs_readlink(struct dentry *, char __user *, int ); extern int sysfs_follow_link(struct dentry *, struct nameidata *); extern struct rw_semaphore sysfs_rename_sem; +extern struct file_operations sysfs_file_operations; +extern struct file_operations bin_fops; +extern struct inode_operations sysfs_dir_inode_operations; +extern struct file_operations sysfs_dir_operations; + +struct sysfs_symlink { + char * link_name; + struct kobject * target_kobj; +}; + +static inline +struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * p, void * e, int t) +{ + struct sysfs_dirent * sd; + + sd = kmalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return NULL; + memset(sd, 0, sizeof(*sd)); + atomic_set(&sd->s_count, 1); + sd->s_element = e; + sd->s_type = t; + sd->s_dentry = NULL; + INIT_LIST_HEAD(&sd->s_children); + list_add(&sd->s_sibling, &p->s_children); + + return sd; +} + +static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +{ + if (sd) { + WARN_ON(!atomic_read(&sd->s_count)); + atomic_inc(&sd->s_count); + } + return sd; +} + +static inline void sysfs_put(struct sysfs_dirent * sd) +{ + if (atomic_dec_and_test(&sd->s_count)) { + if (sd->s_type & SYSFS_KOBJ_LINK) { + struct sysfs_symlink * sl = sd->s_element; + kfree(sl->link_name); + kobject_put(sl->target_kobj); + kfree(sl); + } + kfree(sd); + } +} static inline struct kobject *sysfs_get_kobject(struct dentry *dentry) { struct kobject * kobj = NULL; spin_lock(&dcache_lock); - if (!d_unhashed(dentry)) - kobj = kobject_get(dentry->d_fsdata); + if (!d_unhashed(dentry)) { + struct sysfs_dirent * sd = dentry->d_fsdata; + if (sd->s_type & SYSFS_KOBJ_LINK) { + struct sysfs_symlink * sl = sd->s_element; + kobj = kobject_get(sl->target_kobj); + } else + kobj = kobject_get(sd->s_element); + } spin_unlock(&dcache_lock); return kobj; --- linux-2.6.8-rc1/fs/sysv/inode.c 2004-07-11 14:13:29.000000000 -0700 +++ 25/fs/sysv/inode.c 2004-07-13 17:09:13.000000000 -0700 @@ -233,12 +233,12 @@ static struct buffer_head * sysv_update_ if (!ino || ino > sbi->s_ninodes) { printk("Bad inode number on dev %s: %d is out of range\n", inode->i_sb->s_id, ino); - return 0; + return NULL; } raw_inode = sysv_raw_inode(sb, ino, &bh); if (!raw_inode) { printk("unable to read i-node block\n"); - return 0; + return NULL; } raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode); --- linux-2.6.8-rc1/include/acpi/acconfig.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/acconfig.h 2004-07-13 17:09:17.642590792 -0700 @@ -64,11 +64,21 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040326 +#define ACPI_CA_VERSION 0x20040615 + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" /* Maximum objects in the various object caches */ -#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ +#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects */ #define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_EXTPARSE_CACHE_DEPTH 64 /* Parse tree objects */ #define ACPI_MAX_OBJECT_CACHE_DEPTH 64 /* Interpreter operand objects */ @@ -152,10 +162,11 @@ /* Constants used in searching for the RSDP in low memory */ -#define ACPI_LO_RSDP_WINDOW_BASE 0 /* Physical Address */ -#define ACPI_HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ -#define ACPI_LO_RSDP_WINDOW_SIZE 0x400 -#define ACPI_HI_RSDP_WINDOW_SIZE 0x20000 +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 #define ACPI_RSDP_SCAN_STEP 16 /* Operation regions */ @@ -187,7 +198,7 @@ /* Number of strings associated with the _OSI reserved method */ -#define ACPI_NUM_OSI_STRINGS 4 +#define ACPI_NUM_OSI_STRINGS 9 /****************************************************************************** --- linux-2.6.8-rc1/include/acpi/acdebug.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acdebug.h 2004-07-13 17:09:17.000000000 -0700 @@ -106,6 +106,10 @@ acpi_db_method_end ( * dbcmds - debug commands and output routines */ +acpi_status +acpi_db_disassemble_method ( + char *name); + void acpi_db_display_table_info ( char *table_arg); @@ -164,6 +168,10 @@ void acpi_db_set_scope ( char *name); +acpi_status +acpi_db_sleep ( + char *object_arg); + void acpi_db_find_references ( char *object_arg); --- linux-2.6.8-rc1/include/acpi/acdisasm.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acdisasm.h 2004-07-13 17:09:17.000000000 -0700 @@ -52,6 +52,13 @@ #define BLOCK_BRACE 2 #define BLOCK_COMMA_LIST 4 +struct acpi_external_list +{ + char *path; + struct acpi_external_list *next; +}; + +extern struct acpi_external_list *acpi_gbl_external_list; extern const char *acpi_gbl_io_decode[2]; extern const char *acpi_gbl_word_decode[4]; extern const char *acpi_gbl_consume_decode[2]; @@ -399,4 +406,12 @@ acpi_dm_vendor_small_descriptor ( u32 level); +/* + * dmutils + */ + +void +acpi_dm_add_to_external_list ( + char *path); + #endif /* __ACDISASM_H__ */ --- linux-2.6.8-rc1/include/acpi/acdispat.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acdispat.h 2004-07-13 17:09:17.000000000 -0700 @@ -437,8 +437,7 @@ acpi_ds_init_aml_walk ( struct acpi_namespace_node *method_node, u8 *aml_start, u32 aml_length, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc, + struct acpi_parameter_info *info, u32 pass_number); acpi_status --- linux-2.6.8-rc1/include/acpi/acevents.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acevents.h 2004-07-13 17:09:17.000000000 -0700 @@ -46,11 +46,11 @@ acpi_status -acpi_ev_initialize ( +acpi_ev_initialize_events ( void); acpi_status -acpi_ev_handler_initialize ( +acpi_ev_install_xrupt_handlers ( void); @@ -117,6 +117,20 @@ u8 acpi_ev_valid_gpe_event ( struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_update_gpe_enable_masks ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type); + +acpi_status +acpi_ev_enable_gpe ( + struct acpi_gpe_event_info *gpe_event_info, + u8 write_to_hardware); + +acpi_status +acpi_ev_disable_gpe ( + struct acpi_gpe_event_info *gpe_event_info); + struct acpi_gpe_event_info * acpi_ev_get_gpe_event_info ( acpi_handle gpe_device, @@ -139,6 +153,11 @@ acpi_status acpi_ev_delete_gpe_block ( struct acpi_gpe_block_info *gpe_block); +acpi_status +acpi_ev_delete_gpe_handlers ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + u32 acpi_ev_gpe_dispatch ( struct acpi_gpe_event_info *gpe_event_info, @@ -148,12 +167,25 @@ u32 acpi_ev_gpe_detect ( struct acpi_gpe_xrupt_info *gpe_xrupt_list); +acpi_status +acpi_ev_set_gpe_type ( + struct acpi_gpe_event_info *gpe_event_info, + u8 type); + +acpi_status +acpi_ev_check_for_wake_only_gpe ( + struct acpi_gpe_event_info *gpe_event_info); + /* * Evregion - Address Space handling */ acpi_status -acpi_ev_init_address_spaces ( +acpi_ev_install_region_handlers ( + void); + +acpi_status +acpi_ev_initialize_op_regions ( void); acpi_status @@ -183,6 +215,19 @@ acpi_ev_detach_region ( u8 acpi_ns_is_locked); acpi_status +acpi_ev_install_space_handler ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, + void *context); + +acpi_status +acpi_ev_execute_reg_methods ( + struct acpi_namespace_node *node, + acpi_adr_space_type space_id); + +acpi_status acpi_ev_execute_reg_method ( union acpi_operand_object *region_obj, u32 function); --- linux-2.6.8-rc1/include/acpi/acexcep.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acexcep.h 2004-07-13 17:09:17.645590336 -0700 @@ -95,8 +95,9 @@ #define AE_LOGICAL_ADDRESS (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL) #define AE_ABORT_METHOD (acpi_status) (0x001C | AE_CODE_ENVIRONMENTAL) #define AE_SAME_HANDLER (acpi_status) (0x001D | AE_CODE_ENVIRONMENTAL) +#define AE_WAKE_ONLY_GPE (acpi_status) (0x001E | AE_CODE_ENVIRONMENTAL) -#define AE_CODE_ENV_MAX 0x001D +#define AE_CODE_ENV_MAX 0x001E /* * Programmer exceptions @@ -222,7 +223,8 @@ char const *acpi_gbl_exception_names_e "AE_NO_GLOBAL_LOCK", "AE_LOGICAL_ADDRESS", "AE_ABORT_METHOD", - "AE_SAME_HANDLER" + "AE_SAME_HANDLER", + "AE_WAKE_ONLY_GPE" }; char const *acpi_gbl_exception_names_pgm[] = --- linux-2.6.8-rc1/include/acpi/acglobal.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/acglobal.h 2004-07-13 17:09:17.646590184 -0700 @@ -46,15 +46,17 @@ /* - * Ensure that the globals are actually defined only once. + * Ensure that the globals are actually defined and initialized only once. * - * The use of these defines allows a single list of globals (here) in order + * The use of these macros allows a single list of globals (here) in order * to simplify maintenance of the code. */ #ifdef DEFINE_ACPI_GLOBALS #define ACPI_EXTERN +#define ACPI_INIT_GLOBAL(a,b) a=b #else #define ACPI_EXTERN extern +#define ACPI_INIT_GLOBAL(a,b) a #endif /* @@ -64,6 +66,7 @@ ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; + /***************************************************************************** * * Debug support @@ -79,15 +82,35 @@ extern u32 extern u32 acpi_gbl_nesting_level; + /***************************************************************************** * - * Runtime configuration + * Runtime configuration (static defaults that can be overriden at runtime) * ****************************************************************************/ -ACPI_EXTERN u8 acpi_gbl_create_osi_method; -ACPI_EXTERN u8 acpi_gbl_all_methods_serialized; -ACPI_EXTERN u8 acpi_gbl_leave_wake_gpes_disabled; +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPI CA is fully compatible with other ACPI implementations. + * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_create_osi_method, TRUE); + +/* + * Automatically serialize ALL control methods? Default is FALSE, meaning + * to use the Serialized/not_serialized method flags on a per method basis. + * Only change this if the ASL code is poorly written and cannot handle + * reentrancy even though methods are marked "not_serialized". + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_all_methods_serialized, FALSE); + +/* + * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and + * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only + * be enabled just before going to sleep. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_leave_wake_gpes_disabled, TRUE); + /***************************************************************************** * @@ -102,7 +125,6 @@ ACPI_EXTERN u8 * * These tables are single-table only; meaning that there can be at most one * of each in the system. Each global points to the actual table. - * */ ACPI_EXTERN u32 acpi_gbl_table_flags; ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; @@ -170,6 +192,7 @@ ACPI_EXTERN u8 ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_global_lock_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; +ACPI_EXTERN u8 acpi_gbl_system_awake_and_running; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; --- linux-2.6.8-rc1/include/acpi/achware.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/achware.h 2004-07-13 17:09:17.646590184 -0700 @@ -114,15 +114,7 @@ acpi_hw_clear_acpi_status ( /* GPE support */ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info); - -void -acpi_hw_enable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - -acpi_status -acpi_hw_disable_gpe ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info); acpi_status @@ -130,10 +122,6 @@ acpi_hw_disable_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - acpi_status acpi_hw_clear_gpe ( struct acpi_gpe_event_info *gpe_event_info); @@ -149,13 +137,27 @@ acpi_hw_get_gpe_status ( acpi_event_status *event_status); acpi_status -acpi_hw_prepare_gpes_for_sleep ( +acpi_hw_disable_all_gpes ( + void); + +acpi_status +acpi_hw_enable_all_runtime_gpes ( void); acpi_status -acpi_hw_restore_gpes_on_wake ( +acpi_hw_enable_all_wakeup_gpes ( void); +acpi_status +acpi_hw_enable_runtime_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + +acpi_status +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + /* ACPI Timer prototypes */ --- linux-2.6.8-rc1/include/acpi/acinterp.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acinterp.h 2004-07-13 17:09:17.000000000 -0700 @@ -118,6 +118,12 @@ acpi_ex_convert_to_ascii ( */ acpi_status +acpi_ex_common_buffer_setup ( + union acpi_operand_object *obj_desc, + u32 buffer_length, + u32 *datum_count); + +acpi_status acpi_ex_extract_from_field ( union acpi_operand_object *obj_desc, void *buffer, @@ -240,8 +246,8 @@ acpi_ex_do_concatenate ( u8 acpi_ex_do_logical_op ( u16 opcode, - acpi_integer operand0, - acpi_integer operand1); + union acpi_operand_object *obj_desc, + union acpi_operand_object *obj_desc2); acpi_integer acpi_ex_do_math_op ( @@ -563,8 +569,11 @@ acpi_status acpi_ex_store_object_to_node ( union acpi_operand_object *source_desc, struct acpi_namespace_node *node, - struct acpi_walk_state *walk_state); + struct acpi_walk_state *walk_state, + u8 implicit_conversion); +#define ACPI_IMPLICIT_CONVERSION TRUE +#define ACPI_NO_IMPLICIT_CONVERSION FALSE /* * exstoren --- linux-2.6.8-rc1/include/acpi/aclocal.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/aclocal.h 2004-07-13 17:09:17.649589728 -0700 @@ -189,8 +189,6 @@ struct acpi_namespace_node u8 type; /* Type associated with this name */ u16 owner_id; union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ - - union acpi_operand_object *object; /* Pointer to attached ACPI object (optional) */ struct acpi_namespace_node *child; /* First child */ struct acpi_namespace_node *peer; /* Next peer*/ @@ -211,10 +209,8 @@ struct acpi_namespace_node #define ANOBJ_METHOD_LOCAL 0x10 #define ANOBJ_METHOD_NO_RETVAL 0x20 #define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 - #define ANOBJ_IS_BIT_OFFSET 0x80 - /* * ACPI Table Descriptor. One per ACPI table */ @@ -309,16 +305,31 @@ struct acpi_create_field_info * ****************************************************************************/ -/* Information about a GPE, one per each GPE in an array */ +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ -struct acpi_gpe_event_info +struct acpi_handler_info { - struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - acpi_gpe_handler handler; /* Address of handler, if any */ + acpi_event_handler address; /* Address of handler, if any */ void *context; /* Context to be passed to handler */ + struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ +}; + +union acpi_gpe_dispatch_info +{ + struct acpi_namespace_node *method_node; /* Method node for this GPE level */ + struct acpi_handler_info *handler; +}; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +struct acpi_gpe_event_info +{ + union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ - u8 flags; /* Level or Edge */ - u8 bit_mask; /* This GPE within the register */ + u8 flags; /* Misc info about this GPE */ + u8 register_bit; /* This GPE bit within the register */ }; /* Information about a GPE register pair, one per each status/enable pair in an array */ @@ -327,9 +338,8 @@ struct acpi_gpe_register_info { struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address enable_address; /* Address of enable reg */ - u8 status; /* Current value of status reg */ - u8 enable; /* Current value of enable reg */ - u8 wake_enable; /* Mask of bits to keep enabled when sleeping */ + u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ + u8 enable_for_run; /* GPEs to keep enabled when running */ u8 base_gpe_number; /* Base GPE number for this register */ }; @@ -339,6 +349,7 @@ struct acpi_gpe_register_info */ struct acpi_gpe_block_info { + struct acpi_namespace_node *node; struct acpi_gpe_block_info *previous; struct acpi_gpe_block_info *next; struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ @@ -502,7 +513,7 @@ struct acpi_thread_state struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ u32 thread_id; /* Running thread ID */ - u16 current_sync_level; /* Mutex Sync (nested acquire) level */ + u8 current_sync_level; /* Mutex Sync (nested acquire) level */ }; --- linux-2.6.8-rc1/include/acpi/acmacros.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/acmacros.h 2004-07-13 17:09:17.649589728 -0700 @@ -53,6 +53,9 @@ #define ACPI_LOBYTE(l) ((u8)(u16)(l)) #define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) + #if ACPI_MACHINE_WIDTH == 16 @@ -97,7 +100,7 @@ * printf() format helpers */ -/* Split 64-bit integer into two 32-bit values. use with %8,8_x%8.8X */ +/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */ #define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i) --- linux-2.6.8-rc1/include/acpi/acnamesp.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acnamesp.h 2004-07-13 17:09:17.000000000 -0700 @@ -278,33 +278,25 @@ acpi_ns_dump_objects ( acpi_status acpi_ns_evaluate_by_handle ( - struct acpi_namespace_node *prefix_node, - union acpi_operand_object **params, - union acpi_operand_object **return_object); + struct acpi_parameter_info *info); acpi_status acpi_ns_evaluate_by_name ( char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object); + struct acpi_parameter_info *info); acpi_status acpi_ns_evaluate_relative ( - struct acpi_namespace_node *prefix_node, char *pathname, - union acpi_operand_object **params, - union acpi_operand_object **return_object); + struct acpi_parameter_info *info); acpi_status acpi_ns_execute_control_method ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc); + struct acpi_parameter_info *info); acpi_status acpi_ns_get_object_value ( - struct acpi_namespace_node *object_node, - union acpi_operand_object **return_obj_desc); + struct acpi_parameter_info *info); /* --- linux-2.6.8-rc1/include/acpi/acobject.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/acobject.h 2004-07-13 17:09:17.651589424 -0700 @@ -204,13 +204,14 @@ struct acpi_object_method struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER - u16 sync_level; - u16 acquisition_depth; - struct acpi_thread_state *owner_thread; - void *semaphore; + u8 sync_level; /* 0-15, specified in Mutex() call */ + u16 acquisition_depth; /* Allow multiple Acquires, same thread */ + struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ + void *semaphore; /* Actual OS synchronization object */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ + u8 original_sync_level; /* Owner's original sync level (0-15) */ }; @@ -220,7 +221,7 @@ struct acpi_object_region u8 space_id; union acpi_operand_object *handler; /* Handler for region access */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ union acpi_operand_object *next; u32 length; acpi_physical_address address; --- linux-2.6.8-rc1/include/acpi/acparser.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acparser.h 2004-07-13 17:09:17.000000000 -0700 @@ -73,9 +73,7 @@ acpi_psx_load_table ( acpi_status acpi_psx_execute ( - struct acpi_namespace_node *method_node, - union acpi_operand_object **params, - union acpi_operand_object **return_obj_desc); + struct acpi_parameter_info *info); /****************************************************************************** --- linux-2.6.8-rc1/include/acpi/acpixf.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/acpixf.h 2004-07-13 17:09:17.652589272 -0700 @@ -296,7 +296,7 @@ acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context); acpi_status @@ -312,7 +312,7 @@ acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler); + acpi_event_handler address); acpi_status acpi_enable_event ( @@ -334,6 +334,12 @@ acpi_get_event_status ( acpi_event_status *event_status); acpi_status +acpi_set_gpe_type ( + acpi_handle gpe_device, + u32 gpe_number, + u8 type); + +acpi_status acpi_enable_gpe ( acpi_handle gpe_device, u32 gpe_number, --- linux-2.6.8-rc1/include/acpi/acstruct.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/acstruct.h 2004-07-13 17:09:17.653589120 -0700 @@ -69,13 +69,14 @@ struct acpi_walk_state { u8 data_type; /* To differentiate various internal objs MUST BE FIRST!*/\ + u8 walk_type; acpi_owner_id owner_id; /* Owner of objects created during the walk */ u8 last_predicate; /* Result of last predicate */ + u8 reserved; /* For alignment */ u8 current_result; /* */ u8 next_op_info; /* Info about next_op */ u8 num_operands; /* Stack pointer for Operands[] array */ u8 return_used; - u8 walk_type; u16 opcode; /* Current AML opcode */ u8 scope_depth; u8 reserved1; @@ -91,7 +92,8 @@ struct acpi_walk_state struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ union acpi_operand_object **caller_return_desc; union acpi_generic_state *control_state; /* List of control states (nested IFs) */ - struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ struct acpi_namespace_node *method_call_node; /* Called method Node*/ union acpi_parse_object *method_call_op; /* method_call Op if running a method */ @@ -200,4 +202,21 @@ union acpi_aml_operands }; +/* Internal method parameter list */ + +struct acpi_parameter_info +{ + struct acpi_namespace_node *node; + union acpi_operand_object **parameters; + union acpi_operand_object *return_object; + u8 parameter_type; + u8 return_object_type; +}; + +/* Types for parameter_type above */ + +#define ACPI_PARAM_ARGS 0 +#define ACPI_PARAM_GPE 1 + + #endif --- linux-2.6.8-rc1/include/acpi/actbl.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/actbl.h 2004-07-13 17:09:17.653589120 -0700 @@ -288,19 +288,6 @@ struct smart_battery_table }; -/* - * High performance timer - */ -struct hpet_table -{ - ACPI_TABLE_HEADER_DEF - u32 hardware_id; - u32 base_address [3]; - u8 hpet_number; - u16 clock_tick; - u8 attributes; -}; - #pragma pack() @@ -344,4 +331,20 @@ struct acpi_table_support #include "actbl2.h" /* Acpi 2.0 table definitions */ +#pragma pack(1) +/* + * High performance timer + */ +struct hpet_table +{ + ACPI_TABLE_HEADER_DEF + u32 hardware_id; + struct acpi_generic_address base_address; + u8 hpet_number; + u16 clock_tick; + u8 attributes; +}; + +#pragma pack() + #endif /* __ACTBL_H__ */ --- linux-2.6.8-rc1/include/acpi/actypes.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/acpi/actypes.h 2004-07-13 17:09:17.655588816 -0700 @@ -557,34 +557,56 @@ typedef u32 #define ACPI_GPE_MAX 0xFF #define ACPI_NUM_GPE 256 +#define ACPI_GPE_ENABLE 0 +#define ACPI_GPE_DISABLE 1 + + /* * GPE info flags - Per GPE - * +---------+-+-+-+ - * |Bits 8:3 |2|1|0| - * +---------+-+-+-+ - * | | | | - * | | | +- Edge or Level Triggered - * | | +--- Type: Wake or Runtime - * | +----- Enabled for wake? - * +-------- - */ -#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 1 -#define ACPI_GPE_LEVEL_TRIGGERED (u8) 1 -#define ACPI_GPE_EDGE_TRIGGERED (u8) 0 - -#define ACPI_GPE_TYPE_MASK (u8) 2 -#define ACPI_GPE_TYPE_WAKE (u8) 2 -#define ACPI_GPE_TYPE_RUNTIME (u8) 0 /* Default */ - -#define ACPI_GPE_ENABLE_MASK (u8) 4 -#define ACPI_GPE_ENABLED (u8) 4 -#define ACPI_GPE_DISABLED (u8) 0 /* Default */ + * +-+-+-+---+---+-+ + * |7|6|5|4:3|2:1|0| + * +-+-+-+---+---+-+ + * | | | | | | + * | | | | | +--- Interrupt type: Edge or Level Triggered + * | | | | +--- Type: Wake-only, Runtime-only, or wake/runtime + * | | | +--- Type of dispatch -- to method, handler, or none + * | | +--- Enabled for runtime? + * | +--- Enabled for wake? + * +--- System state when GPE ocurred (running/waking) + */ +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01 +#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 + +#define ACPI_GPE_TYPE_MASK (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE_RUN (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE (u8) 0x02 +#define ACPI_GPE_TYPE_RUNTIME (u8) 0x04 /* Default */ + +#define ACPI_GPE_DISPATCH_MASK (u8) 0x18 +#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x08 +#define ACPI_GPE_DISPATCH_METHOD (u8) 0x10 +#define ACPI_GPE_DISPATCH_NOT_USED (u8) 0x00 /* Default */ + +#define ACPI_GPE_RUN_ENABLE_MASK (u8) 0x20 +#define ACPI_GPE_RUN_ENABLED (u8) 0x20 +#define ACPI_GPE_RUN_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_WAKE_ENABLE_MASK (u8) 0x40 +#define ACPI_GPE_WAKE_ENABLED (u8) 0x40 +#define ACPI_GPE_WAKE_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_ENABLE_MASK (u8) 0x60 /* Both run/wake */ + +#define ACPI_GPE_SYSTEM_MASK (u8) 0x80 +#define ACPI_GPE_SYSTEM_RUNNING (u8) 0x80 +#define ACPI_GPE_SYSTEM_WAKING (u8) 0x00 /* * Flags for GPE and Lock interfaces */ -#define ACPI_EVENT_WAKE_ENABLE 0x2 -#define ACPI_EVENT_WAKE_DISABLE 0x2 +#define ACPI_EVENT_WAKE_ENABLE 0x2 /* acpi_gpe_enable */ +#define ACPI_EVENT_WAKE_DISABLE 0x2 /* acpi_gpe_disable */ #define ACPI_NOT_ISR 0x1 #define ACPI_ISR 0x0 @@ -592,9 +614,10 @@ typedef u32 /* Notify types */ -#define ACPI_SYSTEM_NOTIFY 0 -#define ACPI_DEVICE_NOTIFY 1 -#define ACPI_MAX_NOTIFY_HANDLER_TYPE 1 +#define ACPI_SYSTEM_NOTIFY 0x1 +#define ACPI_DEVICE_NOTIFY 0x2 +#define ACPI_ALL_NOTIFY 0x3 +#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 #define ACPI_MAX_SYS_NOTIFY 0x7f @@ -790,10 +813,6 @@ u32 (*acpi_event_handler) ( void *context); typedef -void (*acpi_gpe_handler) ( - void *context); - -typedef void (*acpi_notify_handler) ( acpi_handle device, u32 value, @@ -880,6 +899,7 @@ struct acpi_compatible_id_list #define ACPI_VALID_HID 0x0004 #define ACPI_VALID_UID 0x0008 #define ACPI_VALID_CID 0x0010 +#define ACPI_VALID_SXDS 0x0020 #define ACPI_COMMON_OBJ_INFO \ @@ -899,12 +919,12 @@ struct acpi_device_info { ACPI_COMMON_OBJ_INFO; - u8 highest_dstates[4]; /* _sx_d values 0xFF indicates not valid */ u32 valid; /* Indicates which fields below are valid */ u32 current_status; /* _STA value */ acpi_integer address; /* _ADR value if any */ struct acpi_device_id hardware_id; /* _HID value if any */ struct acpi_device_id unique_id; /* _UID value if any */ + u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ struct acpi_compatible_id_list compatibility_id; /* List of _CIDs if any */ }; --- linux-2.6.8-rc1/include/acpi/platform/acenv.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/platform/acenv.h 2004-07-13 17:09:17.655588816 -0700 @@ -152,12 +152,8 @@ #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long - -/* Name of host operating system (returned by the _OS_ namespace object) */ - -#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" - -/* This macro is used to tag functions as "printf-like" because +/* + * This macro is used to tag functions as "printf-like" because * some compilers can catch printf format string problems. MSVC * doesn't, so this is proprocessed away. */ --- linux-2.6.8-rc1/include/acpi/platform/aclinux.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/acpi/platform/aclinux.h 2004-07-13 17:09:17.656588664 -0700 @@ -44,8 +44,6 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ -#define ACPI_OS_NAME "Linux" - #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 --- linux-2.6.8-rc1/include/asm-alpha/core_lca.h 2003-06-14 12:18:34.000000000 -0700 +++ 25/include/asm-alpha/core_lca.h 2004-07-13 17:09:13.000000000 -0700 @@ -136,7 +136,7 @@ #define LCA_PMR_DMAO 0x80 /* DMA override */ #define LCA_PMR_OCCEB 0xffff0000L /* Override cycle counter - even bits */ #define LCA_PMR_OCCOB 0xffff000000000000L /* Override cycle counter - even bits */ -#define LCA_PMR_PRIMARY_MASK 0xfffffffffffffff8 +#define LCA_PMR_PRIMARY_MASK 0xfffffffffffffff8L /* LCA PMR Macros */ --- linux-2.6.8-rc1/include/asm-alpha/fpu.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/include/asm-alpha/fpu.h 2004-07-13 17:09:13.000000000 -0700 @@ -27,7 +27,7 @@ #define FPCR_DYN_PLUS (0x3UL << FPCR_DYN_SHIFT) /* towards +INF */ #define FPCR_DYN_MASK (0x3UL << FPCR_DYN_SHIFT) -#define FPCR_MASK 0xffff800000000000 +#define FPCR_MASK 0xffff800000000000L /* * IEEE trap enables are implemented in software. These per-thread --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-alpha/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,84 @@ +/* + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Peter Rival (frival@zk3.dec.com) + */ + +#ifndef _ALPHA_LOCKMETER_H +#define _ALPHA_LOCKMETER_H + +#include +#define CPU_CYCLE_FREQUENCY hwrpb->cycle_freq + +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +#include + +#define SPINLOCK_MAGIC_INIT /**/ + +/* + * Macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * We also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + * Note: although these defines and macros are the same as what is being used + * in include/asm-i386/lockmeter.h, they are present here to easily + * allow an alternate Alpha implementation. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Alpha is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1) +#define IABS(x) ((x) > 0 ? (x) : -(x)) + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock; + /* readers subtract 2, so we have to: */ + /* - andnot off a possible writer (bit 0) */ + /* - get the absolute value */ + /* - divide by 2 (right shift by one) */ + /* to find the number of readers */ + if (tmp == 0) return(0); + else return(IABS(tmp & ~1)>>1); +} + +#endif /* _ALPHA_LOCKMETER_H */ --- linux-2.6.8-rc1/include/asm-alpha/pgalloc.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-alpha/pgalloc.h 2004-07-13 17:09:13.000000000 -0700 @@ -66,7 +66,7 @@ pte_alloc_one(struct mm_struct *mm, unsi pte_t *pte = pte_alloc_one_kernel(mm, addr); if (pte) return virt_to_page(pte); - return 0; + return NULL; } static inline void --- linux-2.6.8-rc1/include/asm-alpha/signal.h 2004-06-15 23:29:44.000000000 -0700 +++ 25/include/asm-alpha/signal.h 2004-07-13 17:09:13.000000000 -0700 @@ -128,7 +128,11 @@ typedef unsigned long sigset_t; #define SIG_SETMASK 3 /* for setting the signal mask */ /* Type of a signal handler. */ -typedef void (*__sighandler_t)(int); +typedef void __signalfn_t(int); +typedef __signalfn_t __user *__sighandler_t; + +typedef void __restorefn_t(void); +typedef __restorefn_t __user *__sigrestore_t; #define SIG_DFL ((__sighandler_t)0) /* default signal handling */ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ @@ -149,7 +153,7 @@ struct sigaction { struct k_sigaction { struct sigaction sa; - void (*ka_restorer)(void); + __sigrestore_t ka_restorer; }; #else /* Here we must cater to libcs that poke about in kernel headers. */ @@ -169,7 +173,7 @@ struct sigaction { #endif /* __KERNEL__ */ typedef struct sigaltstack { - void *ss_sp; + void __user *ss_sp; int ss_flags; size_t ss_size; } stack_t; @@ -179,7 +183,7 @@ typedef struct sigaltstack { implemented here for OSF/1 compatibility. */ struct sigstack { - void *ss_sp; + void __user *ss_sp; int ss_onstack; }; --- linux-2.6.8-rc1/include/asm-alpha/spinlock.h 2004-06-15 23:29:44.000000000 -0700 +++ 25/include/asm-alpha/spinlock.h 2004-07-13 17:09:29.000000000 -0700 @@ -6,6 +6,10 @@ #include #include +#ifdef CONFIG_LOCKMETER +#undef DEBUG_SPINLOCK +#undef DEBUG_RWLOCK +#endif /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -26,9 +30,9 @@ typedef struct { } spinlock_t; #ifdef CONFIG_DEBUG_SPINLOCK -#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, 0, 0, 0} +#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, NULL, NULL, NULL} #define spin_lock_init(x) \ - ((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = 0, (x)->task = 0) + ((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = NULL, (x)->task = NULL) #else #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(x) ((x)->lock = 0) @@ -96,9 +100,18 @@ static inline int _raw_spin_trylock(spin typedef struct { volatile int write_lock:1, read_counter:31; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* need this storage for CPU and lock INDEX ............. */ + unsigned magic; +#endif } /*__attribute__((aligned(32)))*/ rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *)(x) != 0) @@ -170,4 +183,41 @@ static inline void _raw_read_unlock(rwlo : "m" (*lock) : "memory"); } +#ifdef CONFIG_LOCKMETER +static inline int _raw_write_trylock(rwlock_t *lock) +{ + long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " bne %1,1f\n" + " or $31,1,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + + return (result); +} + +static inline int _raw_read_trylock(rwlock_t *lock) +{ + unsigned long temp,result; + + __asm__ __volatile__( + " ldl_l %1,%0\n" + " mov $31,%2\n" + " blbs %1,1f\n" + " subl %1,2,%2\n" + " stl_c %2,%0\n" + "1: mb\n" + : "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result) + : "m" (*(volatile int *)lock) + ); + return (result); +} +#endif /* CONFIG_LOCKMETER */ + #endif /* _ALPHA_SPINLOCK_H */ --- linux-2.6.8-rc1/include/asm-alpha/topology.h 2004-02-17 20:48:46.000000000 -0800 +++ 25/include/asm-alpha/topology.h 2004-07-13 17:09:13.000000000 -0700 @@ -22,17 +22,17 @@ static inline int cpu_to_node(int cpu) return node; } -static inline int node_to_cpumask(int node) +static inline cpumask_t node_to_cpumask(int node) { - unsigned long node_cpu_mask = 0; + cpumask_t node_cpu_mask = CPU_MASK_NONE; int cpu; for(cpu = 0; cpu < NR_CPUS; cpu++) { if (cpu_online(cpu) && (cpu_to_node(cpu) == node)) - node_cpu_mask |= 1UL << cpu; + cpu_set(cpu, node_cpu_mask); } -#if DEBUG_NUMA +#ifdef DEBUG_NUMA printk("node %d: cpu_mask: %016lx\n", node, node_cpu_mask); #endif @@ -42,6 +42,8 @@ static inline int node_to_cpumask(int no /* Cross-node load balancing interval. */ # define NODE_BALANCE_RATE 10 +#define pcibus_to_cpumask(bus) (cpu_online_map) + #else /* CONFIG_NUMA */ # include #endif /* !CONFIG_NUMA */ --- linux-2.6.8-rc1/include/asm-alpha/uaccess.h 2004-06-15 23:29:44.000000000 -0700 +++ 25/include/asm-alpha/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -29,15 +29,6 @@ #define segment_eq(a,b) ((a).seg == (b).seg) -#ifdef __CHECKER__ -#define CHECK_UPTR(ptr) do { \ - __typeof__(*(ptr)) *__dummy_check_uptr = \ - (void __user *)&__dummy_check_uptr; \ -} while(0) -#else -#define CHECK_UPTR(ptr) -#endif - /* * Is a address valid? This does a straightforward calculation rather * than tests. @@ -53,7 +44,7 @@ #define access_ok(type,addr,size) \ ({ \ - CHECK_UPTR(addr); \ + __chk_user_ptr(addr); \ __access_ok(((unsigned long)(addr)),(size),get_fs()); \ }) @@ -101,7 +92,7 @@ extern void __get_user_unknown(void); #define __get_user_nocheck(x,ptr,size) \ ({ \ long __gu_err = 0, __gu_val; \ - CHECK_UPTR(ptr); \ + __chk_user_ptr(ptr); \ switch (size) { \ case 1: __get_user_8(ptr); break; \ case 2: __get_user_16(ptr); break; \ @@ -113,23 +104,23 @@ extern void __get_user_unknown(void); __gu_err; \ }) -#define __get_user_check(x,ptr,size,segment) \ -({ \ - long __gu_err = -EFAULT, __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - CHECK_UPTR(ptr); \ - if (__access_ok((long)__gu_addr,size,segment)) { \ - __gu_err = 0; \ - switch (size) { \ - case 1: __get_user_8(__gu_addr); break; \ - case 2: __get_user_16(__gu_addr); break; \ - case 4: __get_user_32(__gu_addr); break; \ - case 8: __get_user_64(__gu_addr); break; \ - default: __get_user_unknown(); break; \ - } \ - } \ - (x) = (__typeof__(*(ptr))) __gu_val; \ - __gu_err; \ +#define __get_user_check(x,ptr,size,segment) \ +({ \ + long __gu_err = -EFAULT, __gu_val = 0; \ + const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + __chk_user_ptr(ptr); \ + if (__access_ok((unsigned long)__gu_addr,size,segment)) { \ + __gu_err = 0; \ + switch (size) { \ + case 1: __get_user_8(__gu_addr); break; \ + case 2: __get_user_16(__gu_addr); break; \ + case 4: __get_user_32(__gu_addr); break; \ + case 8: __get_user_64(__gu_addr); break; \ + default: __get_user_unknown(); break; \ + } \ + } \ + (x) = (__typeof__(*(ptr))) __gu_val; \ + __gu_err; \ }) struct __large_struct { unsigned long buf[100]; }; @@ -217,7 +208,7 @@ extern void __put_user_unknown(void); #define __put_user_nocheck(x,ptr,size) \ ({ \ long __pu_err = 0; \ - CHECK_UPTR(ptr); \ + __chk_user_ptr(ptr); \ switch (size) { \ case 1: __put_user_8(x,ptr); break; \ case 2: __put_user_16(x,ptr); break; \ @@ -228,22 +219,22 @@ extern void __put_user_unknown(void); __pu_err; \ }) -#define __put_user_check(x,ptr,size,segment) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) *__pu_addr = (ptr); \ - CHECK_UPTR(ptr); \ - if (__access_ok((long)__pu_addr,size,segment)) { \ - __pu_err = 0; \ - switch (size) { \ - case 1: __put_user_8(x,__pu_addr); break; \ - case 2: __put_user_16(x,__pu_addr); break; \ - case 4: __put_user_32(x,__pu_addr); break; \ - case 8: __put_user_64(x,__pu_addr); break; \ - default: __put_user_unknown(); break; \ - } \ - } \ - __pu_err; \ +#define __put_user_check(x,ptr,size,segment) \ +({ \ + long __pu_err = -EFAULT; \ + __typeof__(*(ptr)) *__pu_addr = (ptr); \ + __chk_user_ptr(ptr); \ + if (__access_ok((unsigned long)__pu_addr,size,segment)) { \ + __pu_err = 0; \ + switch (size) { \ + case 1: __put_user_8(x,__pu_addr); break; \ + case 2: __put_user_16(x,__pu_addr); break; \ + case 4: __put_user_32(x,__pu_addr); break; \ + case 8: __put_user_64(x,__pu_addr); break; \ + default: __put_user_unknown(); break; \ + } \ + } \ + __pu_err; \ }) /* @@ -388,32 +379,36 @@ __copy_tofrom_user_nocheck(void *to, con extern inline long __copy_tofrom_user(void *to, const void *from, long len, const void __user *validate) { - if (__access_ok((long)validate, len, get_fs())) + if (__access_ok((unsigned long)validate, len, get_fs())) len = __copy_tofrom_user_nocheck(to, from, len); return len; } -#define __copy_to_user(to,from,n) \ -({ \ - CHECK_UPTR(to); \ - __copy_tofrom_user_nocheck((void *)(to),(from),(n)); \ +#define __copy_to_user(to,from,n) \ +({ \ + __chk_user_ptr(to); \ + __copy_tofrom_user_nocheck((__force void *)(to),(from),(n)); \ }) -#define __copy_from_user(to,from,n) \ -({ \ - CHECK_UPTR(from); \ - __copy_tofrom_user_nocheck((to),(void *)(from),(n)); \ +#define __copy_from_user(to,from,n) \ +({ \ + __chk_user_ptr(from); \ + __copy_tofrom_user_nocheck((to),(__force void *)(from),(n)); \ }) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + + extern inline long copy_to_user(void __user *to, const void *from, long n) { - return __copy_tofrom_user((void *)to, from, n, to); + return __copy_tofrom_user((__force void *)to, from, n, to); } extern inline long copy_from_user(void *to, const void __user *from, long n) { - return __copy_tofrom_user(to, (void *)from, n, from); + return __copy_tofrom_user(to, (__force void *)from, n, from); } extern void __do_clear_user(void); @@ -435,7 +430,7 @@ __clear_user(void __user *to, long len) extern inline long clear_user(void __user *to, long len) { - if (__access_ok((long)to, len, get_fs())) + if (__access_ok((unsigned long)to, len, get_fs())) len = __clear_user(to, len); return len; } @@ -452,7 +447,7 @@ extern inline long strncpy_from_user(char *to, const char __user *from, long n) { long ret = -EFAULT; - if (__access_ok((long)from, 0, get_fs())) + if (__access_ok((unsigned long)from, 0, get_fs())) ret = __strncpy_from_user(to, from, n); return ret; } --- linux-2.6.8-rc1/include/asm-arm26/uaccess.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/include/asm-arm26/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -217,6 +217,9 @@ static __inline__ unsigned long __copy_t return n; } +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + static __inline__ unsigned long clear_user (void *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) --- linux-2.6.8-rc1/include/asm-arm/arch-s3c2410/regs-serial.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-arm/arch-s3c2410/regs-serial.h 2004-07-13 17:09:13.000000000 -0700 @@ -106,8 +106,23 @@ /* fifo size information */ -#define S3C2410_UFCON_RXC(fcon) (((fcon) & S3C2410_UFSTAT_RXMASK) >> S3C2410_UFSTAT_RXSHIFT) -#define S3C2410_UFCON_TXC(fcon) (((fcon) & S3C2410_UFSTAT_TXMASK) >> S3C2410_UFSTAT_TXSHIFT) +#ifndef __ASSEMBLY__ +static inline int S3C2410_UFCON_RXC(int fcon) +{ + if (fcon & S3C2410_UFSTAT_RXFULL) + return 16; + + return ((fcon) & S3C2410_UFSTAT_RXMASK) >> S3C2410_UFSTAT_RXSHIFT; +} + +static inline int S3C2410_UFCON_TXC(int fcon) +{ + if (fcon & S3C2410_UFSTAT_TXFULL) + return 16; + + return ((fcon) & S3C2410_UFSTAT_TXMASK) >> S3C2410_UFSTAT_TXSHIFT; +} +#endif /* __ASSEMBLY__ */ #define S3C2410_UMSTAT_CTS (1<<0) #define S3C2410_UMSTAT_DeltaCTS (1<<2) --- linux-2.6.8-rc1/include/asm-arm/cacheflush.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-arm/cacheflush.h 2004-07-13 17:09:26.000000000 -0700 @@ -294,9 +294,9 @@ flush_cache_page(struct vm_area_struct * extern void flush_dcache_page(struct page *); #define flush_dcache_mmap_lock(mapping) \ - spin_lock_irq(&(mapping)->tree_lock) + write_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \ - spin_unlock_irq(&(mapping)->tree_lock) + write_unlock_irq(&(mapping)->tree_lock) #define flush_icache_user_range(vma,page,addr,len) \ flush_dcache_page(page) --- linux-2.6.8-rc1/include/asm-arm/uaccess.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-arm/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -391,6 +391,9 @@ static inline unsigned long __copy_to_us return __arch_copy_to_user(to, from, n); } +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + static inline unsigned long clear_user (void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) --- linux-2.6.8-rc1/include/asm-cris/uaccess.h 2003-07-10 18:50:32.000000000 -0700 +++ 25/include/asm-cris/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -434,6 +434,8 @@ __generic_clear_user_nocheck(void *to, u #define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n)) #define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user #define __clear_user(to,n) __generic_clear_user_nocheck((to),(n)) #define strlen_user(str) strnlen_user((str), 0x7ffffffe) --- linux-2.6.8-rc1/include/asm-generic/pgtable.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-generic/pgtable.h 2004-07-13 17:09:51.000000000 -0700 @@ -122,4 +122,8 @@ static inline void ptep_mkdirty(pte_t *p #define page_test_and_clear_young(page) (0) #endif +#ifndef __HAVE_ARCH_PGD_OFFSET_GATE +#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) +#endif + #endif /* _ASM_GENERIC_PGTABLE_H */ --- linux-2.6.8-rc1/include/asm-generic/siginfo.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-generic/siginfo.h 2004-07-13 17:09:13.633200312 -0700 @@ -6,7 +6,7 @@ typedef union sigval { int sival_int; - void *sival_ptr; + void __user *sival_ptr; } sigval_t; /* @@ -78,7 +78,7 @@ typedef struct siginfo { /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ struct { - void *_addr; /* faulting insn/memory ref. */ + void __user *_addr; /* faulting insn/memory ref. */ #ifdef __ARCH_SI_TRAPNO int _trapno; /* TRAP # which caused the signal */ #endif --- linux-2.6.8-rc1/include/asm-generic/tlb.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-generic/tlb.h 2004-07-13 17:09:13.633200312 -0700 @@ -147,4 +147,6 @@ static inline void tlb_remove_page(struc __pmd_free_tlb(tlb, pmdp); \ } while (0) +#define tlb_migrate_finish(mm) do {} while (0) + #endif /* _ASM_GENERIC__TLB_H */ --- linux-2.6.8-rc1/include/asm-h8300/uaccess.h 2003-08-08 22:55:13.000000000 -0700 +++ 25/include/asm-h8300/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -123,6 +123,8 @@ extern int __get_user_bad(void); #define __copy_from_user(to, from, n) copy_from_user(to, from, n) #define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user #define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) --- linux-2.6.8-rc1/include/asm-i386/bugs.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/bugs.h 2004-07-13 17:09:25.757357160 -0700 @@ -1,11 +1,11 @@ /* * include/asm-i386/bugs.h * - * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 1994 Linus Torvalds * * Cyrix stuff, June 1998 by: * - Rafael R. Reilova (moved everything from head.S), - * + * * - Channing Corn (tests & fixes), * - Andrew D. Balsa (code cleanup). * @@ -25,7 +25,20 @@ #include #include #include - +#ifdef CONFIG_KGDB +/* + * Provied the command line "gdb" initial break + */ +int __init kgdb_initial_break(char * str) +{ + if (*str == '\0'){ + breakpoint(); + return 1; + } + return 0; +} +__setup("gdb",kgdb_initial_break); +#endif static int __init no_halt(char *s) { boot_cpu_data.hlt_works_ok = 0; @@ -140,7 +153,7 @@ static void __init check_popad(void) : "ecx", "edi" ); /* If this fails, it means that any user program may lock the CPU hard. Too bad. */ if (res != 12345678) printk( "Buggy.\n" ); - else printk( "OK.\n" ); + else printk( "OK.\n" ); #endif } --- linux-2.6.8-rc1/include/asm-i386/checksum.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/checksum.h 2004-07-13 17:09:51.000000000 -0700 @@ -46,6 +46,7 @@ static __inline__ unsigned int csum_partial_copy_from_user ( const char *src, char *dst, int len, int sum, int *err_ptr) { + might_sleep(); return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL); } @@ -177,6 +178,7 @@ static __inline__ unsigned int csum_and_ int len, int sum, int *err_ptr) { + might_sleep(); if (access_ok(VERIFY_WRITE, dst, len)) return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); --- linux-2.6.8-rc1/include/asm-i386/desc.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/desc.h 2004-07-13 17:09:52.000000000 -0700 @@ -8,10 +8,12 @@ #include #include +#include #include -extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES]; +extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +DECLARE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]); struct Xgt_desc_struct { unsigned short size; @@ -44,7 +46,7 @@ __asm__ __volatile__ ("movw %w3,0(%2)\n\ static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr) { - _set_tssldt_desc(&cpu_gdt_table[cpu][entry], (int)addr, + _set_tssldt_desc(&per_cpu(cpu_gdt_table, cpu)[entry], (int)addr, offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89); } @@ -52,7 +54,7 @@ static inline void __set_tss_desc(unsign static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size) { - _set_tssldt_desc(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82); + _set_tssldt_desc(&per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82); } #define LDT_entry_a(info) \ @@ -86,7 +88,7 @@ static inline void set_ldt_desc(unsigned static inline void load_TLS(struct thread_struct *t, unsigned int cpu) { -#define C(i) cpu_gdt_table[cpu][GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] +#define C(i) per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i] C(0); C(1); C(2); #undef C } --- linux-2.6.8-rc1/include/asm-i386/dma-mapping.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/dma-mapping.h 2004-07-13 17:09:21.009079008 -0700 @@ -163,4 +163,16 @@ dma_cache_sync(void *vaddr, size_t size, flush_write_buffers(); } +#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY +extern int +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags); + +extern void +dma_release_declared_memory(struct device *dev); + +extern void * +dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size); + #endif --- linux-2.6.8-rc1/include/asm-i386/elf.h 2003-10-08 15:07:10.000000000 -0700 +++ 25/include/asm-i386/elf.h 2004-07-13 17:09:38.549412472 -0700 @@ -117,7 +117,7 @@ typedef struct user_fxsr_struct elf_fpxr #define AT_SYSINFO_EHDR 33 #ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#define SET_PERSONALITY(ex, ibcs2) do { } while (0) extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); --- linux-2.6.8-rc1/include/asm-i386/fixmap.h 2004-03-10 20:41:30.000000000 -0800 +++ 25/include/asm-i386/fixmap.h 2004-07-13 17:09:53.780097056 -0700 @@ -125,7 +125,7 @@ extern void __this_fixmap_does_not_exist * directly without tranlation, we catch the bug with a NULL-deference * kernel oops. Illegal ranges of incoming indices are caught too. */ -static inline unsigned long fix_to_virt(const unsigned int idx) +static __always_inline unsigned long fix_to_virt(const unsigned int idx) { /* * this branch gets completely eliminated after inlining, --- linux-2.6.8-rc1/include/asm-i386/hw_irq.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-i386/hw_irq.h 2004-07-13 17:09:50.000000000 -0700 @@ -68,27 +68,13 @@ extern atomic_t irq_mis_count; #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs)) -/* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ -static inline void x86_do_profile(struct pt_regs * regs) +static inline void __do_profile(unsigned long eip) { - unsigned long eip; extern unsigned long prof_cpu_mask; - profile_hook(regs); - - if (user_mode(regs)) - return; - if (!prof_buffer) return; - eip = regs->eip; - /* * Only measure the CPUs specified by /proc/irq/prof_cpu_mask. * (default is all CPUs.) @@ -108,6 +94,24 @@ static inline void x86_do_profile(struct atomic_inc((atomic_t *)&prof_buffer[eip]); } +#define kern_profile(eip) __do_profile(eip) + +/* + * The profiling function is SMP safe. (nothing can mess + * around with "current", and the profiling counters are + * updated with atomic operations). This is especially + * useful with a profiling multiplier != 1 + */ +static inline void x86_do_profile(struct pt_regs * regs) +{ + profile_hook(regs); + + if (prof_on != 1 || user_mode(regs)) + return; + + __do_profile(regs->eip); +} + #if defined(CONFIG_X86_IO_APIC) static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-i386/kgdb.h 2004-07-13 17:09:26.097305480 -0700 @@ -0,0 +1,69 @@ +#ifndef __KGDB +#define __KGDB + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) + +extern void breakpoint(void); +#define INIT_KGDB_INTS kgdb_enable_ints() + +#ifndef BREAKPOINT +#define BREAKPOINT asm(" int $3") +#endif + +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); + +extern int kgdb_tty_hook(void); +extern int kgdb_eth_hook(void); +extern int kgdboe; + +/* + * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' + * pointer to its routine and it will be entered as the first thing + * when a trap occurs. + * + * Return values are, at present, undefined. + * + * The debug hook routine does not necessarily return to its caller. + * It has the register image and thus may choose to resume execution + * anywhere it pleases. + */ +struct pt_regs; + +extern int kgdb_handle_exception(int trapno, + int signo, int err_code, struct pt_regs *regs); +extern int in_kgdb(struct pt_regs *regs); + +#ifdef CONFIG_KGDB_TS +void kgdb_tstamp(int line, char *source, int data0, int data1); +/* + * This is the time stamp function. The macro adds the source info and + * does a cast on the data to allow most any 32-bit value. + */ + +#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1) +#else +#define kgdb_ts(data0,data1) +#endif +#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ +#ifndef BREAKPOINT +#define BREAKPOINT +#endif +#define kgdb_ts(data0,data1) +#define in_kgdb +#define kgdb_handle_exception +#define breakpoint +#define INIT_KGDB_INTS +#define kgdb_process_breakpoint() do {} while(0) + +#endif +#endif /* __KGDB */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-i386/kgdb_local.h 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,102 @@ +#ifndef __KGDB_LOCAL +#define ___KGDB_LOCAL +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 0x3f8 +#ifdef CONFIG_KGDB_PORT +#undef PORT +#define PORT CONFIG_KGDB_PORT +#endif +#define IRQ 4 +#ifdef CONFIG_KGDB_IRQ +#undef IRQ +#define IRQ CONFIG_KGDB_IRQ +#endif +#define SB_CLOCK 1843200 +#define SB_BASE (SB_CLOCK/16) +#define SB_BAUD9600 SB_BASE/9600 +#define SB_BAUD192 SB_BASE/19200 +#define SB_BAUD384 SB_BASE/38400 +#define SB_BAUD576 SB_BASE/57600 +#define SB_BAUD1152 SB_BASE/115200 +#ifdef CONFIG_KGDB_9600BAUD +#define SB_BAUD SB_BAUD9600 +#endif +#ifdef CONFIG_KGDB_19200BAUD +#define SB_BAUD SB_BAUD192 +#endif +#ifdef CONFIG_KGDB_38400BAUD +#define SB_BAUD SB_BAUD384 +#endif +#ifdef CONFIG_KGDB_57600BAUD +#define SB_BAUD SB_BAUD576 +#endif +#ifdef CONFIG_KGDB_115200BAUD +#define SB_BAUD SB_BAUD1152 +#endif +#ifndef SB_BAUD +#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ +#endif + +#ifndef CONFIG_X86_TSC +#undef rdtsc +#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;} +#undef rdtscll +#define rdtscll(s) s++ +#endif + +#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#define spin_lock _raw_spin_lock +#define spin_trylock _raw_spin_trylock +#define spin_unlock _raw_spin_unlock +#else +#endif +#undef spin_unlock_wait +#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ + while(spin_is_locked(x)) + +#define SB_IER 1 +#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS + +#define FLAGS 0 +#define SB_STATE { \ + magic: SSTATE_MAGIC, \ + baud_base: SB_BASE, \ + port: PORT, \ + irq: IRQ, \ + flags: FLAGS, \ + custom_divisor:SB_BAUD} +#define SB_INFO { \ + magic: SERIAL_MAGIC, \ + port: PORT,0,FLAGS, \ + state: &state, \ + tty: (struct tty_struct *)&state, \ + IER: SB_IER, \ + MCR: SB_MCR} +extern void putDebugChar(int); +/* RTAI support needs us to really stop/start interrupts */ + +#define kgdb_sti() __asm__ __volatile__("sti": : :"memory") +#define kgdb_cli() __asm__ __volatile__("cli": : :"memory") +#define kgdb_local_save_flags(x) __asm__ __volatile__(\ + "pushfl ; popl %0":"=g" (x): /* no input */) +#define kgdb_local_irq_restore(x) __asm__ __volatile__(\ + "pushl %0 ; popfl": \ + /* no output */ :"g" (x):"memory", "cc") +#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli() + +#ifdef CONFIG_SERIAL +extern void shutdown_for_kgdb(struct async_struct *info); +#endif +#define INIT_KDEBUG putDebugChar("+"); +#endif /* __KGDB_LOCAL */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-i386/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,115 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks. + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code here from include/lockmeter.h. + * + */ + +#ifndef _I386_LOCKMETER_H +#define _I386_LOCKMETER_H + +#include +#include + +#include + +#ifdef __KERNEL__ +extern unsigned long cpu_khz; +#define CPU_CYCLE_FREQUENCY (cpu_khz * 1000) +#else +#define CPU_CYCLE_FREQUENCY 450000000 +#endif + +#define THIS_CPU_NUMBER smp_processor_id() + +/* + * macros to cache and retrieve an index value inside of a spin lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. Not normally a problem!! + * we also assume that the hash table has less than 65535 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + unsigned short lock; + unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + /* read and write lock attempts may cause the lock value to temporarily */ + /* be negative. Until it is >= 0 we know nothing (i. e. can't tell if */ + /* is -1 because it was write locked and somebody tried to read lock it */ + /* or if it is -1 because it was read locked and somebody tried to write*/ + /* lock it. ........................................................... */ + do { + tmp = (int) rwlock_ptr->lock; + } while (tmp < 0); + if (tmp == 0) return(0); + else return(RW_LOCK_BIAS-tmp); +} + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0) +#define IABS(x) ((x) > 0 ? (x) : -(x)) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0) + +/* this is a lot of typing just to get gcc to emit "rdtsc" */ +static inline long long get_cycles64 (void) +{ + union longlong_u { + long long intlong; + struct intint_s { + uint32_t eax; + uint32_t edx; + } intint; + } longlong; + + rdtsc(longlong.intint.eax,longlong.intint.edx); + return longlong.intlong; +} + +#endif /* _I386_LOCKMETER_H */ --- linux-2.6.8-rc1/include/asm-i386/mach-default/irq_vectors.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-i386/mach-default/irq_vectors.h 2004-07-13 17:09:34.043097536 -0700 @@ -56,14 +56,15 @@ * sources per level' errata. */ #define LOCAL_TIMER_VECTOR 0xef +#define LOCAL_PERFCTR_VECTOR 0xee /* - * First APIC vector available to drivers: (vectors 0x30-0xee) + * First APIC vector available to drivers: (vectors 0x30-0xed) * we start at 0x31 to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 -#define FIRST_SYSTEM_VECTOR 0xef +#define FIRST_SYSTEM_VECTOR 0xee #define TIMER_IRQ 0 --- linux-2.6.8-rc1/include/asm-i386/mach-visws/irq_vectors.h 2004-01-09 00:04:32.000000000 -0800 +++ 25/include/asm-i386/mach-visws/irq_vectors.h 2004-07-13 17:09:34.000000000 -0700 @@ -35,14 +35,15 @@ * sources per level' errata. */ #define LOCAL_TIMER_VECTOR 0xef +#define LOCAL_PERFCTR_VECTOR 0xee /* - * First APIC vector available to drivers: (vectors 0x30-0xee) + * First APIC vector available to drivers: (vectors 0x30-0xed) * we start at 0x31 to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 -#define FIRST_SYSTEM_VECTOR 0xef +#define FIRST_SYSTEM_VECTOR 0xee #define TIMER_IRQ 0 --- linux-2.6.8-rc1/include/asm-i386/mmu_context.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/mmu_context.h 2004-07-13 17:09:52.000000000 -0700 @@ -18,8 +18,8 @@ static inline void enter_lazy_tlb(struct { #ifdef CONFIG_SMP unsigned cpu = smp_processor_id(); - if (cpu_tlbstate[cpu].state == TLBSTATE_OK) - cpu_tlbstate[cpu].state = TLBSTATE_LAZY; + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) + per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_LAZY; #endif } @@ -33,8 +33,8 @@ static inline void switch_mm(struct mm_s /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); #ifdef CONFIG_SMP - cpu_tlbstate[cpu].state = TLBSTATE_OK; - cpu_tlbstate[cpu].active_mm = next; + per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; + per_cpu(cpu_tlbstate, cpu).active_mm = next; #endif cpu_set(cpu, next->cpu_vm_mask); @@ -49,8 +49,8 @@ static inline void switch_mm(struct mm_s } #ifdef CONFIG_SMP else { - cpu_tlbstate[cpu].state = TLBSTATE_OK; - BUG_ON(cpu_tlbstate[cpu].active_mm != next); + per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; + BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { /* We were in lazy tlb mode and leave_mm disabled --- linux-2.6.8-rc1/include/asm-i386/mtrr.h 2003-06-14 12:18:09.000000000 -0700 +++ 25/include/asm-i386/mtrr.h 2004-07-13 17:09:54.000000000 -0700 @@ -67,8 +67,6 @@ struct mtrr_gentry #ifdef __KERNEL__ -extern char *mtrr_strings[]; - /* The following functions are for use by other drivers */ # ifdef CONFIG_MTRR extern int mtrr_add (unsigned long base, unsigned long size, --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-i386/perfctr.h 2004-07-13 17:09:35.126932768 -0700 @@ -0,0 +1,188 @@ +/* $Id: perfctr.h,v 1.52 2004/05/23 22:36:34 mikpe Exp $ + * x86/x86_64 Performance-Monitoring Counters driver + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#ifndef _ASM_I386_PERFCTR_H +#define _ASM_I386_PERFCTR_H + +/* cpu_type values */ +#define PERFCTR_X86_GENERIC 0 /* any x86 with rdtsc */ +#define PERFCTR_X86_INTEL_P5 1 /* no rdpmc */ +#define PERFCTR_X86_INTEL_P5MMX 2 +#define PERFCTR_X86_INTEL_P6 3 +#define PERFCTR_X86_INTEL_PII 4 +#define PERFCTR_X86_INTEL_PIII 5 +#define PERFCTR_X86_CYRIX_MII 6 +#define PERFCTR_X86_WINCHIP_C6 7 /* no rdtsc */ +#define PERFCTR_X86_WINCHIP_2 8 /* no rdtsc */ +#define PERFCTR_X86_AMD_K7 9 +#define PERFCTR_X86_VIA_C3 10 /* no pmc0 */ +#define PERFCTR_X86_INTEL_P4 11 /* model 0 and 1 */ +#define PERFCTR_X86_INTEL_P4M2 12 /* model 2 */ +#define PERFCTR_X86_AMD_K8 13 +#define PERFCTR_X86_INTEL_PENTM 14 /* Pentium M */ +#define PERFCTR_X86_AMD_K8C 15 /* Revision C */ +#define PERFCTR_X86_INTEL_P4M3 16 /* model 3 and above */ + +struct perfctr_sum_ctrs { + unsigned long long tsc; + unsigned long long pmc[18]; +}; + +struct perfctr_cpu_control { + unsigned int tsc_on; + unsigned int nractrs; /* # of a-mode counters */ + unsigned int nrictrs; /* # of i-mode counters */ + unsigned int pmc_map[18]; + unsigned int evntsel[18]; /* one per counter, even on P5 */ + struct { + unsigned int escr[18]; + unsigned int pebs_enable; /* for replay tagging */ + unsigned int pebs_matrix_vert; /* for replay tagging */ + } p4; + int ireset[18]; /* < 0, for i-mode counters */ + unsigned int _reserved1; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +struct perfctr_cpu_state { + unsigned int cstatus; + struct { /* k1 is opaque in the user ABI */ + unsigned int id; + int isuspend_cpu; + } k1; + /* The two tsc fields must be inlined. Placing them in a + sub-struct causes unwanted internal padding on x86-64. */ + unsigned int tsc_start; + unsigned long long tsc_sum; + struct { + unsigned int map; + unsigned int start; + unsigned long long sum; + } pmc[18]; /* the size is not part of the user ABI */ +#ifdef __KERNEL__ + struct perfctr_cpu_control control; + unsigned int p4_escr_map[18]; +#endif +}; + +/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs + which should have less overhead in most cases */ + +static inline +unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs, + unsigned int nrictrs) +{ + return (tsc_on<<31) | (nrictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs; +} + +static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus) +{ + return cstatus; +} + +static inline int perfctr_cstatus_has_tsc(unsigned int cstatus) +{ + return (int)cstatus < 0; /* test and jump on sign */ +} + +static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus) +{ + return cstatus & 0x7F; /* and with imm8 */ +} + +static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus) +{ + return (cstatus >> 8) & 0x7F; +} + +static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus) +{ + return cstatus & (0x7F << 16); +} + +/* + * 'struct siginfo' support for perfctr overflow signals. + * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask + * describing which perfctrs overflowed is put in si_pmc_ovf_mask. + * A bitmask is used since more than one perfctr can have overflowed + * by the time the interrupt handler runs. + * + * glibc's doesn't seem to define __SI_FAULT or __SI_CODE(), + * and including as well may cause redefinition errors, + * so the user and kernel values are different #defines here. + */ +#ifdef __KERNEL__ +#define SI_PMC_OVF (__SI_FAULT|'P') +#else +#define SI_PMC_OVF ('P') +#endif +#define si_pmc_ovf_mask _sifields._pad[0] /* XXX: use an unsigned field later */ + +/* version number for user-visible CPU-specific data */ +#define PERFCTR_CPU_VERSION 0x0500 /* 5.0 */ + +#ifdef __KERNEL__ + +#if defined(CONFIG_PERFCTR) + +/* Driver init/exit. */ +extern int perfctr_cpu_init(void); +extern void perfctr_cpu_exit(void); + +/* CPU type name. */ +extern char *perfctr_cpu_name; + +/* Hardware reservation. */ +extern const char *perfctr_cpu_reserve(const char *service); +extern void perfctr_cpu_release(const char *service); + +/* PRE: state has no running interrupt-mode counters. + Check that the new control data is valid. + Update the driver's private control data. + is_global should be zero for per-process counters and non-zero + for global-mode counters. This matters for HT P4s, alas. + Returns a negative error code if the control data is invalid. */ +extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global); + +/* Read a-mode counters. Subtract from start and accumulate into sums. + Must be called with preemption disabled. */ +extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state); + +/* Write control registers. Read a-mode counters into start. + Must be called with preemption disabled. */ +extern void perfctr_cpu_resume(struct perfctr_cpu_state *state); + +/* Perform an efficient combined suspend/resume operation. + Must be called with preemption disabled. */ +extern void perfctr_cpu_sample(struct perfctr_cpu_state *state); + +/* The type of a perfctr overflow interrupt handler. + It will be called in IRQ context, with preemption disabled. */ +typedef void (*perfctr_ihandler_t)(unsigned long pc); + +/* Operations related to overflow interrupt handling. */ +#ifdef CONFIG_X86_LOCAL_APIC +extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t); +extern void perfctr_cpu_ireload(struct perfctr_cpu_state*); +extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*); +#else +static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { } +#endif + +#endif /* CONFIG_PERFCTR */ + +#if defined(CONFIG_PERFCTR) && defined(CONFIG_X86_LOCAL_APIC) +asmlinkage void perfctr_interrupt(struct pt_regs*); +#define perfctr_vector_init() \ + set_intr_gate(LOCAL_PERFCTR_VECTOR, perfctr_interrupt) +#else +#define perfctr_vector_init() do{}while(0) +#endif + +#endif /* __KERNEL__ */ + +#endif /* _ASM_I386_PERFCTR_H */ --- linux-2.6.8-rc1/include/asm-i386/processor.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/processor.h 2004-07-13 17:09:52.535286296 -0700 @@ -19,6 +19,7 @@ #include #include #include +#include /* flag for disabling the tsc */ extern int tsc_disable; @@ -84,8 +85,8 @@ struct cpuinfo_x86 { extern struct cpuinfo_x86 boot_cpu_data; extern struct cpuinfo_x86 new_cpu_data; -extern struct tss_struct init_tss[NR_CPUS]; extern struct tss_struct doublefault_tss; +DECLARE_PER_CPU(struct tss_struct, init_tss); #ifdef CONFIG_SMP extern struct cpuinfo_x86 cpu_data[]; @@ -296,6 +297,8 @@ extern unsigned int mca_pentium_flag; */ #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#define HAVE_ARCH_PICK_MMAP_LAYOUT + /* * Size of io_bitmap. */ @@ -422,6 +425,8 @@ struct thread_struct { unsigned int saved_fs, saved_gs; /* IO permissions */ unsigned long *io_bitmap_ptr; +/* performance counters */ + struct vperfctr *perfctr; }; #define INIT_THREAD { \ @@ -439,7 +444,6 @@ struct thread_struct { #define INIT_TSS { \ .esp0 = sizeof(init_stack) + (long)&init_stack, \ .ss0 = __KERNEL_DS, \ - .esp1 = sizeof(init_tss[0]) + (long)&init_tss[0], \ .ss1 = __KERNEL_CS, \ .ldt = GDT_ENTRY_LDT, \ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \ --- linux-2.6.8-rc1/include/asm-i386/spinlock.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/spinlock.h 2004-07-13 17:09:29.266823640 -0700 @@ -169,6 +169,11 @@ here: */ typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned magic; #endif @@ -176,11 +181,19 @@ typedef struct { #define RWLOCK_MAGIC 0xdeaf1eed +#ifdef CONFIG_LOCKMETER +#ifdef CONFIG_DEBUG_SPINLOCK +#define RWLOCK_MAGIC_INIT , 0, RWLOCK_MAGIC +#else +#define RWLOCK_MAGIC_INIT , 0 +#endif +#else /* !CONFIG_LOCKMETER */ #ifdef CONFIG_DEBUG_SPINLOCK #define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC #else #define RWLOCK_MAGIC_INIT /* */ #endif +#endif /* !CONFIG_LOCKMETER */ #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } @@ -227,4 +240,60 @@ static inline int _raw_write_trylock(rwl return 0; } +#ifdef CONFIG_LOCKMETER +static inline int _raw_read_trylock(rwlock_t *lock) +{ +/* FIXME -- replace with assembler */ + atomic_t *count = (atomic_t *)lock; + atomic_dec(count); + if (count->counter > 0) + return 1; + atomic_inc(count); + return 0; +} +#endif + +#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK) +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Matches what is in arch/i386/lib/dec_and_lock.c, except this one is + * "static inline" so that the spin_lock(), if actually invoked, is charged + * against the real caller, not against the catch-all atomic_dec_and_lock + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + int counter; + int newcount; + +repeat: + counter = atomic_read(atomic); + newcount = counter-1; + + if (!newcount) + goto slow_path; + + asm volatile("lock; cmpxchgl %1,%2" + :"=a" (newcount) + :"r" (newcount), "m" (atomic->counter), "0" (counter)); + + /* If the above failed, "eax" will have changed */ + if (newcount != counter) + goto repeat; + return 0; + +slow_path: + preempt_disable(); + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + preempt_enable(); + return 0; +} + +#define ATOMIC_DEC_AND_LOCK +#endif + #endif /* __ASM_SPINLOCK_H */ --- linux-2.6.8-rc1/include/asm-i386/string.h 2004-07-11 14:13:29.000000000 -0700 +++ 25/include/asm-i386/string.h 2004-07-13 17:35:10.358542088 -0700 @@ -277,22 +277,6 @@ static __inline__ void *__memcpy3d(void #endif -/* - * struct_cpy(x,y), copy structure *x into (matching structure) *y. - * - * We get link-time errors if the structure sizes do not match. - * There is no runtime overhead, it's all optimized away at - * compile time. - */ -extern void __struct_cpy_bug (void); - -#define struct_cpy(x,y) \ -({ \ - if (sizeof(*(x)) != sizeof(*(y))) \ - __struct_cpy_bug(); \ - memcpy(x, y, sizeof(*(x))); \ -}) - #define __HAVE_ARCH_MEMMOVE void *memmove(void * dest,const void * src, size_t n); --- linux-2.6.8-rc1/include/asm-i386/thread_info.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-i386/thread_info.h 2004-07-13 17:09:30.567625888 -0700 @@ -157,7 +157,7 @@ static inline unsigned long current_stac /* work to do on interrupt/exception return */ #define _TIF_WORK_MASK \ - (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)) + (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)) #define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */ /* --- linux-2.6.8-rc1/include/asm-i386/tlbflush.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/asm-i386/tlbflush.h 2004-07-13 17:09:52.000000000 -0700 @@ -131,7 +131,7 @@ struct tlb_state int state; char __cacheline_padding[L1_CACHE_BYTES-8]; }; -extern struct tlb_state cpu_tlbstate[NR_CPUS]; +DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate); #endif --- linux-2.6.8-rc1/include/asm-i386/uaccess.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-i386/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -400,7 +400,7 @@ unsigned long __copy_from_user_ll(void * * On success, this will be zero. */ static inline unsigned long -__copy_to_user(void __user *to, const void *from, unsigned long n) +__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -420,6 +420,13 @@ __copy_to_user(void __user *to, const vo return __copy_to_user_ll(to, from, n); } +static inline unsigned long +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + might_sleep(); + return __copy_to_user_inatomic(to, from, n); +} + /** * __copy_from_user: - Copy a block of data from user space, with less checking. * @to: Destination address, in kernel space. @@ -438,7 +445,7 @@ __copy_to_user(void __user *to, const vo * data to the requested size using zero bytes. */ static inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) +__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n) { if (__builtin_constant_p(n)) { unsigned long ret; @@ -458,6 +465,12 @@ __copy_from_user(void *to, const void __ return __copy_from_user_ll(to, from, n); } +static inline unsigned long +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + might_sleep(); + return __copy_from_user_inatomic(to, from, n); +} unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); --- linux-2.6.8-rc1/include/asm-i386/unistd.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-i386/unistd.h 2004-07-13 17:09:34.045097232 -0700 @@ -289,8 +289,14 @@ #define __NR_mq_notify (__NR_mq_open+4) #define __NR_mq_getsetattr (__NR_mq_open+5) #define __NR_sys_kexec_load 283 +#define __NR_perfctr_info 284 +#define __NR_vperfctr_open (__NR_perfctr_info+1) +#define __NR_vperfctr_control (__NR_perfctr_info+2) +#define __NR_vperfctr_unlink (__NR_perfctr_info+3) +#define __NR_vperfctr_iresume (__NR_perfctr_info+4) +#define __NR_vperfctr_read (__NR_perfctr_info+5) -#define NR_syscalls 284 +#define NR_syscalls 290 /* user-visible error numbers are in the range -1 - -124: see */ --- linux-2.6.8-rc1/include/asm-ia64/atomic.h 2004-06-15 23:29:47.000000000 -0700 +++ 25/include/asm-ia64/atomic.h 2004-07-13 17:09:13.000000000 -0700 @@ -56,7 +56,7 @@ ia64_atomic64_add (__s64 i, atomic64_t * CMPXCHG_BUGCHECK(v); old = atomic_read(v); new = old + i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); return new; } @@ -84,7 +84,7 @@ ia64_atomic64_sub (__s64 i, atomic64_t * CMPXCHG_BUGCHECK(v); old = atomic_read(v); new = old - i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); return new; } --- linux-2.6.8-rc1/include/asm-ia64/dma-mapping.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-ia64/dma-mapping.h 2004-07-13 17:09:13.000000000 -0700 @@ -6,6 +6,8 @@ * David Mosberger-Tang */ +#include + #define dma_alloc_coherent platform_dma_alloc_coherent #define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */ #define dma_free_coherent platform_dma_free_coherent --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ia64/kgdb.h 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,69 @@ +#ifndef __KGDB +#define __KGDB + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) + +extern void breakpoint(void); +#define INIT_KGDB_INTS kgdb_enable_ints() + +#ifndef BREAKPOINT +#define BREAKPOINT asm volatile ("break.m 0x6665") +#endif + +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); + +extern int kgdb_tty_hook(void); +extern int kgdb_eth_hook(void); +extern int kgdboe; + +struct kgdb_serial { + unsigned long iobase; + unsigned long shift; + int line; + int iotype; + int claimed; +}; + +/* + * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' + * pointer to its routine and it will be entered as the first thing + * when a trap occurs. + * + * Return values are, at present, undefined. + * + * The debug hook routine does not necessarily return to its caller. + * It has the register image and thus may choose to resume execution + * anywhere it pleases. + */ +struct pt_regs; + +extern int kgdb_handle_exception(int trapno, + int signo, unsigned long err_code, struct pt_regs *regs); +struct unw_frame_info; +extern int in_kgdb(struct pt_regs *regs, struct unw_frame_info *); +#ifdef CONFIG_KGDB_EARLY +extern void __init kgdb_serial_init(void); +#endif + +#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ +#ifndef BREAKPOINT +#define BREAKPOINT +#endif +#define in_kgdb +#define kgdb_handle_exception +#define breakpoint +#define INIT_KGDB_INTS +#define kgdb_process_breakpoint() do {} while(0) + +#endif +#endif /* __KGDB */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ia64/kgdb_local.h 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,114 @@ +#ifndef __KGDB_LOCAL +#define ___KGDB_LOCAL +#include +#include +#include +#include +#include +#include +#include + +#define PORT 0x0 +#ifdef CONFIG_KGDB_PORT +#undef PORT +#define PORT CONFIG_KGDB_PORT +#define IOTYPE SERIAL_IO_PORT +#endif + +#define IOMEM 0x0 +#ifdef CONFIG_KGDB_IOMEM +#undef IOMEM +#define IOMEM CONFIG_KGDB_IOMEM +#define IOTYPE SERIAL_IO_MEM +#endif + +#define IRQ 4 +#ifdef CONFIG_KGDB_IRQ +#undef IRQ +#define IRQ CONFIG_KGDB_IRQ +#endif + +#define IOMEM_REG_SHIFT 0 +#ifdef CONFIG_IOMEM_REG_SHIFT +#undef IOMEM_REG_SHIFT +#define IOMEM_REG_SHIFT CONFIG_IOMEM_REG_SHIFT +#endif + + +#define SB_CLOCK 1843200 +#define SB_BASE (SB_CLOCK/16) +#define SB_BAUD9600 SB_BASE/9600 +#define SB_BAUD192 SB_BASE/19200 +#define SB_BAUD384 SB_BASE/38400 +#define SB_BAUD576 SB_BASE/57600 +#define SB_BAUD1152 SB_BASE/115200 +#ifdef CONFIG_KGDB_9600BAUD +#define SB_BAUD SB_BAUD9600 +#endif +#ifdef CONFIG_KGDB_19200BAUD +#define SB_BAUD SB_BAUD192 +#endif +#ifdef CONFIG_KGDB_38400BAUD +#define SB_BAUD SB_BAUD384 +#endif +#ifdef CONFIG_KGDB_57600BAUD +#define SB_BAUD SB_BAUD576 +#endif +#ifdef CONFIG_KGDB_115200BAUD +#define SB_BAUD SB_BAUD1152 +#endif +#ifndef SB_BAUD +#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ +#endif + + +#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#define spin_lock _raw_spin_lock +#define spin_trylock _raw_spin_trylock +#define spin_unlock _raw_spin_unlock +#else +#endif +#undef spin_unlock_wait +#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ + while(spin_is_locked(x)) + +#define SB_IER 1 +#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS + +#define FLAGS 0 +#define SB_STATE { \ + magic: SSTATE_MAGIC, \ + baud_base: SB_BASE, \ + port: PORT, \ + iomem_base:(u8 *) IOMEM, \ + iomem_reg_shift: IOMEM_REG_SHIFT,\ + io_type: IOTYPE, \ + irq: IRQ, \ + flags: FLAGS, \ + custom_divisor:SB_BAUD} +#define SB_INFO { \ + magic: SERIAL_MAGIC, \ + port: PORT,0,FLAGS, \ + io_type: IOTYPE, \ + iomem_base: (u8 *) IOMEM, \ + iomem_reg_shift: IOMEM_REG_SHIFT, \ + state: &state, \ + tty: (struct tty_struct *)&state, \ + IER: SB_IER, \ + MCR: SB_MCR} +extern void putDebugChar(int); +/* RTAI support needs us to really stop/start interrupts */ + +#define kgdb_local_save_flags(x) local_save_flags(x) +#define kgdb_local_irq_restore(x) local_irq_restore(x) +#define kgdb_local_irq_save(x) local_irq_save(x) + +#ifdef CONFIG_SERIAL +extern void shutdown_for_kgdb(struct async_struct *info); +extern void kgdb_serial_setup(struct uart_port *); +#endif +#define INIT_KDEBUG putDebugChar("+"); +#endif /* __KGDB_LOCAL */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ia64/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + */ + +#ifndef _IA64_LOCKMETER_H +#define _IA64_LOCKMETER_H + +#ifdef local_cpu_data +#define CPU_CYCLE_FREQUENCY local_cpu_data->itc_freq +#else +#define CPU_CYCLE_FREQUENCY my_cpu_data.itc_freq +#endif +#define get_cycles64() get_cycles() + +#define THIS_CPU_NUMBER smp_processor_id() + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + */ +/* + * instrumented spinlock structure -- never used to allocate storage + * only used in macros below to overlay a spinlock_t + */ +typedef struct inst_spinlock_s { + /* remember, Intel is little endian */ + volatile unsigned short lock; + volatile unsigned short index; +} inst_spinlock_t; +#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv +#define GET_INDEX(lock_ptr) ((inst_spinlock_t *)(lock_ptr))->index + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int read_counter:31; + volatile int write_lock:1; + volatile unsigned short index; + volatile unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) ((rwlock_ptr)->read_counter) + +/* + * return true if rwlock is write locked + * (note that other lock attempts can cause the lock value to be negative) + */ +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->read_counter) + +#endif /* _IA64_LOCKMETER_H */ + --- linux-2.6.8-rc1/include/asm-ia64/machvec.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-ia64/machvec.h 2004-07-13 17:09:13.000000000 -0700 @@ -19,6 +19,7 @@ struct pt_regs; struct scatterlist; struct irq_desc; struct page; +struct mm_struct; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_cpu_init_t (void); @@ -26,6 +27,7 @@ typedef void ia64_mv_irq_init_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *); typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long); +typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *); typedef struct irq_desc *ia64_mv_irq_desc (unsigned int); typedef u8 ia64_mv_irq_to_vector (u8); typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector); @@ -69,11 +71,21 @@ typedef unsigned short ia64_mv_readw_rel typedef unsigned int ia64_mv_readl_relaxed_t (void *); typedef unsigned long ia64_mv_readq_relaxed_t (void *); -extern void machvec_noop (void); +static inline void +machvec_noop (void) +{ +} + +static inline void +machvec_noop_mm (struct mm_struct *mm) +{ +} + extern void machvec_setup (char **); extern void machvec_timer_interrupt (int, void *, struct pt_regs *); extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int); extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int); +extern void machvec_tlb_migrate_finish (struct mm_struct *); # if defined (CONFIG_IA64_HP_SIM) # include @@ -95,6 +107,7 @@ extern void machvec_dma_sync_sg (struct # define platform_send_ipi ia64_mv.send_ipi # define platform_timer_interrupt ia64_mv.timer_interrupt # define platform_global_tlb_purge ia64_mv.global_tlb_purge +# define platform_tlb_migrate_finish ia64_mv.tlb_migrate_finish # define platform_dma_init ia64_mv.dma_init # define platform_dma_alloc_coherent ia64_mv.dma_alloc_coherent # define platform_dma_free_coherent ia64_mv.dma_free_coherent @@ -140,6 +153,7 @@ struct ia64_machine_vector { ia64_mv_send_ipi_t *send_ipi; ia64_mv_timer_interrupt_t *timer_interrupt; ia64_mv_global_tlb_purge_t *global_tlb_purge; + ia64_mv_tlb_migrate_finish_t *tlb_migrate_finish; ia64_mv_dma_init *dma_init; ia64_mv_dma_alloc_coherent *dma_alloc_coherent; ia64_mv_dma_free_coherent *dma_free_coherent; @@ -181,6 +195,7 @@ struct ia64_machine_vector { platform_send_ipi, \ platform_timer_interrupt, \ platform_global_tlb_purge, \ + platform_tlb_migrate_finish, \ platform_dma_init, \ platform_dma_alloc_coherent, \ platform_dma_free_coherent, \ @@ -260,6 +275,9 @@ extern ia64_mv_dma_supported swiotlb_dm #ifndef platform_global_tlb_purge # define platform_global_tlb_purge ia64_global_tlb_purge /* default to architected version */ #endif +#ifndef platform_tlb_migrate_finish +# define platform_tlb_migrate_finish machvec_noop_mm +#endif #ifndef platform_dma_init # define platform_dma_init swiotlb_init #endif --- linux-2.6.8-rc1/include/asm-ia64/machvec_sn2.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-ia64/machvec_sn2.h 2004-07-13 17:09:13.000000000 -0700 @@ -39,6 +39,7 @@ extern ia64_mv_irq_init_t sn_irq_init; extern ia64_mv_send_ipi_t sn2_send_IPI; extern ia64_mv_timer_interrupt_t sn_timer_interrupt; extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge; +extern ia64_mv_tlb_migrate_finish_t sn_tlb_migrate_finish; extern ia64_mv_irq_desc sn_irq_desc; extern ia64_mv_irq_to_vector sn_irq_to_vector; extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq; @@ -83,6 +84,7 @@ extern ia64_mv_dma_supported sn_dma_sup #define platform_send_ipi sn2_send_IPI #define platform_timer_interrupt sn_timer_interrupt #define platform_global_tlb_purge sn2_global_tlb_purge +#define platform_tlb_migrate_finish sn_tlb_migrate_finish #define platform_pci_fixup sn_pci_fixup #define platform_inb __sn_inb #define platform_inw __sn_inw --- linux-2.6.8-rc1/include/asm-ia64/pgtable.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ia64/pgtable.h 2004-07-13 17:09:51.000000000 -0700 @@ -321,6 +321,11 @@ pgd_offset (struct mm_struct *mm, unsign #define pgd_offset_k(addr) \ (init_mm.pgd + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))) +/* Look up a pgd entry in the gate area. On IA-64, the gate-area + resides in the kernel-mapped segment, hence we use pgd_offset_k() + here. */ +#define pgd_offset_gate(mm, addr) pgd_offset_k(addr) + /* Find an entry in the second-level page table.. */ #define pmd_offset(dir,addr) \ ((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) @@ -552,6 +557,7 @@ do { \ #define __HAVE_ARCH_PTEP_SET_WRPROTECT #define __HAVE_ARCH_PTEP_MKDIRTY #define __HAVE_ARCH_PTE_SAME +#define __HAVE_ARCH_PGD_OFFSET_GATE #include #endif /* _ASM_IA64_PGTABLE_H */ --- linux-2.6.8-rc1/include/asm-ia64/spinlock.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-ia64/spinlock.h 2004-07-13 17:09:29.000000000 -0700 @@ -116,8 +116,18 @@ do { \ typedef struct { volatile int read_counter : 31; volatile int write_lock : 1; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; + +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *) (x) != 0) @@ -133,6 +143,48 @@ do { \ } \ } while (0) +#ifdef CONFIG_LOCKMETER +/* + * HACK: This works, but still have a timing window that affects performance: + * we see that no one owns the Write lock, then someone * else grabs for Write + * lock before we do a read_lock(). + * This means that on rare occasions our read_lock() will stall and spin-wait + * until we acquire for Read, instead of simply returning a trylock failure. + */ +static inline int _raw_read_trylock(rwlock_t *rw) +{ + if (rw->write_lock) { + return 0; + } else { + _raw_read_lock(rw); + return 1; + } +} + +static inline int _raw_write_trylock(rwlock_t *rw) +{ + if (!(rw->write_lock)) { + /* isn't currently write-locked... that looks promising... */ + if (test_and_set_bit(31, rw) == 0) { + /* now it is write-locked by me... */ + if (rw->read_counter) { + /* really read-locked, so release write-lock and fail */ + clear_bit(31, rw); + } else { + /* we've the the write-lock, no read-lockers... success! */ + barrier(); + return 1; + } + + } + } + + /* falls through ... fails to write-lock */ + barrier(); + return 0; +} +#endif + #define _raw_read_unlock(rw) \ do { \ rwlock_t *__read_lock_ptr = (rw); \ @@ -196,4 +248,25 @@ do { \ clear_bit(31, (x)); \ }) +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock(spinlock_t *lock); + +/* + * Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering + * so we can see the callerPC of who is actually doing the spin_lock(). + * Otherwise, all we see is the generic rollup of all locks done by + * atomic_dec_and_lock(). + */ +static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + _metered_spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + _metered_spin_unlock(lock); + return 0; +} +#define ATOMIC_DEC_AND_LOCK +#endif + #endif /* _ASM_IA64_SPINLOCK_H */ --- linux-2.6.8-rc1/include/asm-ia64/thread_info.h 2003-07-02 14:53:17.000000000 -0700 +++ 25/include/asm-ia64/thread_info.h 2004-07-13 17:09:13.000000000 -0700 @@ -73,12 +73,15 @@ struct thread_info { #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ +#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_WORK_MASK 0x7 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE */ -#define TIF_ALLWORK_MASK 0xf /* bits 0..3 are "work to do on user-return" bits */ +#define TIF_ALLWORK_MASK 0x1f /* bits 0..4 are "work to do on user-return" bits */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) --- linux-2.6.8-rc1/include/asm-ia64/tlb.h 2004-03-10 20:41:31.000000000 -0800 +++ 25/include/asm-ia64/tlb.h 2004-07-13 17:09:13.000000000 -0700 @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_SMP # define FREE_PTE_NR 2048 @@ -211,6 +212,8 @@ __tlb_remove_tlb_entry (struct mmu_gathe tlb->end_addr = address + PAGE_SIZE; } +#define tlb_migrate_finish(mm) platform_tlb_migrate_finish(mm) + #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) --- linux-2.6.8-rc1/include/asm-ia64/uaccess.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-ia64/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -202,7 +202,8 @@ extern unsigned long __copy_user (void * #define __copy_to_user(to, from, n) __copy_user((to), (from), (n)) #define __copy_from_user(to, from, n) __copy_user((to), (from), (n)) - +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user #define copy_to_user(to, from, n) __copy_tofrom_user((to), (from), (n), 1) #define copy_from_user(to, from, n) __copy_tofrom_user((to), (from), (n), 0) --- linux-2.6.8-rc1/include/asm-m68knommu/uaccess.h 2003-07-10 18:50:32.000000000 -0700 +++ 25/include/asm-m68knommu/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -134,6 +134,8 @@ extern int __get_user_bad(void); #define __copy_from_user(to, from, n) copy_from_user(to, from, n) #define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user #define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) --- linux-2.6.8-rc1/include/asm-m68k/uaccess.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/asm-m68k/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -521,6 +521,9 @@ __constant_copy_from_user(void *to, cons : "0"(to), "1"(from), "2"(n/4) \ : "d0", "memory") +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + static inline unsigned long __constant_copy_to_user(void *to, const void *from, unsigned long n) { --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-mips/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * Ported to mips32 for Asita Technologies + * by D.J. Barrow ( dj.barrow@asitatechnologies.com ) + */ +#ifndef _ASM_LOCKMETER_H +#define _ASM_LOCKMETER_H + +/* do_gettimeoffset is a function pointer on mips */ +/* & it is not included by */ +#include +#include +#include + +#define SPINLOCK_MAGIC_INIT /* */ + +#define CPU_CYCLE_FREQUENCY get_cpu_cycle_frequency() + +#define THIS_CPU_NUMBER smp_processor_id() + +static uint32_t cpu_cycle_frequency = 0; + +static uint32_t get_cpu_cycle_frequency(void) +{ + /* a total hack, slow and invasive, but ... it works */ + int sec; + uint32_t start_cycles; + struct timeval tv; + + if (cpu_cycle_frequency == 0) { /* uninitialized */ + do_gettimeofday(&tv); + sec = tv.tv_sec; /* set up to catch the tv_sec rollover */ + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + sec = tv.tv_sec; /* rolled over to a new sec value */ + start_cycles = get_cycles(); + while (sec == tv.tv_sec) { do_gettimeofday(&tv); } + cpu_cycle_frequency = get_cycles() - start_cycles; + } + + return cpu_cycle_frequency; +} + +extern struct timeval xtime; + +static uint64_t get_cycles64(void) +{ + static uint64_t last_get_cycles64 = 0; + uint64_t ret; + unsigned long sec; + unsigned long usec, usec_offset; + +again: + sec = xtime.tv_sec; + usec = xtime.tv_usec; + usec_offset = do_gettimeoffset(); + if ((xtime.tv_sec != sec) || + (xtime.tv_usec != usec)|| + (usec_offset >= 20000)) + goto again; + + ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency); + /* We can't do a normal 64 bit division on mips without libgcc.a */ + do_div(ret,1000000); + ret += ((uint64_t)sec * cpu_cycle_frequency); + + /* XXX why does time go backwards? do_gettimeoffset? general time adj? */ + if (ret <= last_get_cycles64) + ret = last_get_cycles64+1; + last_get_cycles64 = ret; + + return ret; +} + +/* + * macros to cache and retrieve an index value inside of a lock + * these macros assume that there are less than 65536 simultaneous + * (read mode) holders of a rwlock. + * we also assume that the hash table has less than 32767 entries. + * the high order bit is used for write locking a rw_lock + */ +#define INDEX_MASK 0x7FFF0000 +#define READERS_MASK 0x0000FFFF +#define INDEX_SHIFT 16 +#define PUT_INDEX(lockp,index) \ + lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT) +#define GET_INDEX(lockp) \ + (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT) + +/* + * macros to cache and retrieve an index value in a read/write lock + * as well as the cpu where a reader busy period started + * we use the 2nd word (the debug word) for this, so require the + * debug word to be present + */ +/* + * instrumented rwlock structure -- never used to allocate storage + * only used in macros below to overlay a rwlock_t + */ +typedef struct inst_rwlock_s { + volatile int lock; + unsigned short index; + unsigned short cpu; +} inst_rwlock_t; +#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv +#define GET_RWINDEX(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv +#define GET_RW_CPU(rwlock_ptr) ((inst_rwlock_t *)(rwlock_ptr))->cpu + +/* + * return the number of readers for a rwlock_t + */ +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + int tmp = (int) rwlock_ptr->lock; + return (tmp >= 0) ? tmp : 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock > 0) + +#endif /* _ASM_LOCKMETER_H */ --- linux-2.6.8-rc1/include/asm-mips/spinlock.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-mips/spinlock.h 2004-07-13 17:09:29.000000000 -0700 @@ -92,9 +92,18 @@ static inline unsigned int _raw_spin_try typedef struct { volatile unsigned int lock; +#ifdef CONFIG_LOCKMETER + /* required for LOCKMETER since all bits in lock are used */ + /* and we need this storage for CPU and lock INDEX */ + unsigned lockmeter_magic; +#endif } rwlock_t; +#ifdef CONFIG_LOCKMETER +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#else #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) --- linux-2.6.8-rc1/include/asm-mips/uaccess.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-mips/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -463,6 +463,9 @@ extern size_t __copy_user(void *__to, co __cu_len; \ }) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + /* * copy_to_user: - Copy a block of data into user space. * @to: Destination address, in user space. --- linux-2.6.8-rc1/include/asm-parisc/cacheflush.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-parisc/cacheflush.h 2004-07-13 17:09:26.000000000 -0700 @@ -79,9 +79,9 @@ static inline void flush_dcache_page(str } #define flush_dcache_mmap_lock(mapping) \ - spin_lock_irq(&(mapping)->tree_lock) + write_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \ - spin_unlock_irq(&(mapping)->tree_lock) + write_unlock_irq(&(mapping)->tree_lock) #define flush_icache_page(vma,page) do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0) --- linux-2.6.8-rc1/include/asm-parisc/uaccess.h 2004-02-17 20:48:46.000000000 -0800 +++ 25/include/asm-parisc/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -279,5 +279,7 @@ extern long lstrnlen_user(const char __u #define __copy_to_user lcopy_to_user #define copy_in_user lcopy_in_user #define __copy_in_user lcopy_in_user +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user #endif /* __PARISC_UACCESS_H */ --- linux-2.6.8-rc1/include/asm-ppc64/uaccess.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ppc64/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -281,6 +281,9 @@ extern unsigned long copy_in_user(void _ extern unsigned long __clear_user(void __user *addr, unsigned long size); +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + static inline unsigned long clear_user(void __user *addr, unsigned long size) { --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ppc/mpc52xx.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,380 @@ +/* + * include/asm-ppc/mpc52xx.h + * + * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips + * May need to be cleaned as the port goes on ... + * + * + * Maintainer : Sylvain Munaut + * + * Originally written by Dale Farnsworth + * for the 2.4 kernel. + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __ASM_MPC52xx_H__ +#define __ASM_MPC52xx_H__ + +#ifndef __ASSEMBLY__ +#include +#include + +struct pt_regs; +struct ocp_def; +#endif /* __ASSEMBLY__ */ + + +/* ======================================================================== */ +/* Main registers/struct addresses */ +/* ======================================================================== */ +/* Theses are PHYSICAL addresses ! */ +/* TODO : There should be no static mapping, but it's not yet the case, so */ +/* we require a 1:1 mapping */ + +#define MPC52xx_MBAR 0xf0000000 /* Phys address */ +#define MPC52xx_MBAR_SIZE 0x00010000 +#define MPC52xx_MBAR_VIRT 0xf0000000 /* Virt address */ + +#define MPC52xx_MMAP_CTL (MPC52xx_MBAR + 0x0000) +#define MPC52xx_CDM (MPC52xx_MBAR + 0x0200) +#define MPC52xx_SFTRST (MPC52xx_MBAR + 0x0220) +#define MPC52xx_SFTRST_BIT 0x01000000 +#define MPC52xx_INTR (MPC52xx_MBAR + 0x0500) +#define MPC52xx_GPTx(x) (MPC52xx_MBAR + 0x0600 + ((x)<<4)) +#define MPC52xx_RTC (MPC52xx_MBAR + 0x0800) +#define MPC52xx_MSCAN1 (MPC52xx_MBAR + 0x0900) +#define MPC52xx_MSCAN2 (MPC52xx_MBAR + 0x0980) +#define MPC52xx_GPIO (MPC52xx_MBAR + 0x0b00) +#define MPC52xx_PCI (MPC52xx_MBAR + 0x0d00) +#define MPC52xx_USB_OHCI (MPC52xx_MBAR + 0x1000) +#define MPC52xx_SDMA (MPC52xx_MBAR + 0x1200) +#define MPC52xx_XLB (MPC52xx_MBAR + 0x1f00) +#define MPC52xx_PSCx(x) (MPC52xx_MBAR + 0x2000 + ((x)<<9)) +#define MPC52xx_PSC1 (MPC52xx_MBAR + 0x2000) +#define MPC52xx_PSC2 (MPC52xx_MBAR + 0x2200) +#define MPC52xx_PSC3 (MPC52xx_MBAR + 0x2400) +#define MPC52xx_PSC4 (MPC52xx_MBAR + 0x2600) +#define MPC52xx_PSC5 (MPC52xx_MBAR + 0x2800) +#define MPC52xx_PSC6 (MPC52xx_MBAR + 0x2C00) +#define MPC52xx_FEC (MPC52xx_MBAR + 0x3000) +#define MPC52xx_ATA (MPC52xx_MBAR + 0x3a00) +#define MPC52xx_I2C1 (MPC52xx_MBAR + 0x3d00) +#define MPC52xx_I2C_MICR (MPC52xx_MBAR + 0x3d20) +#define MPC52xx_I2C2 (MPC52xx_MBAR + 0x3d40) + +/* SRAM used for SDMA */ +#define MPC52xx_SRAM (MPC52xx_MBAR + 0x8000) +#define MPC52xx_SRAM_SIZE (16*1024) +#define MPC52xx_SDMA_MAX_TASKS 16 + + /* Memory allocation block size */ +#define MPC52xx_SDRAM_UNIT 0x8000 /* 32K byte */ + + +/* ======================================================================== */ +/* IRQ mapping */ +/* ======================================================================== */ +/* Be sure to look at mpc52xx_pic.h if you wish for whatever reason to change + * this + */ + +#define MPC52xx_CRIT_IRQ_NUM 4 +#define MPC52xx_MAIN_IRQ_NUM 17 +#define MPC52xx_SDMA_IRQ_NUM 17 +#define MPC52xx_PERP_IRQ_NUM 23 + +#define MPC52xx_CRIT_IRQ_BASE 0 +#define MPC52xx_MAIN_IRQ_BASE (MPC52xx_CRIT_IRQ_BASE + MPC52xx_CRIT_IRQ_NUM) +#define MPC52xx_SDMA_IRQ_BASE (MPC52xx_MAIN_IRQ_BASE + MPC52xx_MAIN_IRQ_NUM) +#define MPC52xx_PERP_IRQ_BASE (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM) + +#define MPC52xx_IRQ0 (MPC52xx_CRIT_IRQ_BASE + 0) +#define MPC52xx_SLICE_TIMER_0_IRQ (MPC52xx_CRIT_IRQ_BASE + 1) +#define MPC52xx_HI_INT_IRQ (MPC52xx_CRIT_IRQ_BASE + 2) +#define MPC52xx_CCS_IRQ (MPC52xx_CRIT_IRQ_BASE + 3) + +#define MPC52xx_IRQ1 (MPC52xx_MAIN_IRQ_BASE + 1) +#define MPC52xx_IRQ2 (MPC52xx_MAIN_IRQ_BASE + 2) +#define MPC52xx_IRQ3 (MPC52xx_MAIN_IRQ_BASE + 3) + +#define MPC52xx_SDMA_IRQ (MPC52xx_PERP_IRQ_BASE + 0) +#define MPC52xx_PSC1_IRQ (MPC52xx_PERP_IRQ_BASE + 1) +#define MPC52xx_PSC2_IRQ (MPC52xx_PERP_IRQ_BASE + 2) +#define MPC52xx_PSC3_IRQ (MPC52xx_PERP_IRQ_BASE + 3) +#define MPC52xx_PSC6_IRQ (MPC52xx_PERP_IRQ_BASE + 4) +#define MPC52xx_IRDA_IRQ (MPC52xx_PERP_IRQ_BASE + 4) +#define MPC52xx_FEC_IRQ (MPC52xx_PERP_IRQ_BASE + 5) +#define MPC52xx_USB_IRQ (MPC52xx_PERP_IRQ_BASE + 6) +#define MPC52xx_ATA_IRQ (MPC52xx_PERP_IRQ_BASE + 7) +#define MPC52xx_PCI_CNTRL_IRQ (MPC52xx_PERP_IRQ_BASE + 8) +#define MPC52xx_PCI_SCIRX_IRQ (MPC52xx_PERP_IRQ_BASE + 9) +#define MPC52xx_PCI_SCITX_IRQ (MPC52xx_PERP_IRQ_BASE + 10) +#define MPC52xx_PSC4_IRQ (MPC52xx_PERP_IRQ_BASE + 11) +#define MPC52xx_PSC5_IRQ (MPC52xx_PERP_IRQ_BASE + 12) +#define MPC52xx_SPI_MODF_IRQ (MPC52xx_PERP_IRQ_BASE + 13) +#define MPC52xx_SPI_SPIF_IRQ (MPC52xx_PERP_IRQ_BASE + 14) +#define MPC52xx_I2C1_IRQ (MPC52xx_PERP_IRQ_BASE + 15) +#define MPC52xx_I2C2_IRQ (MPC52xx_PERP_IRQ_BASE + 16) +#define MPC52xx_CAN1_IRQ (MPC52xx_PERP_IRQ_BASE + 17) +#define MPC52xx_CAN2_IRQ (MPC52xx_PERP_IRQ_BASE + 18) +#define MPC52xx_IR_RX_IRQ (MPC52xx_PERP_IRQ_BASE + 19) +#define MPC52xx_IR_TX_IRQ (MPC52xx_PERP_IRQ_BASE + 20) +#define MPC52xx_XLB_ARB_IRQ (MPC52xx_PERP_IRQ_BASE + 21) + + + +/* ======================================================================== */ +/* Structures mapping of some unit register set */ +/* ======================================================================== */ + +#ifndef __ASSEMBLY__ + +/* Memory Mapping Control */ +struct mpc52xx_mmap_ctl { + volatile u32 mbar; /* MMAP_CTRL + 0x00 */ + + volatile u32 cs0_start; /* MMAP_CTRL + 0x04 */ + volatile u32 cs0_stop; /* MMAP_CTRL + 0x08 */ + volatile u32 cs1_start; /* MMAP_CTRL + 0x0c */ + volatile u32 cs1_stop; /* MMAP_CTRL + 0x10 */ + volatile u32 cs2_start; /* MMAP_CTRL + 0x14 */ + volatile u32 cs2_stop; /* MMAP_CTRL + 0x18 */ + volatile u32 cs3_start; /* MMAP_CTRL + 0x1c */ + volatile u32 cs3_stop; /* MMAP_CTRL + 0x20 */ + volatile u32 cs4_start; /* MMAP_CTRL + 0x24 */ + volatile u32 cs4_stop; /* MMAP_CTRL + 0x28 */ + volatile u32 cs5_start; /* MMAP_CTRL + 0x2c */ + volatile u32 cs5_stop; /* MMAP_CTRL + 0x30 */ + + volatile u32 sdram0; /* MMAP_CTRL + 0x34 */ + volatile u32 sdram1; /* MMAP_CTRL + 0X38 */ + + volatile u32 reserved[4]; /* MMAP_CTRL + 0x3c .. 0x48 */ + + volatile u32 boot_start; /* MMAP_CTRL + 0x4c */ + volatile u32 boot_stop; /* MMAP_CTRL + 0x50 */ + + volatile u32 ipbi_ws_ctrl; /* MMAP_CTRL + 0x54 */ + + volatile u32 cs6_start; /* MMAP_CTRL + 0x58 */ + volatile u32 cs6_stop; /* MMAP_CTRL + 0x5c */ + volatile u32 cs7_start; /* MMAP_CTRL + 0x60 */ + volatile u32 cs7_stop; /* MMAP_CTRL + 0x60 */ +}; + +/* Interrupt controller */ +struct mpc52xx_intr { + volatile u32 per_mask; /* INTR + 0x00 */ + volatile u32 per_pri1; /* INTR + 0x04 */ + volatile u32 per_pri2; /* INTR + 0x08 */ + volatile u32 per_pri3; /* INTR + 0x0c */ + volatile u32 ctrl; /* INTR + 0x10 */ + volatile u32 main_mask; /* INTR + 0x14 */ + volatile u32 main_pri1; /* INTR + 0x18 */ + volatile u32 main_pri2; /* INTR + 0x1c */ + volatile u32 reserved1; /* INTR + 0x20 */ + volatile u32 enc_status; /* INTR + 0x24 */ + volatile u32 crit_status; /* INTR + 0x28 */ + volatile u32 main_status; /* INTR + 0x2c */ + volatile u32 per_status; /* INTR + 0x30 */ + volatile u32 reserved2; /* INTR + 0x34 */ + volatile u32 per_error; /* INTR + 0x38 */ +}; + +/* SDMA */ +struct mpc52xx_sdma { + volatile u32 taskBar; /* SDMA + 0x00 */ + volatile u32 currentPointer; /* SDMA + 0x04 */ + volatile u32 endPointer; /* SDMA + 0x08 */ + volatile u32 variablePointer;/* SDMA + 0x0c */ + + volatile u8 IntVect1; /* SDMA + 0x10 */ + volatile u8 IntVect2; /* SDMA + 0x11 */ + volatile u16 PtdCntrl; /* SDMA + 0x12 */ + + volatile u32 IntPend; /* SDMA + 0x14 */ + volatile u32 IntMask; /* SDMA + 0x18 */ + + volatile u16 tcr[16]; /* SDMA + 0x1c .. 0x3a */ + + volatile u8 ipr[31]; /* SDMA + 0x3c .. 5b */ + + volatile u32 res1; /* SDMA + 0x5c */ + volatile u32 task_size0; /* SDMA + 0x60 */ + volatile u32 task_size1; /* SDMA + 0x64 */ + volatile u32 MDEDebug; /* SDMA + 0x68 */ + volatile u32 ADSDebug; /* SDMA + 0x6c */ + volatile u32 Value1; /* SDMA + 0x70 */ + volatile u32 Value2; /* SDMA + 0x74 */ + volatile u32 Control; /* SDMA + 0x78 */ + volatile u32 Status; /* SDMA + 0x7c */ +}; + +/* GPT */ +struct mpc52xx_gpt { + volatile u32 mode; /* GPTx + 0x00 */ + volatile u32 count; /* GPTx + 0x04 */ + volatile u32 pwm; /* GPTx + 0x08 */ + volatile u32 status; /* GPTx + 0X0c */ +}; + +/* RTC */ +struct mpc52xx_rtc { + volatile u32 time_set; /* RTC + 0x00 */ + volatile u32 date_set; /* RTC + 0x04 */ + volatile u32 stopwatch; /* RTC + 0x08 */ + volatile u32 int_enable; /* RTC + 0x0c */ + volatile u32 time; /* RTC + 0x10 */ + volatile u32 date; /* RTC + 0x14 */ + volatile u32 stopwatch_intr; /* RTC + 0x18 */ + volatile u32 bus_error; /* RTC + 0x1c */ + volatile u32 dividers; /* RTC + 0x20 */ +}; + +/* GPIO */ +struct mpc52xx_gpio { + volatile u32 port_config; /* GPIO + 0x00 */ + volatile u32 simple_gpioe; /* GPIO + 0x04 */ + volatile u32 simple_ode; /* GPIO + 0x08 */ + volatile u32 simple_ddr; /* GPIO + 0x0c */ + volatile u32 simple_dvo; /* GPIO + 0x10 */ + volatile u32 simple_ival; /* GPIO + 0x14 */ + volatile u8 outo_gpioe; /* GPIO + 0x18 */ + volatile u8 reserved1[3]; /* GPIO + 0x19 */ + volatile u8 outo_dvo; /* GPIO + 0x1c */ + volatile u8 reserved2[3]; /* GPIO + 0x1d */ + volatile u8 sint_gpioe; /* GPIO + 0x20 */ + volatile u8 reserved3[3]; /* GPIO + 0x21 */ + volatile u8 sint_ode; /* GPIO + 0x24 */ + volatile u8 reserved4[3]; /* GPIO + 0x25 */ + volatile u8 sint_ddr; /* GPIO + 0x28 */ + volatile u8 reserved5[3]; /* GPIO + 0x29 */ + volatile u8 sint_dvo; /* GPIO + 0x2c */ + volatile u8 reserved6[3]; /* GPIO + 0x2d */ + volatile u8 sint_inten; /* GPIO + 0x30 */ + volatile u8 reserved7[3]; /* GPIO + 0x31 */ + volatile u16 sint_itype; /* GPIO + 0x34 */ + volatile u16 reserved8; /* GPIO + 0x36 */ + volatile u8 gpio_control; /* GPIO + 0x38 */ + volatile u8 reserved9[3]; /* GPIO + 0x39 */ + volatile u8 sint_istat; /* GPIO + 0x3c */ + volatile u8 sint_ival; /* GPIO + 0x3d */ + volatile u8 bus_errs; /* GPIO + 0x3e */ + volatile u8 reserved10; /* GPIO + 0x3f */ +}; + +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD 4 +#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD 5 +#define MPC52xx_GPIO_PCI_DIS (1<<15) + +/* XLB Bus control */ +struct mpc52xx_xlb { + volatile u8 reserved[0x40]; + volatile u32 config; /* XLB + 0x40 */ + volatile u32 version; /* XLB + 0x44 */ + volatile u32 status; /* XLB + 0x48 */ + volatile u32 int_enable; /* XLB + 0x4c */ + volatile u32 addr_capture; /* XLB + 0x50 */ + volatile u32 bus_sig_capture; /* XLB + 0x54 */ + volatile u32 addr_timeout; /* XLB + 0x58 */ + volatile u32 data_timeout; /* XLB + 0x5c */ + volatile u32 bus_act_timeout; /* XLB + 0x60 */ + volatile u32 master_pri_enable; /* XLB + 0x64 */ + volatile u32 master_priority; /* XLB + 0x68 */ + volatile u32 base_address; /* XLB + 0x6c */ + volatile u32 snoop_window; /* XLB + 0x70 */ +}; + + +/* Clock Distribution control */ +struct mpc52xx_cdm { + volatile u32 jtag_id; /* MBAR_CDM + 0x00 reg0 read only */ + volatile u32 rstcfg; /* MBAR_CDM + 0x04 reg1 read only */ + volatile u32 breadcrumb; /* MBAR_CDM + 0x08 reg2 */ + + volatile u8 mem_clk_sel; /* MBAR_CDM + 0x0c reg3 byte0 */ + volatile u8 xlb_clk_sel; /* MBAR_CDM + 0x0d reg3 byte1 read only */ + volatile u8 ipb_clk_sel; /* MBAR_CDM + 0x0e reg3 byte2 */ + volatile u8 pci_clk_sel; /* MBAR_CDM + 0x0f reg3 byte3 */ + + volatile u8 ext_48mhz_en; /* MBAR_CDM + 0x10 reg4 byte0 */ + volatile u8 fd_enable; /* MBAR_CDM + 0x11 reg4 byte1 */ + volatile u16 fd_counters; /* MBAR_CDM + 0x12 reg4 byte2,3 */ + + volatile u32 clk_enables; /* MBAR_CDM + 0x14 reg5 */ + + volatile u8 osc_disable; /* MBAR_CDM + 0x18 reg6 byte0 */ + volatile u8 reserved0[3]; /* MBAR_CDM + 0x19 reg6 byte1,2,3 */ + + volatile u8 ccs_sleep_enable;/* MBAR_CDM + 0x1c reg7 byte0 */ + volatile u8 osc_sleep_enable;/* MBAR_CDM + 0x1d reg7 byte1 */ + volatile u8 reserved1; /* MBAR_CDM + 0x1e reg7 byte2 */ + volatile u8 ccs_qreq_test; /* MBAR_CDM + 0x1f reg7 byte3 */ + + volatile u8 soft_reset; /* MBAR_CDM + 0x20 u8 byte0 */ + volatile u8 no_ckstp; /* MBAR_CDM + 0x21 u8 byte0 */ + volatile u8 reserved2[2]; /* MBAR_CDM + 0x22 u8 byte1,2,3 */ + + volatile u8 pll_lock; /* MBAR_CDM + 0x24 reg9 byte0 */ + volatile u8 pll_looselock; /* MBAR_CDM + 0x25 reg9 byte1 */ + volatile u8 pll_sm_lockwin; /* MBAR_CDM + 0x26 reg9 byte2 */ + volatile u8 reserved3; /* MBAR_CDM + 0x27 reg9 byte3 */ + + volatile u16 reserved4; /* MBAR_CDM + 0x28 reg10 byte0,1 */ + volatile u16 mclken_div_psc1;/* MBAR_CDM + 0x2a reg10 byte2,3 */ + + volatile u16 reserved5; /* MBAR_CDM + 0x2c reg11 byte0,1 */ + volatile u16 mclken_div_psc2;/* MBAR_CDM + 0x2e reg11 byte2,3 */ + + volatile u16 reserved6; /* MBAR_CDM + 0x30 reg12 byte0,1 */ + volatile u16 mclken_div_psc3;/* MBAR_CDM + 0x32 reg12 byte2,3 */ + + volatile u16 reserved7; /* MBAR_CDM + 0x34 reg13 byte0,1 */ + volatile u16 mclken_div_psc6;/* MBAR_CDM + 0x36 reg13 byte2,3 */ +}; + +#endif /* __ASSEMBLY__ */ + + +/* ========================================================================= */ +/* Prototypes for MPC52xx syslib */ +/* ========================================================================= */ + +#ifndef __ASSEMBLY__ + +extern void mpc52xx_init_irq(void); +extern int mpc52xx_get_irq(struct pt_regs *regs); + +extern unsigned long mpc52xx_find_end_of_memory(void); +extern void mpc52xx_set_bat(void); +extern void mpc52xx_map_io(void); +extern void mpc52xx_restart(char *cmd); +extern void mpc52xx_halt(void); +extern void mpc52xx_power_off(void); +extern void mpc52xx_progress(char *s, unsigned short hex); +extern void mpc52xx_calibrate_decr(void); +extern void mpc52xx_add_board_devices(struct ocp_def board_ocp[]); + +#endif /* __ASSEMBLY__ */ + + +/* ========================================================================= */ +/* Platform configuration */ +/* ========================================================================= */ + +/* The U-Boot platform information struct */ +extern bd_t __res; + +/* Platform options */ +#if defined(CONFIG_LITE5200) +#include +#endif + + +#endif /* __ASM_MPC52xx_H__ */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ppc/mpc52xx_psc.h 2004-07-13 17:09:23.000000000 -0700 @@ -0,0 +1,191 @@ +/* + * include/asm-ppc/mpc52xx_psc.h + * + * Definitions of consts/structs to drive the Freescale MPC52xx OnChip + * PSCs. Theses are shared between multiple drivers since a PSC can be + * UART, AC97, IR, I2S, ... So this header is in asm-ppc. + * + * + * Maintainer : Sylvain Munaut + * + * Based/Extracted from some header of the 2.4 originally written by + * Dale Farnsworth + * + * Copyright (C) 2004 Sylvain Munaut + * Copyright (C) 2003 MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __MPC52xx_PSC_H__ +#define __MPC52xx_PSC_H__ + +#include + +/* Max number of PSCs */ +#define MPC52xx_PSC_MAXNUM 6 + +/* Programmable Serial Controller (PSC) status register bits */ +#define MPC52xx_PSC_SR_CDE 0x0080 +#define MPC52xx_PSC_SR_RXRDY 0x0100 +#define MPC52xx_PSC_SR_RXFULL 0x0200 +#define MPC52xx_PSC_SR_TXRDY 0x0400 +#define MPC52xx_PSC_SR_TXEMP 0x0800 +#define MPC52xx_PSC_SR_OE 0x1000 +#define MPC52xx_PSC_SR_PE 0x2000 +#define MPC52xx_PSC_SR_FE 0x4000 +#define MPC52xx_PSC_SR_RB 0x8000 + +/* PSC Command values */ +#define MPC52xx_PSC_RX_ENABLE 0x0001 +#define MPC52xx_PSC_RX_DISABLE 0x0002 +#define MPC52xx_PSC_TX_ENABLE 0x0004 +#define MPC52xx_PSC_TX_DISABLE 0x0008 +#define MPC52xx_PSC_SEL_MODE_REG_1 0x0010 +#define MPC52xx_PSC_RST_RX 0x0020 +#define MPC52xx_PSC_RST_TX 0x0030 +#define MPC52xx_PSC_RST_ERR_STAT 0x0040 +#define MPC52xx_PSC_RST_BRK_CHG_INT 0x0050 +#define MPC52xx_PSC_START_BRK 0x0060 +#define MPC52xx_PSC_STOP_BRK 0x0070 + +/* PSC TxRx FIFO status bits */ +#define MPC52xx_PSC_RXTX_FIFO_ERR 0x0040 +#define MPC52xx_PSC_RXTX_FIFO_UF 0x0020 +#define MPC52xx_PSC_RXTX_FIFO_OF 0x0010 +#define MPC52xx_PSC_RXTX_FIFO_FR 0x0008 +#define MPC52xx_PSC_RXTX_FIFO_FULL 0x0004 +#define MPC52xx_PSC_RXTX_FIFO_ALARM 0x0002 +#define MPC52xx_PSC_RXTX_FIFO_EMPTY 0x0001 + +/* PSC interrupt mask bits */ +#define MPC52xx_PSC_IMR_TXRDY 0x0100 +#define MPC52xx_PSC_IMR_RXRDY 0x0200 +#define MPC52xx_PSC_IMR_DB 0x0400 +#define MPC52xx_PSC_IMR_IPC 0x8000 + +/* PSC input port change bit */ +#define MPC52xx_PSC_CTS 0x01 +#define MPC52xx_PSC_DCD 0x02 +#define MPC52xx_PSC_D_CTS 0x10 +#define MPC52xx_PSC_D_DCD 0x20 + +/* PSC mode fields */ +#define MPC52xx_PSC_MODE_5_BITS 0x00 +#define MPC52xx_PSC_MODE_6_BITS 0x01 +#define MPC52xx_PSC_MODE_7_BITS 0x02 +#define MPC52xx_PSC_MODE_8_BITS 0x03 +#define MPC52xx_PSC_MODE_BITS_MASK 0x03 +#define MPC52xx_PSC_MODE_PAREVEN 0x00 +#define MPC52xx_PSC_MODE_PARODD 0x04 +#define MPC52xx_PSC_MODE_PARFORCE 0x08 +#define MPC52xx_PSC_MODE_PARNONE 0x10 +#define MPC52xx_PSC_MODE_ERR 0x20 +#define MPC52xx_PSC_MODE_FFULL 0x40 +#define MPC52xx_PSC_MODE_RXRTS 0x80 + +#define MPC52xx_PSC_MODE_ONE_STOP_5_BITS 0x00 +#define MPC52xx_PSC_MODE_ONE_STOP 0x07 +#define MPC52xx_PSC_MODE_TWO_STOP 0x0f + +#define MPC52xx_PSC_RFNUM_MASK 0x01ff + + +/* Structure of the hardware registers */ +struct mpc52xx_psc { + volatile u8 mode; /* PSC + 0x00 */ + volatile u8 reserved0[3]; + union { /* PSC + 0x04 */ + volatile u16 status; + volatile u16 clock_select; + } sr_csr; +#define mpc52xx_psc_status sr_csr.status +#define mpc52xx_psc_clock_select sr_csr.clock_select + volatile u16 reserved1; + volatile u8 command; /* PSC + 0x08 */ +volatile u8 reserved2[3]; + union { /* PSC + 0x0c */ + volatile u8 buffer_8; + volatile u16 buffer_16; + volatile u32 buffer_32; + } buffer; +#define mpc52xx_psc_buffer_8 buffer.buffer_8 +#define mpc52xx_psc_buffer_16 buffer.buffer_16 +#define mpc52xx_psc_buffer_32 buffer.buffer_32 + union { /* PSC + 0x10 */ + volatile u8 ipcr; + volatile u8 acr; + } ipcr_acr; +#define mpc52xx_psc_ipcr ipcr_acr.ipcr +#define mpc52xx_psc_acr ipcr_acr.acr + volatile u8 reserved3[3]; + union { /* PSC + 0x14 */ + volatile u16 isr; + volatile u16 imr; + } isr_imr; +#define mpc52xx_psc_isr isr_imr.isr +#define mpc52xx_psc_imr isr_imr.imr + volatile u16 reserved4; + volatile u8 ctur; /* PSC + 0x18 */ + volatile u8 reserved5[3]; + volatile u8 ctlr; /* PSC + 0x1c */ + volatile u8 reserved6[3]; + volatile u16 ccr; /* PSC + 0x20 */ + volatile u8 reserved7[14]; + volatile u8 ivr; /* PSC + 0x30 */ + volatile u8 reserved8[3]; + volatile u8 ip; /* PSC + 0x34 */ + volatile u8 reserved9[3]; + volatile u8 op1; /* PSC + 0x38 */ + volatile u8 reserved10[3]; + volatile u8 op0; /* PSC + 0x3c */ + volatile u8 reserved11[3]; + volatile u32 sicr; /* PSC + 0x40 */ + volatile u8 ircr1; /* PSC + 0x44 */ + volatile u8 reserved13[3]; + volatile u8 ircr2; /* PSC + 0x44 */ + volatile u8 reserved14[3]; + volatile u8 irsdr; /* PSC + 0x4c */ + volatile u8 reserved15[3]; + volatile u8 irmdr; /* PSC + 0x50 */ + volatile u8 reserved16[3]; + volatile u8 irfdr; /* PSC + 0x54 */ + volatile u8 reserved17[3]; + volatile u16 rfnum; /* PSC + 0x58 */ + volatile u16 reserved18; + volatile u16 tfnum; /* PSC + 0x5c */ + volatile u16 reserved19; + volatile u32 rfdata; /* PSC + 0x60 */ + volatile u16 rfstat; /* PSC + 0x64 */ + volatile u16 reserved20; + volatile u8 rfcntl; /* PSC + 0x68 */ + volatile u8 reserved21[5]; + volatile u16 rfalarm; /* PSC + 0x6e */ + volatile u16 reserved22; + volatile u16 rfrptr; /* PSC + 0x72 */ + volatile u16 reserved23; + volatile u16 rfwptr; /* PSC + 0x76 */ + volatile u16 reserved24; + volatile u16 rflrfptr; /* PSC + 0x7a */ + volatile u16 reserved25; + volatile u16 rflwfptr; /* PSC + 0x7e */ + volatile u32 tfdata; /* PSC + 0x80 */ + volatile u16 tfstat; /* PSC + 0x84 */ + volatile u16 reserved26; + volatile u8 tfcntl; /* PSC + 0x88 */ + volatile u8 reserved27[5]; + volatile u16 tfalarm; /* PSC + 0x8e */ + volatile u16 reserved28; + volatile u16 tfrptr; /* PSC + 0x92 */ + volatile u16 reserved29; + volatile u16 tfwptr; /* PSC + 0x96 */ + volatile u16 reserved30; + volatile u16 tflrfptr; /* PSC + 0x9a */ + volatile u16 reserved31; + volatile u16 tflwfptr; /* PSC + 0x9e */ +}; + + +#endif /* __MPC52xx_PSC_H__ */ --- linux-2.6.8-rc1/include/asm-ppc/ocp_ids.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ppc/ocp_ids.h 2004-07-13 17:09:23.000000000 -0700 @@ -42,6 +42,7 @@ #define OCP_FUNC_16550 0x0031 #define OCP_FUNC_IIC 0x0032 #define OCP_FUNC_USB 0x0033 +#define OCP_FUNC_PSC_UART 0x0034 /* Memory devices 0x0090 - 0x009F */ #define OCP_FUNC_MAL 0x0090 --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-ppc/perfctr.h 2004-07-13 17:09:35.000000000 -0700 @@ -0,0 +1,170 @@ +/* $Id: perfctr.h,v 1.6 2004/05/30 14:47:34 mikpe Exp $ + * PPC32 Performance-Monitoring Counters driver + * + * Copyright (C) 2004 Mikael Pettersson + */ +#ifndef _ASM_PPC_PERFCTR_H +#define _ASM_PPC_PERFCTR_H + +/* perfctr_info.cpu_type values */ +#define PERFCTR_PPC_GENERIC 0 +#define PERFCTR_PPC_604 1 +#define PERFCTR_PPC_604e 2 +#define PERFCTR_PPC_750 3 +#define PERFCTR_PPC_7400 4 +#define PERFCTR_PPC_7450 5 + +struct perfctr_sum_ctrs { + unsigned long long tsc; + unsigned long long pmc[8]; +}; + +struct perfctr_cpu_control { + unsigned int tsc_on; + unsigned int nractrs; /* # of a-mode counters */ + unsigned int nrictrs; /* # of i-mode counters */ + unsigned int pmc_map[8]; + unsigned int evntsel[8]; /* one per counter, even on P5 */ + int ireset[8]; /* [0,0x7fffffff], for i-mode counters */ + struct { + unsigned int mmcr0; /* sans PMC{1,2}SEL */ + unsigned int mmcr2; /* only THRESHMULT */ + /* IABR/DABR/BAMR not supported */ + } ppc; + unsigned int _reserved1; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +struct perfctr_cpu_state { + unsigned int cstatus; + struct { /* k1 is opaque in the user ABI */ + unsigned int id; + int isuspend_cpu; + } k1; + /* The two tsc fields must be inlined. Placing them in a + sub-struct causes unwanted internal padding on x86-64. */ + unsigned int tsc_start; + unsigned long long tsc_sum; + struct { + unsigned int map; + unsigned int start; + unsigned long long sum; + } pmc[8]; /* the size is not part of the user ABI */ +#ifdef __KERNEL__ + unsigned int ppc_mmcr[3]; + struct perfctr_cpu_control control; +#endif +}; + +/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs + which should have less overhead in most cases */ +/* XXX: ppc driver internally also uses cstatus&(1<<30) */ + +static inline +unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs, + unsigned int nrictrs) +{ + return (tsc_on<<31) | (nrictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs; +} + +static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus) +{ + return cstatus; +} + +static inline int perfctr_cstatus_has_tsc(unsigned int cstatus) +{ + return (int)cstatus < 0; /* test and jump on sign */ +} + +static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus) +{ + return cstatus & 0x7F; /* and with imm8 */ +} + +static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus) +{ + return (cstatus >> 8) & 0x7F; +} + +static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus) +{ + return cstatus & (0x7F << 16); +} + +/* + * 'struct siginfo' support for perfctr overflow signals. + * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask + * describing which perfctrs overflowed is put in si_pmc_ovf_mask. + * A bitmask is used since more than one perfctr can have overflowed + * by the time the interrupt handler runs. + * + * glibc's doesn't seem to define __SI_FAULT or __SI_CODE(), + * and including as well may cause redefinition errors, + * so the user and kernel values are different #defines here. + */ +#ifdef __KERNEL__ +#define SI_PMC_OVF (__SI_FAULT|'P') +#else +#define SI_PMC_OVF ('P') +#endif +#define si_pmc_ovf_mask _sifields._pad[0] /* XXX: use an unsigned field later */ + +/* version number for user-visible CPU-specific data */ +#define PERFCTR_CPU_VERSION 0 /* XXX: not yet cast in stone */ + +#ifdef __KERNEL__ + +#if defined(CONFIG_PERFCTR) + +/* Driver init/exit. */ +extern int perfctr_cpu_init(void); +extern void perfctr_cpu_exit(void); + +/* CPU type name. */ +extern char *perfctr_cpu_name; + +/* Hardware reservation. */ +extern const char *perfctr_cpu_reserve(const char *service); +extern void perfctr_cpu_release(const char *service); + +/* PRE: state has no running interrupt-mode counters. + Check that the new control data is valid. + Update the driver's private control data. + Returns a negative error code if the control data is invalid. */ +extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global); + +/* Read a-mode counters. Subtract from start and accumulate into sums. + Must be called with preemption disabled. */ +extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state); + +/* Write control registers. Read a-mode counters into start. + Must be called with preemption disabled. */ +extern void perfctr_cpu_resume(struct perfctr_cpu_state *state); + +/* Perform an efficient combined suspend/resume operation. + Must be called with preemption disabled. */ +extern void perfctr_cpu_sample(struct perfctr_cpu_state *state); + +/* The type of a perfctr overflow interrupt handler. + It will be called in IRQ context, with preemption disabled. */ +typedef void (*perfctr_ihandler_t)(unsigned long pc); + +/* Operations related to overflow interrupt handling. + XXX: The hardware supports overflow interrupts, but the driver + does not yet enable this due to an erratum in 750/7400/7410. */ +#ifdef CONFIG_PERFCTR_INTERRUPT_SUPPORT +extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t); +extern void perfctr_cpu_ireload(struct perfctr_cpu_state*); +extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*); +#else +static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { } +#endif + +#endif /* CONFIG_PERFCTR */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_PPC_PERFCTR_H */ --- linux-2.6.8-rc1/include/asm-ppc/ppcboot.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ppc/ppcboot.h 2004-07-13 17:09:23.000000000 -0700 @@ -55,6 +55,9 @@ typedef struct bd_info { #if defined(CONFIG_8xx) || defined(CONFIG_CPM2) || defined(CONFIG_85xx) unsigned long bi_immr_base; /* base of IMMR register */ #endif +#if defined(CONFIG_PPC_MPC52xx) + unsigned long bi_mbar_base; /* base of internal registers */ +#endif unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ unsigned long bi_ip_addr; /* IP Address */ unsigned char bi_enetaddr[6]; /* Ethernet address */ @@ -67,6 +70,10 @@ typedef struct bd_info { unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */ unsigned long bi_vco; /* VCO Out from PLL, in MHz */ #endif +#if defined(CONFIG_PPC_MPC52xx) + unsigned long bi_ipbfreq; /* IPB Bus Freq, in MHz */ + unsigned long bi_pcifreq; /* PCI Bus Freq, in MHz */ +#endif unsigned long bi_baudrate; /* Console Baudrate */ #if defined(CONFIG_405GP) unsigned char bi_s_version[4]; /* Version of this structure */ --- linux-2.6.8-rc1/include/asm-ppc/processor.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ppc/processor.h 2004-07-13 17:09:34.000000000 -0700 @@ -126,6 +126,7 @@ struct thread_struct { unsigned long spefscr; /* SPE & eFP status */ int used_spe; /* set if process has used spe */ #endif /* CONFIG_SPE */ + struct vperfctr *perfctr; /* performance counters */ }; #define ARCH_MIN_TASKALIGN 16 --- linux-2.6.8-rc1/include/asm-ppc/reg.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-ppc/reg.h 2004-07-13 17:09:34.000000000 -0700 @@ -269,22 +269,14 @@ #define SPRN_LDSTCR 0x3f8 /* Load/Store control register */ #define SPRN_LDSTDB 0x3f4 /* */ #define SPRN_LR 0x008 /* Link Register */ -#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 */ -#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 */ #ifndef SPRN_PIR #define SPRN_PIR 0x3FF /* Processor Identification Register */ #endif -#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 */ -#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 */ -#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 */ -#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 */ #define SPRN_PTEHI 0x3D5 /* 981 7450 PTE HI word (S/W TLB load) */ #define SPRN_PTELO 0x3D6 /* 982 7450 PTE LO word (S/W TLB load) */ #define SPRN_PVR 0x11F /* Processor Version Register */ #define SPRN_RPA 0x3D6 /* Required Physical Address Register */ -#define SPRN_SDA 0x3BF /* Sampled Data Address Register */ #define SPRN_SDR1 0x019 /* MMU Hash Base Register */ -#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register */ #define SPRN_SPRG0 0x110 /* Special Purpose Register General 0 */ #define SPRN_SPRG1 0x111 /* Special Purpose Register General 1 */ #define SPRN_SPRG2 0x112 /* Special Purpose Register General 2 */ @@ -311,16 +303,79 @@ #define SPRN_THRM3 0x3FE /* Thermal Management Register 3 */ #define THRM3_E (1<<0) #define SPRN_TLBMISS 0x3D4 /* 980 7450 TLB Miss Register */ -#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 */ -#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 */ -#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 */ -#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 */ -#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ -#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ -#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ #define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ +/* Performance-monitoring control and counter registers */ +#define SPRN_MMCR0 0x3B8 /* Monitor Mode Control Register 0 (604 and up) */ +#define SPRN_MMCR1 0x3BC /* Monitor Mode Control Register 1 (604e and up) */ +#define SPRN_MMCR2 0x3B0 /* Monitor Mode Control Register 2 (7400 and up) */ +#define SPRN_PMC1 0x3B9 /* Performance Counter Register 1 (604 and up) */ +#define SPRN_PMC2 0x3BA /* Performance Counter Register 2 (604 and up) */ +#define SPRN_PMC3 0x3BD /* Performance Counter Register 3 (604e and up) */ +#define SPRN_PMC4 0x3BE /* Performance Counter Register 4 (604e and up) */ +#define SPRN_PMC5 0x3B1 /* Performance Counter Register 5 (7450 and up) */ +#define SPRN_PMC6 0x3B2 /* Performance Counter Register 6 (7450 and up) */ +#define SPRN_SIA 0x3BB /* Sampled Instruction Address Register (604 and up) */ +#define SPRN_SDA 0x3BF /* Sampled Data Address Register (604/604e only) */ +#define SPRN_BAMR 0x3B7 /* Breakpoint Address Mask Register (7400 and up) */ + +#define SPRN_UMMCR0 0x3A8 /* User Monitor Mode Control Register 0 (750 and up) */ +#define SPRN_UMMCR1 0x3AC /* User Monitor Mode Control Register 0 (750 and up) */ +#define SPRN_UMMCR2 0x3A0 /* User Monitor Mode Control Register 0 (7400 and up) */ +#define SPRN_UPMC1 0x3A9 /* User Performance Counter Register 1 (750 and up) */ +#define SPRN_UPMC2 0x3AA /* User Performance Counter Register 2 (750 and up) */ +#define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 (750 and up) */ +#define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 (750 and up) */ +#define SPRN_UPMC5 0x3A1 /* User Performance Counter Register 5 (7450 and up) */ +#define SPRN_UPMC6 0x3A2 /* User Performance Counter Register 5 (7450 and up) */ +#define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register (750 and up) */ +#define SPRN_UBAMR 0x3A7 /* User Breakpoint Address Mask Register (7400 and up) */ + +/* MMCR0 layout (74xx terminology) */ +#define MMCR0_FC 0x80000000 /* Freeze counters unconditionally. */ +#define MMCR0_FCS 0x40000000 /* Freeze counters while MSR[PR]=0 (supervisor mode). */ +#define MMCR0_FCP 0x20000000 /* Freeze counters while MSR[PR]=1 (user mode). */ +#define MMCR0_FCM1 0x10000000 /* Freeze counters while MSR[PM]=1. */ +#define MMCR0_FCM0 0x08000000 /* Freeze counters while MSR[PM]=0. */ +#define MMCR0_PMXE 0x04000000 /* Enable performance monitor exceptions. + * Cleared by hardware when a PM exception occurs. + * 604: PMXE is not cleared by hardware. + */ +#define MMCR0_FCECE 0x02000000 /* Freeze counters on enabled condition or event. + * FCECE is treated as 0 if TRIGGER is 1. + * 74xx: FC is set when the event occurs. + * 604/750: ineffective when PMXE=0. + */ +#define MMCR0_TBSEL 0x01800000 /* Time base lower (TBL) bit selector. + * 00: bit 31, 01: bit 23, 10: bit 19, 11: bit 15. + */ +#define MMCR0_TBEE 0x00400000 /* Enable event on TBL bit transition from 0 to 1. */ +#define MMCR0_THRESHOLD 0x003F0000 /* Threshold value for certain events. */ +#define MMCR0_PMC1CE 0x00008000 /* Enable event on PMC1 overflow. */ +#define MMCR0_PMCjCE 0x00004000 /* Enable event on PMC2-PMC6 overflow. + * 604/750: Overrides FCECE (DISCOUNT). + */ +#define MMCR0_TRIGGER 0x00002000 /* Disable PMC2-PMC6 until PMC1 overflow or other event. + * 74xx: cleared by hardware when the event occurs. + */ +#define MMCR0_PMC1SEL 0x00001FB0 /* PMC1 event selector, 7 bits. */ +#define MMCR0_PMC2SEL 0x0000003F /* PMC2 event selector, 6 bits. */ + +/* MMCR1 layout (604e-7457) */ +#define MMCR1_PMC3SEL 0xF8000000 /* PMC3 event selector, 5 bits. */ +#define MMCR1_PMC4SEL 0x07B00000 /* PMC4 event selector, 5 bits. */ +#define MMCR1_PMC5SEL 0x003E0000 /* PMC5 event selector, 5 bits. (745x only) */ +#define MMCR1_PMC6SEL 0x0001F800 /* PMC6 event selector, 6 bits. (745x only) */ +#define MMCR1__RESERVED 0x000007FF /* should be zero */ + +/* MMCR2 layout (7400-7457) */ +#define MMCR2_THRESHMULT 0x80000000 /* MMCR0[THRESHOLD] multiplier. */ +#define MMCR2_SMCNTEN 0x40000000 /* 7400/7410 only, should be zero. */ +#define MMCR2_SMINTEN 0x20000000 /* 7400/7410 only, should be zero. */ +#define MMCR2__RESERVED 0x1FFFFFFF /* should be zero */ +#define MMCR2_RESERVED (MMCR2_SMCNTEN | MMCR2_SMINTEN | MMCR2__RESERVED) + /* Bit definitions for MMCR0 and PMC1 / PMC2. */ #define MMCR0_PMC1_CYCLES (1 << 7) #define MMCR0_PMC1_ICACHEMISS (5 << 7) --- linux-2.6.8-rc1/include/asm-ppc/uaccess.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/asm-ppc/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -327,6 +327,8 @@ copy_to_user(void __user *to, const void __copy_tofrom_user((void __user *)(to), (from), (size)) #define __copy_to_user(to, from, size) \ __copy_tofrom_user((to), (void __user *)(from), (size)) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user extern unsigned long __clear_user(void __user *addr, unsigned long size); --- linux-2.6.8-rc1/include/asm-ppc/unistd.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-ppc/unistd.h 2004-07-13 17:09:34.000000000 -0700 @@ -273,8 +273,14 @@ #define __NR_mq_notify 266 #define __NR_mq_getsetattr 267 #define __NR_kexec_load 268 +#define __NR_perfctr_info 269 +#define __NR_vperfctr_open (__NR_perfctr_info+1) +#define __NR_vperfctr_control (__NR_perfctr_info+2) +#define __NR_vperfctr_unlink (__NR_perfctr_info+3) +#define __NR_vperfctr_iresume (__NR_perfctr_info+4) +#define __NR_vperfctr_read (__NR_perfctr_info+5) -#define __NR_syscalls 269 +#define __NR_syscalls 275 #define __NR(n) #n --- linux-2.6.8-rc1/include/asm-s390/uaccess.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-s390/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -272,6 +272,9 @@ __copy_to_user(void __user *to, const vo return __copy_to_user_asm(from, n, to); } +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + /** * copy_to_user: - Copy a block of data into user space. * @to: Destination address, in user space. --- linux-2.6.8-rc1/include/asm-sh64/uaccess.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-sh64/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -261,6 +261,9 @@ if (__copy_from_user(to,from,n)) \ return retval; \ }) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + /* XXX: Not sure it works well.. should be such that: 4byte clear and the rest. */ extern __kernel_size_t __clear_user(void *addr, __kernel_size_t size); --- linux-2.6.8-rc1/include/asm-sh/uaccess.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/asm-sh/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -446,6 +446,10 @@ __copy_res; }) __copy_user((void *)(to), \ (void *)(from), n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + + #define copy_from_user(to,from,n) ({ \ void *__copy_to = (void *) (to); \ void *__copy_from = (void *) (from); \ --- linux-2.6.8-rc1/include/asm-sparc64/asi.h 2003-08-08 22:55:14.000000000 -0700 +++ 25/include/asm-sparc64/asi.h 2004-07-13 17:09:13.000000000 -0700 @@ -8,125 +8,138 @@ */ /* V9 Architecture mandary ASIs. */ -#define ASI_N 0x04 /* Nucleus */ -#define ASI_NL 0x0c /* Nucleus, little endian */ -#define ASI_AIUP 0x10 /* Primary, user */ -#define ASI_AIUS 0x11 /* Secondary, user */ -#define ASI_AIUPL 0x18 /* Primary, user, little endian */ -#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ -#define ASI_P 0x80 /* Primary, implicit */ -#define ASI_S 0x81 /* Secondary, implicit */ -#define ASI_PNF 0x82 /* Primary, no fault */ -#define ASI_SNF 0x83 /* Secondary, no fault */ -#define ASI_PL 0x88 /* Primary, implicit, little endian */ -#define ASI_SL 0x89 /* Secondary, implicit, little endian */ -#define ASI_PNFL 0x8a /* Primary, no fault, little endian */ -#define ASI_SNFL 0x8b /* Secondary, no fault, little endian */ +#define ASI_N 0x04 /* Nucleus */ +#define ASI_NL 0x0c /* Nucleus, little endian */ +#define ASI_AIUP 0x10 /* Primary, user */ +#define ASI_AIUS 0x11 /* Secondary, user */ +#define ASI_AIUPL 0x18 /* Primary, user, little endian */ +#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ +#define ASI_P 0x80 /* Primary, implicit */ +#define ASI_S 0x81 /* Secondary, implicit */ +#define ASI_PNF 0x82 /* Primary, no fault */ +#define ASI_SNF 0x83 /* Secondary, no fault */ +#define ASI_PL 0x88 /* Primary, implicit, l-endian */ +#define ASI_SL 0x89 /* Secondary, implicit, l-endian */ +#define ASI_PNFL 0x8a /* Primary, no fault, l-endian */ +#define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */ /* SpitFire and later extended ASIs. The "(III)" marker designates - * UltraSparc-III specific ASIs. + * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates + * Chip Multi Threading specific ASIs. */ -#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ -#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ -#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian */ -#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ -#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ -#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, little endian */ -#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data status RAM diag */ -#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ -#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ -#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ -#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ -#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ -#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ -#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ -#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qword load, little endian */ -#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ -#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ -#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ -#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ -#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ -#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control Register */ -#define ASI_DCACHE_DATA 0x46 /* Data cache data-ram diag access */ -#define ASI_DCACHE_TAG 0x47 /* Data cache tag/valid ram diag access */ -#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ -#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ -#define ASI_UPA_CONFIG 0x4a /* UPA config space */ -#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ -#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ -#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ -#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ -#define ASI_AFSR 0x4c /* Async fault status register */ -#define ASI_AFAR 0x4d /* Async fault address register */ -#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag access */ -#define ASI_IMMU 0x50 /* Insn-MMU main register space */ -#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer register */ -#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer register */ -#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in register */ -#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access register */ -#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read register */ -#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ -#define ASI_DMMU 0x58 /* Data-MMU main register space */ -#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer register */ -#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer register */ -#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer register */ -#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in register */ -#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access register */ -#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read register */ -#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ -#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint register */ -#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag access */ -#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag access */ -#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram diag */ -#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag access */ -#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag access */ -#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag */ -#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ -#define ASI_BLK_AIUS 0x71 /* Secondary, user, block load/store */ -#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller registers */ -#define ASI_EC_DATA 0x74 /* (III) E-cache data staging register */ -#define ASI_EC_CTRL 0x75 /* (III) E-cache control register */ -#define ASI_EC_W 0x76 /* E-cache diag write access */ -#define ASI_UDB_ERROR_W 0x77 /* External UDB error registers write */ -#define ASI_UDB_CONTROL_W 0x77 /* External UDB control registers write */ -#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ -#define ASI_INTR_DATAN_W 0x77 /* (III) Outgoing irq vector data reg N */ -#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ -#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st */ -#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st */ -#define ASI_EC_R 0x7e /* E-cache diag read access */ -#define ASI_UDBH_ERROR_R 0x7f /* External UDB error registers read hi */ -#define ASI_UDBL_ERROR_R 0x7f /* External UDB error registers read low */ -#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control registers read hi */ -#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control registers read low */ -#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ -#define ASI_INTR_DATAN_R 0x7f /* (III) Incoming irq vector data reg N */ -#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ -#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ -#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ -#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ -#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ -#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ -#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, little */ -#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, little */ -#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, little */ -#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, little */ -#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, little */ -#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, little */ -#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ -#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ -#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ -#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ -#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, little */ -#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, little */ -#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st, little */ -#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ -#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ -#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ -#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ -#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ -#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ +#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ +#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ +#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ +#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ +#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ +#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ +#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ +#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ +#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ +#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ +#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ +#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ +#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ +#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */ +#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ +#define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */ +#define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */ +#define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */ +#define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */ +#define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */ +#define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */ +#define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */ +#define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */ +#define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */ +#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ +#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ +#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ +#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ +#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */ +#define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */ +#define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/ +#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ +#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ +#define ASI_UPA_CONFIG 0x4a /* UPA config space */ +#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ +#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ +#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ +#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ +#define ASI_AFSR 0x4c /* Async fault status register */ +#define ASI_AFAR 0x4d /* Async fault address register */ +#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ +#define ASI_IMMU 0x50 /* Insn-MMU main register space */ +#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ +#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ +#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */ +#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */ +#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */ +#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ +#define ASI_DMMU 0x58 /* Data-MMU main register space */ +#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */ +#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */ +#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */ +#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */ +#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */ +#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */ +#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ +#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */ +#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */ +#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */ +#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */ +#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */ +#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */ +#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */ +#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */ +#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */ +#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/ +#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ +#define ASI_BLK_AIUS 0x71 /* Secondary, user, block ld/st */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */ +#define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */ +#define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */ +#define ASI_EC_W 0x76 /* E-cache diag write access */ +#define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */ +#define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */ +#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ +#define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */ +#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ +#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/ +#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/ +#define ASI_EC_R 0x7e /* E-cache diag read access */ +#define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */ +#define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */ +#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */ +#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ +#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ +#define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ +#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ +#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ +#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ +#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ +#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ +#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ +#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */ +#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */ +#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */ +#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */ +#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */ +#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */ +#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ +#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ +#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ +#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ +#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */ +#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/ +#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */ +#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ +#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ +#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ +#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ +#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ +#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ +#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ #endif /* _SPARC64_ASI_H */ --- linux-2.6.8-rc1/include/asm-sparc64/bpp.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/asm-sparc64/bpp.h 2004-07-13 17:09:13.000000000 -0700 @@ -40,9 +40,9 @@ */ # define BPP_PUT_PINS _IOW('B', 1, int) -# define BPP_GET_PINS _IOR('B', 2, void) +# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */ # define BPP_PUT_DATA _IOW('B', 3, int) -# define BPP_GET_DATA _IOR('B', 4, void) +# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */ /* * Set the data bus to input mode. Disengage the data bin driver and --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-sparc64/cmt.h 2004-07-13 17:09:13.000000000 -0700 @@ -0,0 +1,59 @@ +#ifndef _SPARC64_CMT_H +#define _SPARC64_CMT_H + +/* cmt.h: Chip Multi-Threading register definitions + * + * Copyright (C) 2004 David S. Miller (davem@redhat.com) + */ + +/* ASI_CORE_ID - private */ +#define LP_ID 0x0000000000000010UL +#define LP_ID_MAX 0x00000000003f0000UL +#define LP_ID_ID 0x000000000000003fUL + +/* ASI_INTR_ID - private */ +#define LP_INTR_ID 0x0000000000000000UL +#define LP_INTR_ID_ID 0x00000000000003ffUL + +/* ASI_CESR_ID - private */ +#define CESR_ID 0x0000000000000040UL +#define CESR_ID_ID 0x00000000000000ffUL + +/* ASI_CORE_AVAILABLE - shared */ +#define LP_AVAIL 0x0000000000000000UL +#define LP_AVAIL_1 0x0000000000000002UL +#define LP_AVAIL_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE_STATUS - shared */ +#define LP_ENAB_STAT 0x0000000000000010UL +#define LP_ENAB_STAT_1 0x0000000000000002UL +#define LP_ENAB_STAT_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE - shared */ +#define LP_ENAB 0x0000000000000020UL +#define LP_ENAB_1 0x0000000000000002UL +#define LP_ENAB_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING - shared */ +#define LP_RUNNING_RW 0x0000000000000050UL +#define LP_RUNNING_W1S 0x0000000000000060UL +#define LP_RUNNING_W1C 0x0000000000000068UL +#define LP_RUNNING_1 0x0000000000000002UL +#define LP_RUNNING_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING_STAT - shared */ +#define LP_RUN_STAT 0x0000000000000058UL +#define LP_RUN_STAT_1 0x0000000000000002UL +#define LP_RUN_STAT_0 0x0000000000000001UL + +/* ASI_XIR_STEERING - shared */ +#define LP_XIR_STEER 0x0000000000000030UL +#define LP_XIR_STEER_1 0x0000000000000002UL +#define LP_XIR_STEER_0 0x0000000000000001UL + +/* ASI_CMT_ERROR_STEERING - shared */ +#define CMT_ER_STEER 0x0000000000000040UL +#define CMT_ER_STEER_1 0x0000000000000002UL +#define CMT_ER_STEER_0 0x0000000000000001UL + +#endif /* _SPARC64_CMT_H */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-sparc64/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + */ + +#ifndef _SPARC64_LOCKMETER_H +#define _SPARC64_LOCKMETER_H + +#include +#include +#include +#include + +/* Actually, this is not the CPU frequency by the system tick + * frequency which is good enough for lock metering. + */ +#define CPU_CYCLE_FREQUENCY (timer_tick_offset * HZ) +#define THIS_CPU_NUMBER smp_processor_id() + +#define PUT_INDEX(lock_ptr,indexv) (lock_ptr)->index = (indexv) +#define GET_INDEX(lock_ptr) (lock_ptr)->index + +#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv) +#define GET_RWINDEX(rwlock_ptr) (rwlock_ptr)->index +#define PUT_RW_CPU(rwlock_ptr,cpuv) (rwlock_ptr)->cpu = (cpuv) +#define GET_RW_CPU(rwlock_ptr) (rwlock_ptr)->cpu + +#define RWLOCK_READERS(rwlock_ptr) rwlock_readers(rwlock_ptr) + +extern inline int rwlock_readers(rwlock_t *rwlock_ptr) +{ + signed int tmp = rwlock_ptr->lock; + + if (tmp > 0) + return tmp; + else + return 0; +} + +#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) < 0) +#define RWLOCK_IS_READ_LOCKED(rwlock_ptr) ((signed int)((rwlock_ptr)->lock) > 0) + +#define get_cycles64() get_cycles() + +#endif /* _SPARC64_LOCKMETER_H */ --- linux-2.6.8-rc1/include/asm-sparc64/pgalloc.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-sparc64/pgalloc.h 2004-07-13 17:09:13.000000000 -0700 @@ -196,7 +196,7 @@ pte_alloc_one(struct mm_struct *mm, unsi pte_t *pte = pte_alloc_one_kernel(mm, addr); if (pte) return virt_to_page(pte); - return 0; + return NULL; } static __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) --- linux-2.6.8-rc1/include/asm-sparc64/pgtable.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-sparc64/pgtable.h 2004-07-13 17:09:13.000000000 -0700 @@ -378,7 +378,7 @@ sun4u_get_pte (unsigned long addr) if (addr >= PAGE_OFFSET) return addr & _PAGE_PADDR; if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS)) - return prom_virt_to_phys(addr, 0); + return prom_virt_to_phys(addr, NULL); pgdp = pgd_offset_k(addr); pmdp = pmd_offset(pgdp, addr); ptep = pte_offset_kernel(pmdp, addr); --- linux-2.6.8-rc1/include/asm-sparc64/signal.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc64/signal.h 2004-07-13 17:09:13.000000000 -0700 @@ -186,9 +186,14 @@ struct sigstack { /* Type of a signal handler. */ #ifdef __KERNEL__ -typedef void (*__sighandler_t)(int, struct sigcontext *); +typedef void __signalfn_t(int); +typedef __signalfn_t __user *__sighandler_t; + +typedef void __restorefn_t(void); +typedef __restorefn_t __user *__sigrestore_t; #else typedef void (*__sighandler_t)(int); +typedef void (*__sigrestore_t)(void); #endif #define SIG_DFL ((__sighandler_t)0) /* default signal handling */ @@ -198,7 +203,7 @@ typedef void (*__sighandler_t)(int); struct __new_sigaction { __sighandler_t sa_handler; unsigned long sa_flags; - void (*sa_restorer)(void); /* not used by Linux/SPARC yet */ + __sigrestore_t sa_restorer; /* not used by Linux/SPARC yet */ __new_sigset_t sa_mask; }; @@ -233,7 +238,7 @@ struct __old_sigaction32 { #endif typedef struct sigaltstack { - void *ss_sp; + void __user *ss_sp; int ss_flags; size_t ss_size; } stack_t; --- linux-2.6.8-rc1/include/asm-sparc64/spinlock.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc64/spinlock.h 2004-07-13 17:09:29.000000000 -0700 @@ -31,15 +31,23 @@ #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned char spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 +typedef struct { + unsigned char lock; + unsigned int index; +} spinlock_t; -#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) -#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) +#ifdef CONFIG_LOCKMETER +#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, 0} +#else +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#endif -#define spin_unlock_wait(lock) \ +#define spin_lock_init(__lock) do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0) +#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0) + +#define spin_unlock_wait(__lock) \ do { membar("#LoadLoad"); \ -} while(*((volatile unsigned char *)lock)) +} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock)))) static __inline__ void _raw_spin_lock(spinlock_t *lock) { @@ -113,17 +121,31 @@ extern int _spin_trylock (spinlock_t *lo #ifndef CONFIG_DEBUG_SPINLOCK -typedef unsigned int rwlock_t; -#define RW_LOCK_UNLOCKED 0 -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) -#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED) +#ifdef CONFIG_LOCKMETER +typedef struct { + unsigned int lock; + unsigned int index; + unsigned int cpu; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0xff } +#else +typedef struct { + unsigned int lock; +} rwlock_t; +#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif + +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) +#define rwlock_is_locked(x) ((x)->lock != 0) +extern int __read_trylock(rwlock_t *); extern void __read_lock(rwlock_t *); extern void __read_unlock(rwlock_t *); extern void __write_lock(rwlock_t *); extern void __write_unlock(rwlock_t *); extern int __write_trylock(rwlock_t *); +#define _raw_read_trylock(p) __read_trylock(p) #define _raw_read_lock(p) __read_lock(p) #define _raw_read_unlock(p) __read_unlock(p) #define _raw_write_lock(p) __write_lock(p) --- linux-2.6.8-rc1/include/asm-sparc64/uaccess.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc64/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -264,6 +264,8 @@ extern unsigned long __copy_in_user(void #define copy_from_user __copy_from_user #define copy_to_user __copy_to_user #define copy_in_user __copy_in_user +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user extern unsigned long __bzero_noasi(void __user *, unsigned long); --- linux-2.6.8-rc1/include/asm-sparc/bpp.h 2003-06-14 12:18:29.000000000 -0700 +++ 25/include/asm-sparc/bpp.h 2004-07-13 17:09:13.000000000 -0700 @@ -40,9 +40,9 @@ */ # define BPP_PUT_PINS _IOW('B', 1, int) -# define BPP_GET_PINS _IOR('B', 2, void) +# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */ # define BPP_PUT_DATA _IOW('B', 3, int) -# define BPP_GET_DATA _IOR('B', 4, void) +# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */ /* * Set the data bus to input mode. Disengage the data bin driver and --- linux-2.6.8-rc1/include/asm-sparc/bug.h 2003-07-27 12:14:40.000000000 -0700 +++ 25/include/asm-sparc/bug.h 2004-07-13 17:09:13.000000000 -0700 @@ -8,7 +8,7 @@ */ #if (__GNUC__ > 3) || \ (__GNUC__ == 3 && __GNUC_MINOR__ > 3) || \ - (__GNUC__ == 3 && __GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ >= 1) + (__GNUC__ == 3 && __GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ >= 4) #define __bug_trap() __builtin_trap() #else #define __bug_trap() \ --- linux-2.6.8-rc1/include/asm-sparc/dma.h 2003-06-14 12:18:22.000000000 -0700 +++ 25/include/asm-sparc/dma.h 2004-07-13 17:09:13.000000000 -0700 @@ -19,6 +19,7 @@ #include #include +struct page; extern spinlock_t dma_spin_lock; static __inline__ unsigned long claim_dma_lock(void) @@ -244,4 +245,46 @@ extern int isa_dma_bridge_buggy; #define isa_dma_bridge_buggy (0) #endif +/* Routines for data transfer buffers. */ +BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long) +BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long) + +#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len) +#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len) + +/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */ +BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) +BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) +BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) +BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) + +#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus) +#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus) +#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus) +#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus) + +/* + * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep. + * + * The mmu_map_dma_area establishes two mappings in one go. + * These mappings point to pages normally mapped at 'va' (linear address). + * First mapping is for CPU visible address at 'a', uncached. + * This is an alias, but it works because it is an uncached mapping. + * Second mapping is for device visible address, or "bus" address. + * The bus address is returned at '*pba'. + * + * These functions seem distinct, but are hard to split. On sun4c, + * at least for now, 'a' is equal to bus address, and retured in *pba. + * On sun4m, page attributes depend on the CPU type, so we have to + * know if we are mapping RAM or I/O, so it has to be an additional argument + * to a separate mapping function for CPU visible mappings. + */ +BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len) +BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa) +BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len) + +#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len) +#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len) +#define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba) + #endif /* !(_ASM_SPARC_DMA_H) */ --- linux-2.6.8-rc1/include/asm-sparc/pci.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-sparc/pci.h 2004-07-13 17:09:13.000000000 -0700 @@ -87,6 +87,12 @@ extern dma_addr_t pci_map_page(struct pc extern void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, size_t size, int direction); +/* map_page and map_single cannot fail */ +static inline int pci_dma_mapping_error(dma_addr_t dma_addr) +{ + return 0; +} + /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the * above pci_map_single interface. Here the scatter gather list --- linux-2.6.8-rc1/include/asm-sparc/pgtable.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc/pgtable.h 2004-07-13 17:09:13.000000000 -0700 @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -33,48 +32,6 @@ struct page; extern void load_mmu(void); extern unsigned long calc_highpages(void); -/* Routines for data transfer buffers. */ -BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long) -BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long) - -#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len) -#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len) - -/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */ -BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) -BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) -BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) -BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) - -#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus) -#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus) -#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus) -#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus) - -/* - * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep. - * - * The mmu_map_dma_area establishes two mappings in one go. - * These mappings point to pages normally mapped at 'va' (linear address). - * First mapping is for CPU visible address at 'a', uncached. - * This is an alias, but it works because it is an uncached mapping. - * Second mapping is for device visible address, or "bus" address. - * The bus address is returned at '*pba'. - * - * These functions seem distinct, but are hard to split. On sun4c, - * at least for now, 'a' is equal to bus address, and retured in *pba. - * On sun4m, page attributes depend on the CPU type, so we have to - * know if we are mapping RAM or I/O, so it has to be an additional argument - * to a separate mapping function for CPU visible mappings. - */ -BTFIXUPDEF_CALL(int, mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len) -BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa) -BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, unsigned long busa, int len) - -#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len) -#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len) -#define mmu_translate_dvma(ba) BTFIXUP_CALL(mmu_translate_dvma)(ba) - BTFIXUPDEF_SIMM13(pgdir_shift) BTFIXUPDEF_SETHI(pgdir_size) BTFIXUPDEF_SETHI(pgdir_mask) --- linux-2.6.8-rc1/include/asm-sparc/pgtsrmmu.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc/pgtsrmmu.h 2004-07-13 17:09:13.000000000 -0700 @@ -106,7 +106,7 @@ * enforce all the protection levels that vma's can have. * XXX But for now... */ -#define SRMMU_PAGE_NONE __pgprot(SRMMU_VALID | SRMMU_CACHE | \ +#define SRMMU_PAGE_NONE __pgprot(SRMMU_CACHE | \ SRMMU_PRIV | SRMMU_REF) #define SRMMU_PAGE_SHARED __pgprot(SRMMU_VALID | SRMMU_CACHE | \ SRMMU_EXEC | SRMMU_WRITE | SRMMU_REF) --- linux-2.6.8-rc1/include/asm-sparc/pgtsun4.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc/pgtsun4.h 2004-07-13 17:09:13.000000000 -0700 @@ -51,6 +51,7 @@ #define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ #define _SUN4C_PAGE_PRESENT 0x08000000 /* implemented in software */ #define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ +#define _SUN4C_PAGE_FILE 0x02000000 /* implemented in software */ #define _SUN4C_PAGE_READ 0x00800000 /* implemented in software */ #define _SUN4C_PAGE_WRITE 0x00400000 /* implemented in software */ #define _SUN4C_PAGE_ACCESSED 0x00200000 /* implemented in software */ @@ -71,6 +72,21 @@ #define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\ _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV) +/* SUN4C swap entry encoding + * + * We use 5 bits for the type and 19 for the offset. This gives us + * 32 swapfiles of 4GB each. Encoding looks like: + * + * RRRRRRRRooooooooooooooooooottttt + * fedcba9876543210fedcba9876543210 + * + * The top 8 bits are reserved for protection and status bits, especially + * FILE and PRESENT. + */ +#define SUN4C_SWP_TYPE_MASK 0x1f +#define SUN4C_SWP_OFF_MASK 0x7ffff +#define SUN4C_SWP_OFF_SHIFT 5 + #ifndef __ASSEMBLY__ static inline unsigned long sun4c_get_synchronous_error(void) --- linux-2.6.8-rc1/include/asm-sparc/processor.h 2004-02-17 20:48:46.000000000 -0800 +++ 25/include/asm-sparc/processor.h 2004-07-13 17:09:13.000000000 -0700 @@ -76,20 +76,8 @@ struct thread_struct { #define SPARC_FLAG_UNALIGNED 0x2 /* is allowed to do unaligned accesses */ #define INIT_THREAD { \ -/* kregs, _pad1, */ \ - 0, 0, \ -/* fork_kpsr, fork_kwim */ \ - 0, 0, \ -/* FPU regs */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ -/* FPU status, FPU qdepth, FPU queue */ \ - 0, 0, { { 0, 0, }, }, \ -/* flags, current_ds, */ \ - SPARC_FLAG_KTHREAD, KERNEL_DS, \ -/* core_exec */ \ -{ 0, }, \ -/* new_signal */ \ - 0, \ + .flags = SPARC_FLAG_KTHREAD, \ + .current_ds = KERNEL_DS, \ } /* Return saved PC of a blocked thread. */ --- linux-2.6.8-rc1/include/asm-sparc/sun4prom.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/include/asm-sparc/sun4prom.h 2004-07-13 17:09:13.000000000 -0700 @@ -25,7 +25,7 @@ typedef struct { unsigned char (*getchar)(void); /* Get char from input device */ void (*putchar)(char); /* Put char to output device */ int (*mayget)(void); /* Maybe get char, or -1 */ - int (*mayput)(void); /* Maybe put char, or -1 */ + int (*mayput)(int); /* Maybe put char, or -1 */ unsigned char *echo; /* Should getchar echo? */ unsigned char *insource; /* Input source selector */ unsigned char *outsink; /* Output sink selector */ --- linux-2.6.8-rc1/include/asm-sparc/uaccess.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-sparc/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -322,6 +322,9 @@ static inline unsigned long __copy_from_ return __copy_user((void __user *) to, from, n); } +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + static inline unsigned long __clear_user(void __user *addr, unsigned long size) { unsigned long ret; --- linux-2.6.8-rc1/include/asm-sparc/vfc_ioctls.h 2003-06-14 12:18:23.000000000 -0700 +++ 25/include/asm-sparc/vfc_ioctls.h 2004-07-13 17:09:13.000000000 -0700 @@ -52,7 +52,7 @@ struct vfc_debug_inout unsigned long addr; unsigned long ret; unsigned long len; - unsigned char *buffer; + unsigned char __user *buffer; }; #endif /* _LINUX_VFC_IOCTLS_H_ */ --- linux-2.6.8-rc1/include/asm-um/archparam-i386.h 2003-06-14 12:18:30.000000000 -0700 +++ 25/include/asm-um/archparam-i386.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -56,6 +56,93 @@ typedef elf_greg_t elf_gregset_t[ELF_NGR pr_reg[16] = PT_REGS_SS(regs); \ } while(0); +#if 0 /* Turn this back on when UML has VSYSCALL working */ +#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) +#else +#define VSYSCALL_BASE 0 +#endif + +#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) +#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) +extern void *__kernel_vsyscall; + +/* + * Architecture-neutral AT_ values in 0-17, leave some room + * for more of them, start the x86-specific ones at 32. + */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ +} while (0) + +/* + * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out + * extra segments containing the vsyscall DSO contents. Dumping its + * contents makes post-mortem fully interpretable later without matching up + * the same kernel and hardware config to see what PC values meant. + * Dumping its extra ELF program headers includes all the other information + * a debugger needs to easily find how the vsyscall DSO was being used. + */ +#if 0 +#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) +#endif + +#undef ELF_CORE_EXTRA_PHDRS + +#if 0 +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + Elf32_Off ofs = 0; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + struct elf_phdr phdr = vsyscall_phdrs[i]; \ + if (phdr.p_type == PT_LOAD) { \ + ofs = phdr.p_offset = offset; \ + offset += phdr.p_filesz; \ + } \ + else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} while (0) +#define ELF_CORE_WRITE_EXTRA_DATA \ +do { \ + const struct elf_phdr *const vsyscall_phdrs = \ + (const struct elf_phdr *) (VSYSCALL_BASE \ + + VSYSCALL_EHDR->e_phoff); \ + int i; \ + for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ + if (vsyscall_phdrs[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ + vsyscall_phdrs[i].p_filesz); \ + } \ +} while (0) +#endif + +#undef ELF_CORE_WRITE_EXTRA_PHDRS +#undef ELF_CORE_WRITE_EXTRA_DATA + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + /********* Bits for asm-um/delay.h **********/ typedef unsigned long um_udelay_t; --- linux-2.6.8-rc1/include/asm-um/common.lds.S 2003-06-14 12:18:00.000000000 -0700 +++ 25/include/asm-um/common.lds.S 2004-07-13 17:09:45.000000000 -0700 @@ -1,3 +1,5 @@ +#include + .fini : { *(.fini) } =0x9090 _etext = .; PROVIDE (etext = .); @@ -13,18 +15,6 @@ RODATA - __start___ksymtab = .; /* Kernel symbol table */ - __ksymtab : { *(__ksymtab) } - __stop___ksymtab = .; - - __start___gpl_ksymtab = .; /* Kernel symbol table: GPL-only symbols */ - __gpl_ksymtab : { *(__gpl_ksymtab) } - __stop___gpl_ksymtab = .; - - __start___kallsyms = .; /* All kernel symbols */ - __kallsyms : { *(__kallsyms) } - __stop___kallsyms = .; - .unprotected : { *(.unprotected) } . = ALIGN(4096); PROVIDE (_unprotected_end = .); @@ -67,11 +57,17 @@ } __initcall_end = .; + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; + __uml_initcall_start = .; .uml.initcall.init : { *(.uml.initcall.init) } __uml_initcall_end = .; __init_end = .; + SECURITY_INIT + __exitcall_begin = .; .exitcall : { *(.exitcall.exit) } __exitcall_end = .; @@ -80,7 +76,33 @@ .uml.exitcall : { *(.uml.exitcall.exit) } __uml_exitcall_end = .; - . = ALIGN(4096); + . = ALIGN(4); + __alt_instructions = .; + .altinstructions : { *(.altinstructions) } + __alt_instructions_end = .; + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } + + __preinit_array_start = .; + .preinit_array : { *(.preinit_array) } + __preinit_array_end = .; + __init_array_start = .; + .init_array : { *(.init_array) } + __init_array_end = .; + __fini_array_start = .; + .fini_array : { *(.fini_array) } + __fini_array_end = .; + + . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exitcall.exit) + } + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-um/cpufeature.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,6 @@ +#ifndef __UM_CPUFEATURE_H +#define __UM_CPUFEATURE_H + +#include "asm/arch/cpufeature.h" + +#endif --- linux-2.6.8-rc1/include/asm-um/current.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/include/asm-um/current.h 2004-07-13 17:09:45.000000000 -0700 @@ -16,8 +16,10 @@ struct thread_info; #define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & \ (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER)) -#define current ({ int dummy; \ - ((struct thread_info *) CURRENT_THREAD(dummy))->task; }) +#define current_thread \ + ({ int dummy; ((struct thread_info *) CURRENT_THREAD(dummy)); }) + +#define current (current_thread->task) #endif /* __ASSEMBLY__ */ --- linux-2.6.8-rc1/include/asm-um/dma-mapping.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/include/asm-um/dma-mapping.h 2004-07-13 17:09:45.000000000 -0700 @@ -1 +1,119 @@ -#include +#ifndef _ASM_DMA_MAPPING_H +#define _ASM_DMA_MAPPING_H + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + BUG(); + return(0); +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG(); + return(0); +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + int flag) +{ + BUG(); + return((void *) 0); +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG(); + return(0); +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +#define dma_is_consistent(d) (1) + +static inline int +dma_get_cache_alignment(void) +{ + BUG(); + return(0); +} + +static inline void +dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_cache_sync(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +#endif --- linux-2.6.8-rc1/include/asm-um/elf.h 2003-06-14 12:18:24.000000000 -0700 +++ 25/include/asm-um/elf.h 2004-07-13 17:09:45.000000000 -0700 @@ -15,4 +15,17 @@ #define USE_ELF_CORE_DUMP +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + #endif --- linux-2.6.8-rc1/include/asm-um/fixmap.h 2003-06-14 12:18:33.000000000 -0700 +++ 25/include/asm-um/fixmap.h 2004-07-13 17:09:45.000000000 -0700 @@ -34,6 +34,7 @@ enum fixed_addresses { FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif + FIX_VSYSCALL, __end_of_fixed_addresses }; @@ -63,6 +64,13 @@ extern unsigned long get_kmem_end(void); #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) +/* + * This is the range that is readable by user mode, and things + * acting like user mode such as get_user_pages. + */ +#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL)) +#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE) + extern void __this_fixmap_does_not_exist(void); /* --- linux-2.6.8-rc1/include/asm-um/irq.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-um/irq.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,15 +1,6 @@ #ifndef __UM_IRQ_H #define __UM_IRQ_H -/* The i386 irq.h has a struct task_struct in a prototype without including - * sched.h. This forward declaration kills the resulting warning. - */ -struct task_struct; - -#include "asm/ptrace.h" - -#undef NR_IRQS - #define TIMER_IRQ 0 #define UMN_IRQ 1 #define CONSOLE_IRQ 2 @@ -28,13 +19,4 @@ struct task_struct; #define LAST_IRQ XTERM_IRQ #define NR_IRQS (LAST_IRQ + 1) -extern int um_request_irq(unsigned int irq, int fd, int type, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char * devname, - void *dev_id); - -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-um/local.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,6 @@ +#ifndef __UM_LOCAL_H +#define __UM_LOCAL_H + +#include "asm/arch/local.h" + +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-um/module-generic.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,6 @@ +#ifndef __UM_MODULE_GENERIC_H +#define __UM_MODULE_GENERIC_H + +#include "asm/arch/module.h" + +#endif --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-um/module-i386.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,13 @@ +#ifndef __UM_MODULE_I386_H +#define __UM_MODULE_I386_H + +/* UML is simple */ +struct mod_arch_specific +{ +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr + +#endif --- linux-2.6.8-rc1/include/asm-um/page.h 2003-06-14 12:18:23.000000000 -0700 +++ 25/include/asm-um/page.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,10 +1,14 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + #ifndef __UM_PAGE_H #define __UM_PAGE_H struct page; #include "asm/arch/page.h" -#include "asm/bug.h" #undef __pa #undef __va @@ -24,25 +28,36 @@ extern unsigned long uml_physmem; #define __va_space (8*1024*1024) -extern unsigned long region_pa(void *virt); -extern void *region_va(unsigned long phys); - -#define __pa(virt) region_pa((void *) (virt)) -#define __va(phys) region_va((unsigned long) (phys)) - -extern unsigned long page_to_pfn(struct page *page); -extern struct page *pfn_to_page(unsigned long pfn); +extern unsigned long to_phys(void *virt); +extern void *to_virt(unsigned long phys); -extern struct page *phys_to_page(unsigned long phys); +#define __pa(virt) to_phys((void *) virt) +#define __va(phys) to_virt((unsigned long) phys) -#define virt_to_page(v) (phys_to_page(__pa(v))) +#define page_to_pfn(page) ((page) - mem_map) +#define pfn_to_page(pfn) (mem_map + (pfn)) -extern struct page *page_mem_map(struct page *page); +#define phys_to_pfn(p) ((p) >> PAGE_SHIFT) +#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -#define pfn_valid(pfn) (page_mem_map(pfn_to_page(pfn)) != NULL) -#define virt_addr_valid(v) pfn_valid(__pa(v) >> PAGE_SHIFT) +#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v))) extern struct page *arch_validate(struct page *page, int mask, int order); #define HAVE_ARCH_VALIDATE +extern void arch_free_page(struct page *page, int order); +#define HAVE_ARCH_FREE_PAGE + #endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ --- linux-2.6.8-rc1/include/asm-um/pgtable.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-um/pgtable.h 2004-07-13 17:09:45.000000000 -0700 @@ -12,8 +12,6 @@ #include "asm/page.h" #include "asm/fixmap.h" -extern pgd_t swapper_pg_dir[1024]; - extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, pte_t *pte_out); @@ -49,6 +47,8 @@ extern unsigned long *empty_zero_page; #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + /* * pgd entries used up by user/kernel: */ @@ -65,10 +65,10 @@ extern unsigned long *empty_zero_page; * area for the same reason. ;) */ -extern unsigned long high_physmem; +extern unsigned long end_iomem; #define VMALLOC_OFFSET (__va_space) -#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) @@ -78,12 +78,13 @@ extern unsigned long high_physmem; #define _PAGE_PRESENT 0x001 #define _PAGE_NEWPAGE 0x002 -#define _PAGE_PROTNONE 0x004 /* If not present */ -#define _PAGE_RW 0x008 -#define _PAGE_USER 0x010 -#define _PAGE_ACCESSED 0x020 -#define _PAGE_DIRTY 0x040 -#define _PAGE_NEWPROT 0x080 +#define _PAGE_NEWPROT 0x004 +#define _PAGE_FILE 0x008 /* set:pagecache unset:swap */ +#define _PAGE_PROTNONE 0x010 /* If not present */ +#define _PAGE_RW 0x020 +#define _PAGE_USER 0x040 +#define _PAGE_ACCESSED 0x080 +#define _PAGE_DIRTY 0x100 #define REGION_MASK 0xf0000000 #define REGION_SHIFT 28 @@ -143,7 +144,8 @@ extern pte_t * __bad_pagetable(void); #define BAD_PAGETABLE __bad_pagetable() #define BAD_PAGE __bad_page() -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) /* number of bits that fit into a memory pointer */ #define BITS_PER_PTR (8*sizeof(unsigned long)) @@ -164,9 +166,6 @@ extern pte_t * __bad_pagetable(void); #define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0) -#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT) -#define pte_region_index(x) phys_region_index(pte_val(x)) - #define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE)) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) @@ -188,19 +187,25 @@ static inline void pgd_clear(pgd_t * pgd #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) -extern struct page *pte_mem_map(pte_t pte); -extern struct page *phys_mem_map(unsigned long phys); -extern unsigned long phys_to_pfn(unsigned long p); -extern unsigned long pfn_to_phys(unsigned long pfn); - -#define pte_page(x) pfn_to_page(pte_pfn(x)) -#define pte_address(x) (__va(pte_val(x) & PAGE_MASK)) -#define mk_phys(a, r) ((a) + (r << REGION_SHIFT)) -#define phys_addr(p) ((p) & ~REGION_MASK) -#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT)) +#define pte_page(pte) phys_to_page(pte_val(pte)) +#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) + #define pte_pfn(x) phys_to_pfn(pte_val(x)) #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot)) -#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot)) + +extern struct page *phys_to_page(const unsigned long phys); +extern struct page *__virt_to_page(const unsigned long virt); +#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) + +/* + * Bits 0 through 3 are taken + */ +#define PTE_FILE_MAX_BITS 28 + +#define pte_to_pgoff(pte) ((pte).pte_low >> 4) + +#define pgoff_to_pte(off) \ + ((pte_t) { ((off) << 4) + _PAGE_FILE }) static inline pte_t pte_mknewprot(pte_t pte) { @@ -235,6 +240,12 @@ static inline void set_pte(pte_t *pteptr * The following only work if pte_present() is true. * Undefined behaviour if not.. */ +static inline int pte_user(pte_t pte) +{ + return((pte_val(pte) & _PAGE_USER) && + !(pte_val(pte) & _PAGE_PROTNONE)); +} + static inline int pte_read(pte_t pte) { return((pte_val(pte) & _PAGE_USER) && @@ -252,6 +263,14 @@ static inline int pte_write(pte_t pte) !(pte_val(pte) & _PAGE_PROTNONE)); } +/* + * The following only works if pte_present() is not true. + */ +static inline int pte_file(pte_t pte) +{ + return (pte).pte_low & _PAGE_FILE; +} + static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; } @@ -334,14 +353,7 @@ extern unsigned long page_to_phys(struct * and a page entry and page directory to the page they refer to. */ -#define mk_pte(page, pgprot) \ -({ \ - pte_t __pte; \ - \ - pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\ - if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \ - __pte; \ -}) +extern pte_t mk_pte(struct page *page, pgprot_t pgprot); static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -351,17 +363,27 @@ static inline pte_t pte_modify(pte_t pte } #define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) -#define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \ - ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT))) -/* to find an entry in a page-table-directory. */ +/* + * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] + * + * this macro returns the index of the entry in the pgd page which would + * control the given virtual address + */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) -/* to find an entry in a page-table-directory */ +/* + * pgd_offset() returns a (pgd_t *) + * pgd_index() is used get the offset into the pgd page's array of pgd_t's; + */ #define pgd_offset(mm, address) \ ((mm)->pgd + ((address) >> PGDIR_SHIFT)) -/* to find an entry in a kernel page-table-directory */ + +/* + * a shortcut which implies the use of the kernel's pgd, instead + * of a process's + */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) #define pmd_index(address) \ @@ -373,7 +395,12 @@ static inline pmd_t * pmd_offset(pgd_t * return (pmd_t *) dir; } -/* Find an entry in the third-level page table.. */ +/* + * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] + * + * this macro returns the index of the entry in the pte page which would + * control the given virtual address + */ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, address) \ ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address)) @@ -387,11 +414,11 @@ static inline pmd_t * pmd_offset(pgd_t * #define update_mmu_cache(vma,address,pte) do ; while (0) /* Encode and de-code a swap entry */ -#define __swp_type(x) (((x).val >> 3) & 0x7f) -#define __swp_offset(x) ((x).val >> 10) +#define __swp_type(x) (((x).val >> 4) & 0x3f) +#define __swp_offset(x) ((x).val >> 11) #define __swp_entry(type, offset) \ - ((swp_entry_t) { ((type) << 3) | ((offset) << 10) }) + ((swp_entry_t) { ((type) << 4) | ((offset) << 11) }) #define __pte_to_swp_entry(pte) \ ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) --- linux-2.6.8-rc1/include/asm-um/processor-generic.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-um/processor-generic.h 2004-07-13 17:09:45.000000000 -0700 @@ -11,33 +11,14 @@ struct pt_regs; struct task_struct; #include "linux/config.h" -#include "linux/signal.h" #include "asm/ptrace.h" -#include "asm/siginfo.h" #include "choose-mode.h" struct mm_struct; #define current_text_addr() ((void *) 0) -#define cpu_relax() do ; while (0) - -#ifdef CONFIG_MODE_TT -struct proc_tt_mode { - int extern_pid; - int tracing; - int switch_pipe[2]; - int singlestep_syscall; - int vm_seq; -}; -#endif - -#ifdef CONFIG_MODE_SKAS -struct proc_skas_mode { - void *switch_buf; - void *fork_buf; -}; -#endif +#define cpu_relax() barrier() struct thread_struct { int forking; @@ -46,6 +27,7 @@ struct thread_struct { struct pt_regs regs; unsigned long cr2; int err; + unsigned long trap_no; void *fault_addr; void *fault_catcher; struct task_struct *prev_sched; @@ -54,10 +36,20 @@ struct thread_struct { struct arch_thread arch; union { #ifdef CONFIG_MODE_TT - struct proc_tt_mode tt; + struct { + int extern_pid; + int tracing; + int switch_pipe[2]; + int singlestep_syscall; + int vm_seq; + } tt; #endif #ifdef CONFIG_MODE_SKAS - struct proc_skas_mode skas; + struct { + void *switch_buf; + void *fork_buf; + int mm_count; + } skas; #endif } mode; struct { @@ -99,14 +91,19 @@ typedef struct { } mm_segment_t; extern struct task_struct *alloc_task_struct(void); -extern void free_task_struct(struct task_struct *task); extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void dump_thread(struct pt_regs *regs, struct user *u); +extern void prepare_to_copy(struct task_struct *tsk); extern unsigned long thread_saved_pc(struct task_struct *t); +static inline void mm_copy_segments(struct mm_struct *from_mm, + struct mm_struct *new_mm) +{ +} + #define init_stack (init_thread_union.stack) /* --- linux-2.6.8-rc1/include/asm-um/processor-i386.h 2003-06-14 12:17:57.000000000 -0700 +++ 25/include/asm-um/processor-i386.h 2004-07-13 17:09:45.000000000 -0700 @@ -6,8 +6,8 @@ #ifndef __UM_PROCESSOR_I386_H #define __UM_PROCESSOR_I386_H -extern int cpu_has_xmm; -extern int cpu_has_cmov; +extern int host_has_xmm; +extern int host_has_cmov; struct arch_thread { unsigned long debugregs[8]; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-um/sections.h 2004-07-13 17:09:45.000000000 -0700 @@ -0,0 +1,7 @@ +#ifndef _UM_SECTIONS_H +#define _UM_SECTIONS_H + +/* nothing to see, move along */ +#include + +#endif --- linux-2.6.8-rc1/include/asm-um/smp.h 2004-02-03 20:42:38.000000000 -0800 +++ 25/include/asm-um/smp.h 2004-07-13 17:09:45.000000000 -0700 @@ -10,7 +10,7 @@ extern cpumask_t cpu_online_map; -#define smp_processor_id() (current->thread_info->cpu) +#define smp_processor_id() (current_thread->cpu) #define cpu_logical_map(n) (n) #define cpu_number_map(n) (n) #define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ --- linux-2.6.8-rc1/include/asm-um/smplock.h 2003-06-14 12:17:59.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,6 +0,0 @@ -#ifndef __UM_SMPLOCK_H -#define __UM_SMPLOCK_H - -#include "asm/arch/smplock.h" - -#endif --- linux-2.6.8-rc1/include/asm-um/spinlock.h 2003-06-14 12:18:33.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,10 +0,0 @@ -#ifndef __UM_SPINLOCK_H -#define __UM_SPINLOCK_H - -#include "linux/config.h" - -#ifdef CONFIG_SMP -#include "asm/arch/spinlock.h" -#endif - -#endif --- linux-2.6.8-rc1/include/asm-um/system-generic.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/asm-um/system-generic.h 2004-07-13 17:09:45.000000000 -0700 @@ -23,8 +23,10 @@ extern int get_signals(void); extern void block_signals(void); extern void unblock_signals(void); -#define local_save_flags(flags) do { (flags) = get_signals(); } while(0) -#define local_irq_restore(flags) do { set_signals(flags); } while(0) +#define local_save_flags(flags) do { typecheck(unsigned long, flags); \ + (flags) = get_signals(); } while(0) +#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \ + set_signals(flags); } while(0) #define local_irq_save(flags) do { local_save_flags(flags); \ local_irq_disable(); } while(0) @@ -39,4 +41,7 @@ extern void unblock_signals(void); (flags == 0); \ }) +extern void *_switch_to(void *prev, void *next, void *last); +#define switch_to(prev, next, last) prev = _switch_to(prev, next, last) + #endif --- linux-2.6.8-rc1/include/asm-um/system-i386.h 2003-06-14 12:18:07.000000000 -0700 +++ 25/include/asm-um/system-i386.h 2004-07-13 17:09:45.000000000 -0700 @@ -2,36 +2,5 @@ #define __UM_SYSTEM_I386_H #include "asm/system-generic.h" - -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, - unsigned long new, int size) -{ - unsigned long prev; - switch (size) { - case 1: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 2: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 4: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - } - return old; -} - -#define cmpxchg(ptr,o,n)\ - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ - (unsigned long)(n),sizeof(*(ptr)))) #endif --- linux-2.6.8-rc1/include/asm-um/thread_info.h 2003-06-14 12:18:06.000000000 -0700 +++ 25/include/asm-um/thread_info.h 2004-07-13 17:09:45.000000000 -0700 @@ -9,6 +9,7 @@ #ifndef __ASSEMBLY__ #include +#include struct thread_info { struct task_struct *task; /* main task structure */ @@ -43,15 +44,18 @@ struct thread_info { static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; - __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL)); + unsigned long mask = PAGE_SIZE * + (1 << CONFIG_KERNEL_STACK_ORDER) - 1; + __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask)); return ti; } /* thread information allocation */ -#define THREAD_SIZE (4*PAGE_SIZE) -#define alloc_thread_info(tsk) ((struct thread_info *) \ - __get_free_pages(GFP_KERNEL,2)) -#define free_thread_info(ti) free_pages((unsigned long) (ti), 2) +#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) +#define alloc_thread_info(tsk) \ + ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL)) +#define free_thread_info(ti) kfree(ti) + #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) @@ -65,11 +69,13 @@ static inline struct thread_info *curren #define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling * TIF_NEED_RESCHED */ +#define TIF_RESTART_BLOCK 4 #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_RESTART_BLOCK (1 << TIF_RESTART_BLOCK) #endif --- linux-2.6.8-rc1/include/asm-um/timex.h 2003-06-14 12:18:24.000000000 -0700 +++ 25/include/asm-um/timex.h 2004-07-13 17:09:45.000000000 -0700 @@ -1,8 +1,6 @@ #ifndef __UM_TIMEX_H #define __UM_TIMEX_H -#include "linux/time.h" - typedef unsigned long cycles_t; #define cacheflush_time (0) --- linux-2.6.8-rc1/include/asm-um/uaccess.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/include/asm-um/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -6,6 +6,8 @@ #ifndef __UM_UACCESS_H #define __UM_UACCESS_H +#include "linux/sched.h" + #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -34,6 +36,9 @@ #define __copy_to_user(to, from, n) copy_to_user(to, from, n) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + #define __get_user(x, ptr) \ ({ \ const __typeof__(ptr) __private_ptr = ptr; \ --- linux-2.6.8-rc1/include/asm-um/unistd.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-um/unistd.h 2004-07-13 17:09:45.000000000 -0700 @@ -48,7 +48,10 @@ extern int um_execve(const char *file, c set_fs(KERNEL_DS); \ ret = sys(args); \ set_fs(fs); \ - return ret; + if (ret >= 0) \ + return ret; \ + errno = -(long)ret; \ + return -1; static inline long open(const char *pathname, int flags, int mode) { --- linux-2.6.8-rc1/include/asm-v850/uaccess.h 2003-06-14 12:18:30.000000000 -0700 +++ 25/include/asm-v850/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -112,6 +112,9 @@ extern int bad_user_access_length (void) #define __copy_from_user(to, from, n) (memcpy (to, from, n), 0) #define __copy_to_user(to, from, n) (memcpy(to, from, n), 0) +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + #define copy_from_user(to, from, n) __copy_from_user (to, from, n) #define copy_to_user(to, from, n) __copy_to_user(to, from, n) --- linux-2.6.8-rc1/include/asm-x86_64/hw_irq.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-x86_64/hw_irq.h 2004-07-13 17:09:34.000000000 -0700 @@ -65,14 +65,15 @@ struct hw_interrupt_type; * sources per level' errata. */ #define LOCAL_TIMER_VECTOR 0xef +#define LOCAL_PERFCTR_VECTOR 0xee /* - * First APIC vector available to drivers: (vectors 0x30-0xee) + * First APIC vector available to drivers: (vectors 0x30-0xed) * we start at 0x31 to spread out vectors evenly between priority * levels. (0x80 is the syscall vector) */ #define FIRST_DEVICE_VECTOR 0x31 -#define FIRST_SYSTEM_VECTOR 0xef /* duplicated in irq.h */ +#define FIRST_SYSTEM_VECTOR 0xee /* duplicated in irq.h */ #ifndef __ASSEMBLY__ --- linux-2.6.8-rc1/include/asm-x86_64/ia32_unistd.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-x86_64/ia32_unistd.h 2004-07-13 17:09:34.000000000 -0700 @@ -289,7 +289,13 @@ #define __NR_ia32_mq_notify (__NR_ia32_mq_open+4) #define __NR_ia32_mq_getsetattr (__NR_ia32_mq_open+5) #define __NR_ia32_kexec 283 +#define __NR_ia32_perfctr_info 284 +#define __NR_ia32_vperfctr_open (__NR_ia32_perfctr_info+1) +#define __NR_ia32_vperfctr_control (__NR_ia32_perfctr_info+2) +#define __NR_ia32_vperfctr_unlink (__NR_ia32_perfctr_info+3) +#define __NR_ia32_vperfctr_iresume (__NR_ia32_perfctr_info+4) +#define __NR_ia32_vperfctr_read (__NR_ia32_perfctr_info+5) -#define IA32_NR_syscalls 287 /* must be > than biggest syscall! */ +#define IA32_NR_syscalls 290 /* must be > than biggest syscall! */ #endif /* _ASM_X86_64_IA32_UNISTD_H_ */ --- linux-2.6.8-rc1/include/asm-x86_64/irq.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/asm-x86_64/irq.h 2004-07-13 17:09:34.000000000 -0700 @@ -29,7 +29,7 @@ */ #define NR_VECTORS 256 -#define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */ +#define FIRST_SYSTEM_VECTOR 0xee /* duplicated in hw_irq.h */ #ifdef CONFIG_PCI_USE_VECTOR #define NR_IRQS FIRST_SYSTEM_VECTOR --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-x86_64/kgdb.h 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,71 @@ +#ifndef __KGDB +#define __KGDB + +/* + * This file should not include ANY others. This makes it usable + * most anywhere without the fear of include order or inclusion. + * Make it so! + * + * This file may be included all the time. It is only active if + * CONFIG_KGDB is defined, otherwise it stubs out all the macros + * and entry points. + */ +#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) + +extern void breakpoint(void); +#define INIT_KGDB_INTS kgdb_enable_ints() + +#ifndef BREAKPOINT +#define BREAKPOINT asm(" int $3") +#endif + +extern void kgdb_schedule_breakpoint(void); +extern void kgdb_process_breakpoint(void); + +extern int kgdb_tty_hook(void); +extern int kgdb_eth_hook(void); +extern int kgdboe; + +/* + * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' + * pointer to its routine and it will be entered as the first thing + * when a trap occurs. + * + * Return values are, at present, undefined. + * + * The debug hook routine does not necessarily return to its caller. + * It has the register image and thus may choose to resume execution + * anywhere it pleases. + */ +struct pt_regs; + +extern int kgdb_handle_exception(int trapno, + int signo, int err_code, struct pt_regs *regs); +extern int in_kgdb(struct pt_regs *regs); + +extern void set_debug_traps(void); + +#ifdef CONFIG_KGDB_TS +void kgdb_tstamp(int line, char *source, int data0, int data1); +/* + * This is the time stamp function. The macro adds the source info and + * does a cast on the data to allow most any 32-bit value. + */ + +#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1) +#else +#define kgdb_ts(data0,data1) +#endif +#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ +#ifndef BREAKPOINT +#define BREAKPOINT +#endif +#define kgdb_ts(data0,data1) +#define in_kgdb (0) +#define kgdb_handle_exception +#define breakpoint +#define INIT_KGDB_INTS +#define kgdb_process_breakpoint() do {} while(0) + +#endif +#endif /* __KGDB */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-x86_64/kgdb_local.h 2004-07-13 17:09:26.000000000 -0700 @@ -0,0 +1,102 @@ +#ifndef __KGDB_LOCAL +#define ___KGDB_LOCAL +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 0x3f8 +#ifdef CONFIG_KGDB_PORT +#undef PORT +#define PORT CONFIG_KGDB_PORT +#endif +#define IRQ 4 +#ifdef CONFIG_KGDB_IRQ +#undef IRQ +#define IRQ CONFIG_KGDB_IRQ +#endif +#define SB_CLOCK 1843200 +#define SB_BASE (SB_CLOCK/16) +#define SB_BAUD9600 SB_BASE/9600 +#define SB_BAUD192 SB_BASE/19200 +#define SB_BAUD384 SB_BASE/38400 +#define SB_BAUD576 SB_BASE/57600 +#define SB_BAUD1152 SB_BASE/115200 +#ifdef CONFIG_KGDB_9600BAUD +#define SB_BAUD SB_BAUD9600 +#endif +#ifdef CONFIG_KGDB_19200BAUD +#define SB_BAUD SB_BAUD192 +#endif +#ifdef CONFIG_KGDB_38400BAUD +#define SB_BAUD SB_BAUD384 +#endif +#ifdef CONFIG_KGDB_57600BAUD +#define SB_BAUD SB_BAUD576 +#endif +#ifdef CONFIG_KGDB_115200BAUD +#define SB_BAUD SB_BAUD1152 +#endif +#ifndef SB_BAUD +#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ +#endif + +#ifndef CONFIG_X86_TSC +#undef rdtsc +#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;} +#undef rdtscll +#define rdtscll(s) s++ +#endif + +#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#define spin_lock _raw_spin_lock +#define spin_trylock _raw_spin_trylock +#define spin_unlock _raw_spin_unlock +#else +#endif +#undef spin_unlock_wait +#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ + while(spin_is_locked(x)) + +#define SB_IER 1 +#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS + +#define FLAGS 0 +#define SB_STATE { \ + magic: SSTATE_MAGIC, \ + baud_base: SB_BASE, \ + port: PORT, \ + irq: IRQ, \ + flags: FLAGS, \ + custom_divisor:SB_BAUD} +#define SB_INFO { \ + magic: SERIAL_MAGIC, \ + port: PORT,0,FLAGS, \ + state: &state, \ + tty: (struct tty_struct *)&state, \ + IER: SB_IER, \ + MCR: SB_MCR} +extern void putDebugChar(int); +/* RTAI support needs us to really stop/start interrupts */ + +#define kgdb_sti() __asm__ __volatile__("sti": : :"memory") +#define kgdb_cli() __asm__ __volatile__("cli": : :"memory") +#define kgdb_local_save_flags(x) __asm__ __volatile__(\ + "pushfl ; popl %0":"=g" (x): /* no input */) +#define kgdb_local_irq_restore(x) __asm__ __volatile__(\ + "pushl %0 ; popfl": \ + /* no output */ :"g" (x):"memory", "cc") +#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli() + +#ifdef CONFIG_SERIAL +extern void shutdown_for_kgdb(struct async_struct *info); +#endif +#define INIT_KDEBUG putDebugChar("+"); +#endif /* __KGDB_LOCAL */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/asm-x86_64/perfctr.h 2004-07-13 17:09:34.000000000 -0700 @@ -0,0 +1 @@ +#include --- linux-2.6.8-rc1/include/asm-x86_64/processor.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-x86_64/processor.h 2004-07-13 17:09:34.000000000 -0700 @@ -253,6 +253,8 @@ struct thread_struct { unsigned long *io_bitmap_ptr; /* cached TLS descriptors. */ u64 tls_array[GDT_ENTRY_TLS_ENTRIES]; +/* performance counters */ + struct vperfctr *perfctr; } __attribute__((aligned(16))); #define INIT_THREAD {} --- linux-2.6.8-rc1/include/asm-x86_64/signal.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/include/asm-x86_64/signal.h 2004-07-13 17:09:13.000000000 -0700 @@ -136,7 +136,11 @@ typedef unsigned long sigset_t; #ifndef __ASSEMBLY__ /* Type of a signal handler. */ -typedef void (*__sighandler_t)(int); +typedef void __signalfn_t(int); +typedef __signalfn_t __user *__sighandler_t; + +typedef void __restorefn_t(void); +typedef __restorefn_t __user *__sigrestore_t; #define SIG_DFL ((__sighandler_t)0) /* default signal handling */ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ @@ -145,7 +149,7 @@ typedef void (*__sighandler_t)(int); struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; - void (*sa_restorer)(void); + __sigrestore_t sa_restorer; sigset_t sa_mask; /* mask last for extensibility */ }; @@ -154,7 +158,7 @@ struct k_sigaction { }; typedef struct sigaltstack { - void *ss_sp; + void __user *ss_sp; int ss_flags; size_t ss_size; } stack_t; --- linux-2.6.8-rc1/include/asm-x86_64/string.h 2003-06-14 12:18:51.000000000 -0700 +++ 25/include/asm-x86_64/string.h 2004-07-13 17:35:10.000000000 -0700 @@ -3,8 +3,6 @@ #ifdef __KERNEL__ -#define struct_cpy(x,y) (*(x)=*(y)) - /* Written 2002 by Andi Kleen */ /* Only used for special circumstances. Stolen from i386/string.h */ --- linux-2.6.8-rc1/include/asm-x86_64/uaccess.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/asm-x86_64/uaccess.h 2004-07-13 17:09:51.000000000 -0700 @@ -351,4 +351,7 @@ long strlen_user(const char __user *str) unsigned long clear_user(void __user *mem, unsigned long len); unsigned long __clear_user(void __user *mem, unsigned long len); +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + #endif /* __X86_64_UACCESS_H */ --- linux-2.6.8-rc1/include/asm-x86_64/unistd.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/asm-x86_64/unistd.h 2004-07-13 17:09:34.000000000 -0700 @@ -554,8 +554,20 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify) __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) #define __NR_kexec_load 246 __SYSCALL(__NR_kexec_load, sys_ni_syscall) +#define __NR_perfctr_info 247 +__SYSCALL(__NR_perfctr_info, sys_perfctr_info) +#define __NR_vperfctr_open (__NR_perfctr_info+1) +__SYSCALL(__NR_vperfctr_open, sys_vperfctr_open) +#define __NR_vperfctr_control (__NR_perfctr_info+2) +__SYSCALL(__NR_vperfctr_control, sys_vperfctr_control) +#define __NR_vperfctr_unlink (__NR_perfctr_info+3) +__SYSCALL(__NR_vperfctr_unlink, sys_vperfctr_unlink) +#define __NR_vperfctr_iresume (__NR_perfctr_info+4) +__SYSCALL(__NR_vperfctr_iresume, sys_vperfctr_iresume) +#define __NR_vperfctr_read (__NR_perfctr_info+5) +__SYSCALL(__NR_vperfctr_read, sys_vperfctr_read) -#define __NR_syscall_max __NR_kexec_load +#define __NR_syscall_max __NR_vperfctr_read #ifndef __NO_STUBS /* user-visible error numbers are in the range -1 - -4095 */ --- linux-2.6.8-rc1/include/asm-x86_64/vsyscall32.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/asm-x86_64/vsyscall32.h 2004-07-13 17:09:13.000000000 -0700 @@ -13,8 +13,8 @@ #define VSYSCALL32_VSYSCALL ((void *)VSYSCALL32_BASE + 0x400) #define VSYSCALL32_SYSEXIT ((void *)VSYSCALL32_BASE + 0x410) -#define VSYSCALL32_SIGRETURN ((void *)VSYSCALL32_BASE + 0x500) -#define VSYSCALL32_RTSIGRETURN ((void *)VSYSCALL32_BASE + 0x600) +#define VSYSCALL32_SIGRETURN ((void __user *)VSYSCALL32_BASE + 0x500) +#define VSYSCALL32_RTSIGRETURN ((void __user *)VSYSCALL32_BASE + 0x600) #endif #endif --- linux-2.6.8-rc1/include/linux/ata.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/ata.h 2004-07-13 17:09:22.000000000 -0700 @@ -42,6 +42,7 @@ enum { ATA_ID_SERNO_OFS = 10, ATA_ID_MAJOR_VER = 80, ATA_ID_PIO_MODES = 64, + ATA_ID_MWDMA_MODES = 63, ATA_ID_UDMA_MODES = 88, ATA_ID_PIO4 = (1 << 1), @@ -133,13 +134,20 @@ enum { XFER_UDMA_2 = 0x42, XFER_UDMA_1 = 0x41, XFER_UDMA_0 = 0x40, + XFER_MW_DMA_2 = 0x22, + XFER_MW_DMA_1 = 0x21, + XFER_MW_DMA_0 = 0x20, XFER_PIO_4 = 0x0C, XFER_PIO_3 = 0x0B, + XFER_PIO_2 = 0x0A, + XFER_PIO_1 = 0x09, + XFER_PIO_0 = 0x08, /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: 0=to device, 1=to host */ + ATAPI_CDB_LEN = 16, /* cable types */ ATA_CBL_NONE = 0, @@ -169,7 +177,8 @@ enum ata_tf_protocols { ATA_PROT_PIO, /* PIO single sector */ ATA_PROT_PIO_MULT, /* PIO multiple sector */ ATA_PROT_DMA, /* DMA */ - ATA_PROT_ATAPI, /* packet command */ + ATA_PROT_ATAPI, /* packet command, PIO data xfer*/ + ATA_PROT_ATAPI_NODATA, /* packet command, no data */ ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */ }; @@ -220,9 +229,20 @@ struct ata_taskfile { ((u64) dev->id[(n) + 1] << 16) | \ ((u64) dev->id[(n) + 0]) ) +static inline int atapi_cdb_len(u16 *dev_id) +{ + u16 tmp = dev_id[0] & 0x3; + switch (tmp) { + case 0: return 12; + case 1: return 16; + default: return -1; + } +} + static inline int is_atapi_taskfile(struct ata_taskfile *tf) { return (tf->protocol == ATA_PROT_ATAPI) || + (tf->protocol == ATA_PROT_ATAPI_NODATA) || (tf->protocol == ATA_PROT_ATAPI_DMA); } --- linux-2.6.8-rc1/include/linux/bio.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/bio.h 2004-07-13 17:09:50.000000000 -0700 @@ -120,6 +120,8 @@ struct bio { #define BIO_SEG_VALID 3 /* nr_hw_seg valid */ #define BIO_CLONED 4 /* doesn't own data */ #define BIO_BOUNCED 5 /* bio is a bounce bio */ +#define BIO_EOPNOTSUPP 6 /* not supported */ +#define BIO_USER_MAPPED 7 /* contains user pages */ #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) /* @@ -159,6 +161,8 @@ struct bio { #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) #define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC)) +#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) +#define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) /* * will die @@ -264,9 +268,11 @@ extern int bio_add_page(struct bio *, st extern int bio_get_nr_vecs(struct block_device *); extern struct bio *bio_map_user(struct request_queue *, struct block_device *, unsigned long, unsigned int, int); -extern void bio_unmap_user(struct bio *, int); +extern void bio_unmap_user(struct bio *); extern void bio_set_pages_dirty(struct bio *bio); extern void bio_check_pages_dirty(struct bio *bio); +extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); +extern int bio_uncopy_user(struct bio *); #ifdef CONFIG_HIGHMEM /* --- linux-2.6.8-rc1/include/linux/bitmap.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/bitmap.h 2004-07-13 17:09:21.009079008 -0700 @@ -98,6 +98,9 @@ extern int bitmap_scnprintf(char *buf, u const unsigned long *src, int nbits); extern int bitmap_parse(const char __user *ubuf, unsigned int ulen, unsigned long *dst, int nbits); +extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); +extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); +extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); #define BITMAP_LAST_WORD_MASK(nbits) \ ( \ --- linux-2.6.8-rc1/include/linux/blkdev.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/blkdev.h 2004-07-13 17:09:50.000000000 -0700 @@ -195,6 +195,8 @@ enum rq_flag_bits { __REQ_PM_SUSPEND, /* suspend request */ __REQ_PM_RESUME, /* resume request */ __REQ_PM_SHUTDOWN, /* shutdown request */ + __REQ_BAR_PREFLUSH, /* barrier pre-flush done */ + __REQ_BAR_POSTFLUSH, /* barrier post-flush */ __REQ_NR_BITS, /* stops here */ }; @@ -220,6 +222,8 @@ enum rq_flag_bits { #define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND) #define REQ_PM_RESUME (1 << __REQ_PM_RESUME) #define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) +#define REQ_BAR_PREFLUSH (1 << __REQ_BAR_PREFLUSH) +#define REQ_BAR_POSTFLUSH (1 << __REQ_BAR_POSTFLUSH) /* * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME @@ -248,6 +252,7 @@ typedef void (unplug_fn) (request_queue_ struct bio_vec; typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *); typedef void (activity_fn) (void *data, int rw); +typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *); enum blk_queue_state { Queue_down, @@ -290,6 +295,7 @@ struct request_queue unplug_fn *unplug_fn; merge_bvec_fn *merge_bvec_fn; activity_fn *activity_fn; + issue_flush_fn *issue_flush_fn; /* * Auto-unplugging state @@ -373,6 +379,7 @@ struct request_queue #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ #define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ #define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */ +#define QUEUE_FLAG_ORDERED 8 /* supports ordered writes */ #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) @@ -390,6 +397,10 @@ struct request_queue #define blk_pm_request(rq) \ ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME)) +#define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER) +#define blk_barrier_preflush(rq) ((rq)->flags & REQ_BAR_PREFLUSH) +#define blk_barrier_postflush(rq) ((rq)->flags & REQ_BAR_POSTFLUSH) + #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) #define rq_data_dir(rq) ((rq)->flags & 1) @@ -524,7 +535,7 @@ extern void __blk_stop_queue(request_que extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct request *, void __user *, struct bio *, unsigned int); +extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) @@ -560,6 +571,14 @@ extern void end_that_request_last(struct extern int process_that_request_first(struct request *, unsigned int); extern void end_request(struct request *req, int uptodate); +/* + * end_that_request_first/chunk() takes an uptodate argument. we account + * any value <= as an io error. 0 means -EIO for compatability reasons, + * any other < 0 value is the direct error type. An uptodate value of + * 1 indicates successful io completion + */ +#define end_io_error(uptodate) (unlikely((uptodate) <= 0)) + static inline void blkdev_dequeue_request(struct request *req) { BUG_ON(list_empty(&req->queuelist)); @@ -588,6 +607,9 @@ extern void blk_queue_prep_rq(request_qu extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *); extern void blk_queue_dma_alignment(request_queue_t *, int); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); +extern void blk_queue_ordered(request_queue_t *, int); +extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *); +extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *); extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *); extern void blk_dump_rq_flags(struct request *, char *); @@ -616,6 +638,7 @@ extern long blk_congestion_wait(int rw, extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); extern void blk_rq_prep_restart(struct request *); +extern int blkdev_issue_flush(struct block_device *, sector_t *); #define MAX_PHYS_SEGMENTS 128 #define MAX_HW_SEGMENTS 128 --- linux-2.6.8-rc1/include/linux/blockgroup_lock.h 2003-06-14 12:17:59.000000000 -0700 +++ 25/include/linux/blockgroup_lock.h 2004-07-13 17:35:09.000000000 -0700 @@ -1,3 +1,5 @@ +#ifndef _LINUX_BLOCKGROUP_LOCK_H +#define _LINUX_BLOCKGROUP_LOCK_H /* * Per-blockgroup locking for ext2 and ext3. * @@ -55,4 +57,4 @@ static inline void bgl_lock_init(struct #define sb_bgl_lock(sb, block_group) \ (&(sb)->s_blockgroup_lock.locks[(block_group) & (NR_BG_LOCKS-1)].lock) - +#endif --- linux-2.6.8-rc1/include/linux/buffer_head.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/buffer_head.h 2004-07-13 17:09:51.000000000 -0700 @@ -26,6 +26,8 @@ enum bh_state_bits { BH_Delay, /* Buffer is not yet allocated on disk */ BH_Boundary, /* Block is followed by a discontiguity */ BH_Write_EIO, /* I/O error on write */ + BH_Ordered, /* ordered write */ + BH_Eopnotsupp, /* operation not supported (barrier) */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -110,7 +112,9 @@ BUFFER_FNS(Async_Read, async_read) BUFFER_FNS(Async_Write, async_write) BUFFER_FNS(Delay, delay) BUFFER_FNS(Boundary, boundary) -BUFFER_FNS(Write_EIO,write_io_error) +BUFFER_FNS(Write_EIO, write_io_error) +BUFFER_FNS(Ordered, ordered) +BUFFER_FNS(Eopnotsupp, eopnotsupp) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) #define touch_buffer(bh) mark_page_accessed(bh->b_page) @@ -172,8 +176,8 @@ void free_buffer_head(struct buffer_head void FASTCALL(unlock_buffer(struct buffer_head *bh)); void FASTCALL(__lock_buffer(struct buffer_head *bh)); void ll_rw_block(int, int, struct buffer_head * bh[]); -void sync_dirty_buffer(struct buffer_head *bh); -void submit_bh(int, struct buffer_head *); +int sync_dirty_buffer(struct buffer_head *bh); +int submit_bh(int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); @@ -274,6 +278,7 @@ map_bh(struct buffer_head *bh, struct su */ static inline void wait_on_buffer(struct buffer_head *bh) { + might_sleep(); if (buffer_locked(bh) || atomic_read(&bh->b_count) == 0) __wait_on_buffer(bh); } --- linux-2.6.8-rc1/include/linux/capi.h 2003-09-08 13:58:59.000000000 -0700 +++ 25/include/linux/capi.h 2004-07-13 17:09:13.000000000 -0700 @@ -77,7 +77,7 @@ typedef struct capi_profile { typedef struct capi_manufacturer_cmd { unsigned long cmd; - void *data; + void __user *data; } capi_manufacturer_cmd; /* --- linux-2.6.8-rc1/include/linux/cd1400.h 2003-06-14 12:18:04.000000000 -0700 +++ 25/include/linux/cd1400.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * cd1400.h -- cd1400 UART hardware info. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This program is free software; you can redistribute it and/or modify --- linux-2.6.8-rc1/include/linux/cdk.h 2003-06-14 12:18:24.000000000 -0700 +++ 25/include/linux/cdk.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * cdk.h -- CDK interface definitions. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This program is free software; you can redistribute it and/or modify --- linux-2.6.8-rc1/include/linux/cdrom.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/cdrom.h 2004-07-13 17:09:41.000000000 -0700 @@ -498,6 +498,7 @@ struct cdrom_generic_command #define GPMODE_VENDOR_PAGE 0x00 #define GPMODE_R_W_ERROR_PAGE 0x01 #define GPMODE_WRITE_PARMS_PAGE 0x05 +#define GPMODE_WCACHING_PAGE 0x08 #define GPMODE_AUDIO_CTL_PAGE 0x0e #define GPMODE_POWER_PAGE 0x1a #define GPMODE_FAULT_FAIL_PAGE 0x1c @@ -946,6 +947,8 @@ struct cdrom_device_info { __u8 reserved : 6; /* not used yet */ int cdda_method; /* see flags */ __u8 last_sense; + __u8 media_written; /* dirty flag, DVD+RW bookkeeping */ + unsigned short mmc3_profile; /* current MMC3 profile */ int for_data; int (*exit)(struct cdrom_device_info *); int mrw_mode_page; --- linux-2.6.8-rc1/include/linux/compat_ioctl.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/compat_ioctl.h 2004-07-13 17:09:22.000000000 -0700 @@ -732,3 +732,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY) COMPATIBLE_IOCTL(SIOCGIWRETRY) COMPATIBLE_IOCTL(SIOCSIWPOWER) COMPATIBLE_IOCTL(SIOCGIWPOWER) +/* hiddev */ +COMPATIBLE_IOCTL(HIDIOCGVERSION) +COMPATIBLE_IOCTL(HIDIOCAPPLICATION) +COMPATIBLE_IOCTL(HIDIOCGDEVINFO) +COMPATIBLE_IOCTL(HIDIOCGSTRING) +COMPATIBLE_IOCTL(HIDIOCINITREPORT) +COMPATIBLE_IOCTL(HIDIOCGREPORT) +COMPATIBLE_IOCTL(HIDIOCSREPORT) +COMPATIBLE_IOCTL(HIDIOCGREPORTINFO) +COMPATIBLE_IOCTL(HIDIOCGFIELDINFO) +COMPATIBLE_IOCTL(HIDIOCGUSAGE) +COMPATIBLE_IOCTL(HIDIOCSUSAGE) +COMPATIBLE_IOCTL(HIDIOCGUCODE) +COMPATIBLE_IOCTL(HIDIOCGFLAG) +COMPATIBLE_IOCTL(HIDIOCSFLAG) +COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX) +COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO) --- linux-2.6.8-rc1/include/linux/compiler-gcc3.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/compiler-gcc3.h 2004-07-13 17:35:09.000000000 -0700 @@ -3,10 +3,10 @@ /* These definitions are for GCC v3.x. */ #include -#if __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 4 -# define inline __inline__ __attribute__((always_inline)) -# define __inline__ __inline__ __attribute__((always_inline)) -# define __inline __inline__ __attribute__((always_inline)) +#if __GNUC_MINOR__ >= 1 +# define inline inline __attribute__((always_inline)) +# define __inline__ __inline__ __attribute__((always_inline)) +# define __inline __inline __attribute__((always_inline)) #endif #if __GNUC_MINOR__ > 0 --- linux-2.6.8-rc1/include/linux/compiler-gcc.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/compiler-gcc.h 2004-07-13 17:09:28.034011056 -0700 @@ -13,5 +13,5 @@ shouldn't recognize the original var, and make assumptions about it */ #define RELOC_HIDE(ptr, off) \ ({ unsigned long __ptr; \ - __asm__ ("" : "=g"(__ptr) : "0"(ptr)); \ + __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) --- linux-2.6.8-rc1/include/linux/compiler-gcc+.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/compiler-gcc+.h 2004-07-13 17:35:09.000000000 -0700 @@ -6,9 +6,9 @@ */ #include -#define inline __inline__ __attribute__((always_inline)) -#define __inline__ __inline__ __attribute__((always_inline)) -#define __inline __inline__ __attribute__((always_inline)) +#define inline inline __attribute__((always_inline)) +#define __inline__ __inline__ __attribute__((always_inline)) +#define __inline __inline __attribute__((always_inline)) #define __deprecated __attribute__((deprecated)) #define __attribute_used__ __attribute__((__used__)) #define __attribute_pure__ __attribute__((pure)) --- linux-2.6.8-rc1/include/linux/compiler.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/compiler.h 2004-07-13 17:09:53.135195096 -0700 @@ -124,4 +124,8 @@ extern void __chk_user_ptr(void __user * #define noinline #endif +#ifndef __always_inline +#define __always_inline inline +#endif + #endif /* __LINUX_COMPILER_H */ --- linux-2.6.8-rc1/include/linux/comstats.h 2003-06-14 12:18:00.000000000 -0700 +++ 25/include/linux/comstats.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * comstats.h -- Serial Port Stats. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This program is free software; you can redistribute it and/or modify --- linux-2.6.8-rc1/include/linux/config.h 2003-11-09 16:45:05.000000000 -0800 +++ 25/include/linux/config.h 2004-07-13 17:09:26.322271280 -0700 @@ -2,5 +2,8 @@ #define _LINUX_CONFIG_H #include +#ifdef CONFIG_X86 +#include +#endif #endif --- linux-2.6.8-rc1/include/linux/device.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/device.h 2004-07-13 17:09:21.407018512 -0700 @@ -56,6 +56,7 @@ struct bus_type { struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; + struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); struct device * (*add) (struct device * parent, char * bus_id); @@ -119,6 +120,7 @@ extern void driver_unregister(struct dev extern struct device_driver * get_driver(struct device_driver * drv); extern void put_driver(struct device_driver * drv); +extern struct device_driver *driver_find(const char *name, struct bus_type *bus); /* driverfs interface for exporting driver attributes */ @@ -283,6 +285,9 @@ struct device { struct list_head dma_pools; /* dma pools (if dma'ble) */ + struct dma_coherent_mem *dma_mem; /* internal for coherent mem + override */ + void (*release)(struct device * dev); }; @@ -381,6 +386,8 @@ extern struct resource *platform_get_res extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_add_devices(struct platform_device **, int); +extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); + /* drivers/base/power.c */ extern void device_shutdown(void); --- linux-2.6.8-rc1/include/linux/dma-mapping.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/dma-mapping.h 2004-07-13 17:09:21.010078856 -0700 @@ -1,6 +1,8 @@ #ifndef _ASM_LINUX_DMA_MAPPING_H #define _ASM_LINUX_DMA_MAPPING_H +#include + /* These definitions mirror those in pci.h, so they can be used * interchangeably with their PCI_ counterparts */ enum dma_data_direction { @@ -21,6 +23,33 @@ enum dma_data_direction { extern u64 dma_get_required_mask(struct device *dev); +/* flags for the coherent memory api */ +#define DMA_MEMORY_MAP 0x01 +#define DMA_MEMORY_IO 0x02 +#define DMA_MEMORY_INCLUDES_CHILDREN 0x04 +#define DMA_MEMORY_EXCLUSIVE 0x08 + +#ifndef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY +static inline int +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + return 0; +} + +static inline void +dma_release_declared_memory(struct device *dev) +{ +} + +static inline void * +dma_mark_declared_memory_occupied(struct device *dev, + dma_addr_t device_addr, size_t size) +{ + return ERR_PTR(-EBUSY); +} +#endif + #endif --- linux-2.6.8-rc1/include/linux/dvb/osd.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/include/linux/dvb/osd.h 2004-07-13 17:09:13.000000000 -0700 @@ -101,7 +101,7 @@ typedef struct osd_cmd_s { int x1; int y1; int color; - void *data; + void __user *data; } osd_cmd_t; --- linux-2.6.8-rc1/include/linux/dvb/video.h 2004-03-10 20:41:31.000000000 -0800 +++ 25/include/linux/dvb/video.h 2004-07-13 17:09:13.000000000 -0700 @@ -100,7 +100,7 @@ struct video_status { struct video_still_picture { - char *iFrame; /* pointer to a single iframe in memory */ + char __user *iFrame; /* pointer to a single iframe in memory */ int32_t size; }; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/dwarf2.h 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,738 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +#ifndef _ELF_DWARF2_H +#define _ELF_DWARF2_H + +/* Structure found in the .debug_line section. */ +#ifndef __ASSEMBLY__ +typedef struct +{ + unsigned char li_length [4]; + unsigned char li_version [2]; + unsigned char li_prologue_length [4]; + unsigned char li_min_insn_length [1]; + unsigned char li_default_is_stmt [1]; + unsigned char li_line_base [1]; + unsigned char li_line_range [1]; + unsigned char li_opcode_base [1]; +} +DWARF2_External_LineInfo; + +typedef struct +{ + unsigned long li_length; + unsigned short li_version; + unsigned int li_prologue_length; + unsigned char li_min_insn_length; + unsigned char li_default_is_stmt; + int li_line_base; + unsigned char li_line_range; + unsigned char li_opcode_base; +} +DWARF2_Internal_LineInfo; + +/* Structure found in .debug_pubnames section. */ +typedef struct +{ + unsigned char pn_length [4]; + unsigned char pn_version [2]; + unsigned char pn_offset [4]; + unsigned char pn_size [4]; +} +DWARF2_External_PubNames; + +typedef struct +{ + unsigned long pn_length; + unsigned short pn_version; + unsigned long pn_offset; + unsigned long pn_size; +} +DWARF2_Internal_PubNames; + +/* Structure found in .debug_info section. */ +typedef struct +{ + unsigned char cu_length [4]; + unsigned char cu_version [2]; + unsigned char cu_abbrev_offset [4]; + unsigned char cu_pointer_size [1]; +} +DWARF2_External_CompUnit; + +typedef struct +{ + unsigned long cu_length; + unsigned short cu_version; + unsigned long cu_abbrev_offset; + unsigned char cu_pointer_size; +} +DWARF2_Internal_CompUnit; + +typedef struct +{ + unsigned char ar_length [4]; + unsigned char ar_version [2]; + unsigned char ar_info_offset [4]; + unsigned char ar_pointer_size [1]; + unsigned char ar_segment_size [1]; +} +DWARF2_External_ARange; + +typedef struct +{ + unsigned long ar_length; + unsigned short ar_version; + unsigned long ar_info_offset; + unsigned char ar_pointer_size; + unsigned char ar_segment_size; +} +DWARF2_Internal_ARange; + +#define ENUM(name) enum name { +#define IF_NOT_ASM(a) a +#define COMMA , +#else +#define ENUM(name) +#define IF_NOT_ASM(a) +#define COMMA + +#endif + +/* Tag names and codes. */ +ENUM(dwarf_tag) + + DW_TAG_padding = 0x00 COMMA + DW_TAG_array_type = 0x01 COMMA + DW_TAG_class_type = 0x02 COMMA + DW_TAG_entry_point = 0x03 COMMA + DW_TAG_enumeration_type = 0x04 COMMA + DW_TAG_formal_parameter = 0x05 COMMA + DW_TAG_imported_declaration = 0x08 COMMA + DW_TAG_label = 0x0a COMMA + DW_TAG_lexical_block = 0x0b COMMA + DW_TAG_member = 0x0d COMMA + DW_TAG_pointer_type = 0x0f COMMA + DW_TAG_reference_type = 0x10 COMMA + DW_TAG_compile_unit = 0x11 COMMA + DW_TAG_string_type = 0x12 COMMA + DW_TAG_structure_type = 0x13 COMMA + DW_TAG_subroutine_type = 0x15 COMMA + DW_TAG_typedef = 0x16 COMMA + DW_TAG_union_type = 0x17 COMMA + DW_TAG_unspecified_parameters = 0x18 COMMA + DW_TAG_variant = 0x19 COMMA + DW_TAG_common_block = 0x1a COMMA + DW_TAG_common_inclusion = 0x1b COMMA + DW_TAG_inheritance = 0x1c COMMA + DW_TAG_inlined_subroutine = 0x1d COMMA + DW_TAG_module = 0x1e COMMA + DW_TAG_ptr_to_member_type = 0x1f COMMA + DW_TAG_set_type = 0x20 COMMA + DW_TAG_subrange_type = 0x21 COMMA + DW_TAG_with_stmt = 0x22 COMMA + DW_TAG_access_declaration = 0x23 COMMA + DW_TAG_base_type = 0x24 COMMA + DW_TAG_catch_block = 0x25 COMMA + DW_TAG_const_type = 0x26 COMMA + DW_TAG_constant = 0x27 COMMA + DW_TAG_enumerator = 0x28 COMMA + DW_TAG_file_type = 0x29 COMMA + DW_TAG_friend = 0x2a COMMA + DW_TAG_namelist = 0x2b COMMA + DW_TAG_namelist_item = 0x2c COMMA + DW_TAG_packed_type = 0x2d COMMA + DW_TAG_subprogram = 0x2e COMMA + DW_TAG_template_type_param = 0x2f COMMA + DW_TAG_template_value_param = 0x30 COMMA + DW_TAG_thrown_type = 0x31 COMMA + DW_TAG_try_block = 0x32 COMMA + DW_TAG_variant_part = 0x33 COMMA + DW_TAG_variable = 0x34 COMMA + DW_TAG_volatile_type = 0x35 COMMA + /* DWARF 3. */ + DW_TAG_dwarf_procedure = 0x36 COMMA + DW_TAG_restrict_type = 0x37 COMMA + DW_TAG_interface_type = 0x38 COMMA + DW_TAG_namespace = 0x39 COMMA + DW_TAG_imported_module = 0x3a COMMA + DW_TAG_unspecified_type = 0x3b COMMA + DW_TAG_partial_unit = 0x3c COMMA + DW_TAG_imported_unit = 0x3d COMMA + /* SGI/MIPS Extensions. */ + DW_TAG_MIPS_loop = 0x4081 COMMA + /* GNU extensions. */ + DW_TAG_format_label = 0x4101 COMMA /* For FORTRAN 77 and Fortran 90. */ + DW_TAG_function_template = 0x4102 COMMA /* For C++. */ + DW_TAG_class_template = 0x4103 COMMA /* For C++. */ + DW_TAG_GNU_BINCL = 0x4104 COMMA + DW_TAG_GNU_EINCL = 0x4105 COMMA + /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ + DW_TAG_upc_shared_type = 0x8765 COMMA + DW_TAG_upc_strict_type = 0x8766 COMMA + DW_TAG_upc_relaxed_type = 0x8767 +IF_NOT_ASM(};) + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +ENUM(dwarf_form) + + DW_FORM_addr = 0x01 COMMA + DW_FORM_block2 = 0x03 COMMA + DW_FORM_block4 = 0x04 COMMA + DW_FORM_data2 = 0x05 COMMA + DW_FORM_data4 = 0x06 COMMA + DW_FORM_data8 = 0x07 COMMA + DW_FORM_string = 0x08 COMMA + DW_FORM_block = 0x09 COMMA + DW_FORM_block1 = 0x0a COMMA + DW_FORM_data1 = 0x0b COMMA + DW_FORM_flag = 0x0c COMMA + DW_FORM_sdata = 0x0d COMMA + DW_FORM_strp = 0x0e COMMA + DW_FORM_udata = 0x0f COMMA + DW_FORM_ref_addr = 0x10 COMMA + DW_FORM_ref1 = 0x11 COMMA + DW_FORM_ref2 = 0x12 COMMA + DW_FORM_ref4 = 0x13 COMMA + DW_FORM_ref8 = 0x14 COMMA + DW_FORM_ref_udata = 0x15 COMMA + DW_FORM_indirect = 0x16 +IF_NOT_ASM(};) + +/* Attribute names and codes. */ + +ENUM(dwarf_attribute) + + DW_AT_sibling = 0x01 COMMA + DW_AT_location = 0x02 COMMA + DW_AT_name = 0x03 COMMA + DW_AT_ordering = 0x09 COMMA + DW_AT_subscr_data = 0x0a COMMA + DW_AT_byte_size = 0x0b COMMA + DW_AT_bit_offset = 0x0c COMMA + DW_AT_bit_size = 0x0d COMMA + DW_AT_element_list = 0x0f COMMA + DW_AT_stmt_list = 0x10 COMMA + DW_AT_low_pc = 0x11 COMMA + DW_AT_high_pc = 0x12 COMMA + DW_AT_language = 0x13 COMMA + DW_AT_member = 0x14 COMMA + DW_AT_discr = 0x15 COMMA + DW_AT_discr_value = 0x16 COMMA + DW_AT_visibility = 0x17 COMMA + DW_AT_import = 0x18 COMMA + DW_AT_string_length = 0x19 COMMA + DW_AT_common_reference = 0x1a COMMA + DW_AT_comp_dir = 0x1b COMMA + DW_AT_const_value = 0x1c COMMA + DW_AT_containing_type = 0x1d COMMA + DW_AT_default_value = 0x1e COMMA + DW_AT_inline = 0x20 COMMA + DW_AT_is_optional = 0x21 COMMA + DW_AT_lower_bound = 0x22 COMMA + DW_AT_producer = 0x25 COMMA + DW_AT_prototyped = 0x27 COMMA + DW_AT_return_addr = 0x2a COMMA + DW_AT_start_scope = 0x2c COMMA + DW_AT_stride_size = 0x2e COMMA + DW_AT_upper_bound = 0x2f COMMA + DW_AT_abstract_origin = 0x31 COMMA + DW_AT_accessibility = 0x32 COMMA + DW_AT_address_class = 0x33 COMMA + DW_AT_artificial = 0x34 COMMA + DW_AT_base_types = 0x35 COMMA + DW_AT_calling_convention = 0x36 COMMA + DW_AT_count = 0x37 COMMA + DW_AT_data_member_location = 0x38 COMMA + DW_AT_decl_column = 0x39 COMMA + DW_AT_decl_file = 0x3a COMMA + DW_AT_decl_line = 0x3b COMMA + DW_AT_declaration = 0x3c COMMA + DW_AT_discr_list = 0x3d COMMA + DW_AT_encoding = 0x3e COMMA + DW_AT_external = 0x3f COMMA + DW_AT_frame_base = 0x40 COMMA + DW_AT_friend = 0x41 COMMA + DW_AT_identifier_case = 0x42 COMMA + DW_AT_macro_info = 0x43 COMMA + DW_AT_namelist_items = 0x44 COMMA + DW_AT_priority = 0x45 COMMA + DW_AT_segment = 0x46 COMMA + DW_AT_specification = 0x47 COMMA + DW_AT_static_link = 0x48 COMMA + DW_AT_type = 0x49 COMMA + DW_AT_use_location = 0x4a COMMA + DW_AT_variable_parameter = 0x4b COMMA + DW_AT_virtuality = 0x4c COMMA + DW_AT_vtable_elem_location = 0x4d COMMA + /* DWARF 3 values. */ + DW_AT_allocated = 0x4e COMMA + DW_AT_associated = 0x4f COMMA + DW_AT_data_location = 0x50 COMMA + DW_AT_stride = 0x51 COMMA + DW_AT_entry_pc = 0x52 COMMA + DW_AT_use_UTF8 = 0x53 COMMA + DW_AT_extension = 0x54 COMMA + DW_AT_ranges = 0x55 COMMA + DW_AT_trampoline = 0x56 COMMA + DW_AT_call_column = 0x57 COMMA + DW_AT_call_file = 0x58 COMMA + DW_AT_call_line = 0x59 COMMA + /* SGI/MIPS extensions. */ + DW_AT_MIPS_fde = 0x2001 COMMA + DW_AT_MIPS_loop_begin = 0x2002 COMMA + DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA + DW_AT_MIPS_epilog_begin = 0x2004 COMMA + DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA + DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA + DW_AT_MIPS_linkage_name = 0x2007 COMMA + DW_AT_MIPS_stride = 0x2008 COMMA + DW_AT_MIPS_abstract_name = 0x2009 COMMA + DW_AT_MIPS_clone_origin = 0x200a COMMA + DW_AT_MIPS_has_inlines = 0x200b COMMA + /* GNU extensions. */ + DW_AT_sf_names = 0x2101 COMMA + DW_AT_src_info = 0x2102 COMMA + DW_AT_mac_info = 0x2103 COMMA + DW_AT_src_coords = 0x2104 COMMA + DW_AT_body_begin = 0x2105 COMMA + DW_AT_body_end = 0x2106 COMMA + DW_AT_GNU_vector = 0x2107 COMMA + /* VMS extensions. */ + DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA + /* UPC extension. */ + DW_AT_upc_threads_scaled = 0x3210 +IF_NOT_ASM(};) + +#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ +#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ + +/* Location atom names and codes. */ +ENUM(dwarf_location_atom) + + DW_OP_addr = 0x03 COMMA + DW_OP_deref = 0x06 COMMA + DW_OP_const1u = 0x08 COMMA + DW_OP_const1s = 0x09 COMMA + DW_OP_const2u = 0x0a COMMA + DW_OP_const2s = 0x0b COMMA + DW_OP_const4u = 0x0c COMMA + DW_OP_const4s = 0x0d COMMA + DW_OP_const8u = 0x0e COMMA + DW_OP_const8s = 0x0f COMMA + DW_OP_constu = 0x10 COMMA + DW_OP_consts = 0x11 COMMA + DW_OP_dup = 0x12 COMMA + DW_OP_drop = 0x13 COMMA + DW_OP_over = 0x14 COMMA + DW_OP_pick = 0x15 COMMA + DW_OP_swap = 0x16 COMMA + DW_OP_rot = 0x17 COMMA + DW_OP_xderef = 0x18 COMMA + DW_OP_abs = 0x19 COMMA + DW_OP_and = 0x1a COMMA + DW_OP_div = 0x1b COMMA + DW_OP_minus = 0x1c COMMA + DW_OP_mod = 0x1d COMMA + DW_OP_mul = 0x1e COMMA + DW_OP_neg = 0x1f COMMA + DW_OP_not = 0x20 COMMA + DW_OP_or = 0x21 COMMA + DW_OP_plus = 0x22 COMMA + DW_OP_plus_uconst = 0x23 COMMA + DW_OP_shl = 0x24 COMMA + DW_OP_shr = 0x25 COMMA + DW_OP_shra = 0x26 COMMA + DW_OP_xor = 0x27 COMMA + DW_OP_bra = 0x28 COMMA + DW_OP_eq = 0x29 COMMA + DW_OP_ge = 0x2a COMMA + DW_OP_gt = 0x2b COMMA + DW_OP_le = 0x2c COMMA + DW_OP_lt = 0x2d COMMA + DW_OP_ne = 0x2e COMMA + DW_OP_skip = 0x2f COMMA + DW_OP_lit0 = 0x30 COMMA + DW_OP_lit1 = 0x31 COMMA + DW_OP_lit2 = 0x32 COMMA + DW_OP_lit3 = 0x33 COMMA + DW_OP_lit4 = 0x34 COMMA + DW_OP_lit5 = 0x35 COMMA + DW_OP_lit6 = 0x36 COMMA + DW_OP_lit7 = 0x37 COMMA + DW_OP_lit8 = 0x38 COMMA + DW_OP_lit9 = 0x39 COMMA + DW_OP_lit10 = 0x3a COMMA + DW_OP_lit11 = 0x3b COMMA + DW_OP_lit12 = 0x3c COMMA + DW_OP_lit13 = 0x3d COMMA + DW_OP_lit14 = 0x3e COMMA + DW_OP_lit15 = 0x3f COMMA + DW_OP_lit16 = 0x40 COMMA + DW_OP_lit17 = 0x41 COMMA + DW_OP_lit18 = 0x42 COMMA + DW_OP_lit19 = 0x43 COMMA + DW_OP_lit20 = 0x44 COMMA + DW_OP_lit21 = 0x45 COMMA + DW_OP_lit22 = 0x46 COMMA + DW_OP_lit23 = 0x47 COMMA + DW_OP_lit24 = 0x48 COMMA + DW_OP_lit25 = 0x49 COMMA + DW_OP_lit26 = 0x4a COMMA + DW_OP_lit27 = 0x4b COMMA + DW_OP_lit28 = 0x4c COMMA + DW_OP_lit29 = 0x4d COMMA + DW_OP_lit30 = 0x4e COMMA + DW_OP_lit31 = 0x4f COMMA + DW_OP_reg0 = 0x50 COMMA + DW_OP_reg1 = 0x51 COMMA + DW_OP_reg2 = 0x52 COMMA + DW_OP_reg3 = 0x53 COMMA + DW_OP_reg4 = 0x54 COMMA + DW_OP_reg5 = 0x55 COMMA + DW_OP_reg6 = 0x56 COMMA + DW_OP_reg7 = 0x57 COMMA + DW_OP_reg8 = 0x58 COMMA + DW_OP_reg9 = 0x59 COMMA + DW_OP_reg10 = 0x5a COMMA + DW_OP_reg11 = 0x5b COMMA + DW_OP_reg12 = 0x5c COMMA + DW_OP_reg13 = 0x5d COMMA + DW_OP_reg14 = 0x5e COMMA + DW_OP_reg15 = 0x5f COMMA + DW_OP_reg16 = 0x60 COMMA + DW_OP_reg17 = 0x61 COMMA + DW_OP_reg18 = 0x62 COMMA + DW_OP_reg19 = 0x63 COMMA + DW_OP_reg20 = 0x64 COMMA + DW_OP_reg21 = 0x65 COMMA + DW_OP_reg22 = 0x66 COMMA + DW_OP_reg23 = 0x67 COMMA + DW_OP_reg24 = 0x68 COMMA + DW_OP_reg25 = 0x69 COMMA + DW_OP_reg26 = 0x6a COMMA + DW_OP_reg27 = 0x6b COMMA + DW_OP_reg28 = 0x6c COMMA + DW_OP_reg29 = 0x6d COMMA + DW_OP_reg30 = 0x6e COMMA + DW_OP_reg31 = 0x6f COMMA + DW_OP_breg0 = 0x70 COMMA + DW_OP_breg1 = 0x71 COMMA + DW_OP_breg2 = 0x72 COMMA + DW_OP_breg3 = 0x73 COMMA + DW_OP_breg4 = 0x74 COMMA + DW_OP_breg5 = 0x75 COMMA + DW_OP_breg6 = 0x76 COMMA + DW_OP_breg7 = 0x77 COMMA + DW_OP_breg8 = 0x78 COMMA + DW_OP_breg9 = 0x79 COMMA + DW_OP_breg10 = 0x7a COMMA + DW_OP_breg11 = 0x7b COMMA + DW_OP_breg12 = 0x7c COMMA + DW_OP_breg13 = 0x7d COMMA + DW_OP_breg14 = 0x7e COMMA + DW_OP_breg15 = 0x7f COMMA + DW_OP_breg16 = 0x80 COMMA + DW_OP_breg17 = 0x81 COMMA + DW_OP_breg18 = 0x82 COMMA + DW_OP_breg19 = 0x83 COMMA + DW_OP_breg20 = 0x84 COMMA + DW_OP_breg21 = 0x85 COMMA + DW_OP_breg22 = 0x86 COMMA + DW_OP_breg23 = 0x87 COMMA + DW_OP_breg24 = 0x88 COMMA + DW_OP_breg25 = 0x89 COMMA + DW_OP_breg26 = 0x8a COMMA + DW_OP_breg27 = 0x8b COMMA + DW_OP_breg28 = 0x8c COMMA + DW_OP_breg29 = 0x8d COMMA + DW_OP_breg30 = 0x8e COMMA + DW_OP_breg31 = 0x8f COMMA + DW_OP_regx = 0x90 COMMA + DW_OP_fbreg = 0x91 COMMA + DW_OP_bregx = 0x92 COMMA + DW_OP_piece = 0x93 COMMA + DW_OP_deref_size = 0x94 COMMA + DW_OP_xderef_size = 0x95 COMMA + DW_OP_nop = 0x96 COMMA + /* DWARF 3 extensions. */ + DW_OP_push_object_address = 0x97 COMMA + DW_OP_call2 = 0x98 COMMA + DW_OP_call4 = 0x99 COMMA + DW_OP_call_ref = 0x9a COMMA + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0 +IF_NOT_ASM(};) + +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ +#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ + +/* Type encodings. */ +ENUM(dwarf_type) + + DW_ATE_void = 0x0 COMMA + DW_ATE_address = 0x1 COMMA + DW_ATE_boolean = 0x2 COMMA + DW_ATE_complex_float = 0x3 COMMA + DW_ATE_float = 0x4 COMMA + DW_ATE_signed = 0x5 COMMA + DW_ATE_signed_char = 0x6 COMMA + DW_ATE_unsigned = 0x7 COMMA + DW_ATE_unsigned_char = 0x8 COMMA + /* DWARF 3. */ + DW_ATE_imaginary_float = 0x9 +IF_NOT_ASM(};) + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +ENUM(dwarf_array_dim_ordering) + + DW_ORD_row_major = 0 COMMA + DW_ORD_col_major = 1 +IF_NOT_ASM(};) + +/* Access attribute. */ +ENUM(dwarf_access_attribute) + + DW_ACCESS_public = 1 COMMA + DW_ACCESS_protected = 2 COMMA + DW_ACCESS_private = 3 +IF_NOT_ASM(};) + +/* Visibility. */ +ENUM(dwarf_visibility_attribute) + + DW_VIS_local = 1 COMMA + DW_VIS_exported = 2 COMMA + DW_VIS_qualified = 3 +IF_NOT_ASM(};) + +/* Virtuality. */ +ENUM(dwarf_virtuality_attribute) + + DW_VIRTUALITY_none = 0 COMMA + DW_VIRTUALITY_virtual = 1 COMMA + DW_VIRTUALITY_pure_virtual = 2 +IF_NOT_ASM(};) + +/* Case sensitivity. */ +ENUM(dwarf_id_case) + + DW_ID_case_sensitive = 0 COMMA + DW_ID_up_case = 1 COMMA + DW_ID_down_case = 2 COMMA + DW_ID_case_insensitive = 3 +IF_NOT_ASM(};) + +/* Calling convention. */ +ENUM(dwarf_calling_convention) + + DW_CC_normal = 0x1 COMMA + DW_CC_program = 0x2 COMMA + DW_CC_nocall = 0x3 +IF_NOT_ASM(};) + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* Inline attribute. */ +ENUM(dwarf_inline_attribute) + + DW_INL_not_inlined = 0 COMMA + DW_INL_inlined = 1 COMMA + DW_INL_declared_not_inlined = 2 COMMA + DW_INL_declared_inlined = 3 +IF_NOT_ASM(};) + +/* Discriminant lists. */ +ENUM(dwarf_discrim_list) + + DW_DSC_label = 0 COMMA + DW_DSC_range = 1 +IF_NOT_ASM(};) + +/* Line number opcodes. */ +ENUM(dwarf_line_number_ops) + + DW_LNS_extended_op = 0 COMMA + DW_LNS_copy = 1 COMMA + DW_LNS_advance_pc = 2 COMMA + DW_LNS_advance_line = 3 COMMA + DW_LNS_set_file = 4 COMMA + DW_LNS_set_column = 5 COMMA + DW_LNS_negate_stmt = 6 COMMA + DW_LNS_set_basic_block = 7 COMMA + DW_LNS_const_add_pc = 8 COMMA + DW_LNS_fixed_advance_pc = 9 COMMA + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10 COMMA + DW_LNS_set_epilogue_begin = 11 COMMA + DW_LNS_set_isa = 12 +IF_NOT_ASM(};) + +/* Line number extended opcodes. */ +ENUM(dwarf_line_number_x_ops) + + DW_LNE_end_sequence = 1 COMMA + DW_LNE_set_address = 2 COMMA + DW_LNE_define_file = 3 +IF_NOT_ASM(};) + +/* Call frame information. */ +ENUM(dwarf_call_frame_info) + + DW_CFA_advance_loc = 0x40 COMMA + DW_CFA_offset = 0x80 COMMA + DW_CFA_restore = 0xc0 COMMA + DW_CFA_nop = 0x00 COMMA + DW_CFA_set_loc = 0x01 COMMA + DW_CFA_advance_loc1 = 0x02 COMMA + DW_CFA_advance_loc2 = 0x03 COMMA + DW_CFA_advance_loc4 = 0x04 COMMA + DW_CFA_offset_extended = 0x05 COMMA + DW_CFA_restore_extended = 0x06 COMMA + DW_CFA_undefined = 0x07 COMMA + DW_CFA_same_value = 0x08 COMMA + DW_CFA_register = 0x09 COMMA + DW_CFA_remember_state = 0x0a COMMA + DW_CFA_restore_state = 0x0b COMMA + DW_CFA_def_cfa = 0x0c COMMA + DW_CFA_def_cfa_register = 0x0d COMMA + DW_CFA_def_cfa_offset = 0x0e COMMA + + /* DWARF 3. */ + DW_CFA_def_cfa_expression = 0x0f COMMA + DW_CFA_expression = 0x10 COMMA + DW_CFA_offset_extended_sf = 0x11 COMMA + DW_CFA_def_cfa_sf = 0x12 COMMA + DW_CFA_def_cfa_offset_sf = 0x13 COMMA + + /* SGI/MIPS specific. */ + DW_CFA_MIPS_advance_loc8 = 0x1d COMMA + + /* GNU extensions. */ + DW_CFA_GNU_window_save = 0x2d COMMA + DW_CFA_GNU_args_size = 0x2e COMMA + DW_CFA_GNU_negative_offset_extended = 0x2f +IF_NOT_ASM(};) + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +ENUM(dwarf_source_language) + + DW_LANG_C89 = 0x0001 COMMA + DW_LANG_C = 0x0002 COMMA + DW_LANG_Ada83 = 0x0003 COMMA + DW_LANG_C_plus_plus = 0x0004 COMMA + DW_LANG_Cobol74 = 0x0005 COMMA + DW_LANG_Cobol85 = 0x0006 COMMA + DW_LANG_Fortran77 = 0x0007 COMMA + DW_LANG_Fortran90 = 0x0008 COMMA + DW_LANG_Pascal83 = 0x0009 COMMA + DW_LANG_Modula2 = 0x000a COMMA + DW_LANG_Java = 0x000b COMMA + /* DWARF 3. */ + DW_LANG_C99 = 0x000c COMMA + DW_LANG_Ada95 = 0x000d COMMA + DW_LANG_Fortran95 = 0x000e COMMA + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001 COMMA + /* UPC. */ + DW_LANG_Upc = 0x8765 +IF_NOT_ASM(};) + +#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ +#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ + +/* Names and codes for macro information. */ +ENUM(dwarf_macinfo_record_type) + + DW_MACINFO_define = 1 COMMA + DW_MACINFO_undef = 2 COMMA + DW_MACINFO_start_file = 3 COMMA + DW_MACINFO_end_file = 4 COMMA + DW_MACINFO_vendor_ext = 255 +IF_NOT_ASM(};) + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +#endif /* _ELF_DWARF2_H */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/dwarf2-lang.h 2004-07-13 17:09:25.000000000 -0700 @@ -0,0 +1,132 @@ +#ifndef DWARF2_LANG +#define DWARF2_LANG +#include + +/* + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2, or (at your option) any later + * version. + */ +/* + * This file defines macros that allow generation of DWARF debug records + * for asm files. This file is platform independent. Register numbers + * (which are about the only thing that is platform dependent) are to be + * supplied by a platform defined file. + */ +#define DWARF_preamble() .section .debug_frame,"",@progbits +/* + * This macro starts a debug frame section. The debug_frame describes + * where to find the registers that the enclosing function saved on + * entry. + * + * ORD is use by the label generator and should be the same as what is + * passed to CFI_postamble. + * + * pc, pc register gdb ordinal. + * + * code_align this is the factor used to define locations or regions + * where the given definitions apply. If you use labels to define these + * this should be 1. + * + * data_align this is the factor used to define register offsets. If + * you use struct offset, this should be the size of the register in + * bytes or the negative of that. This is how it is used: you will + * define a register as the reference register, say the stack pointer, + * then you will say where a register is located relative to this + * reference registers value, say 40 for register 3 (the gdb register + * number). The <40> will be multiplied by to define the + * byte offset of the given register (3, in this example). So if your + * <40> is the byte offset and the reference register points at the + * begining, you would want 1 for the data_offset. If <40> was the 40th + * 4-byte element in that structure you would want 4. And if your + * reference register points at the end of the structure you would want + * a negative data_align value(and you would have to do other math as + * well). + */ + +#define CFI_preamble(ORD, pc, code_align, data_align) \ +.section .debug_frame,"",@progbits ; \ +frame/**/_/**/ORD: \ + .long end/**/_/**/ORD-start/**/_/**/ORD; \ +start/**/_/**/ORD: \ + .long DW_CIE_ID; \ + .byte DW_CIE_VERSION; \ + .byte 0 ; \ + .uleb128 code_align; \ + .sleb128 data_align; \ + .byte pc; + +/* + * After the above macro and prior to the CFI_postamble, you need to + * define the initial state. This starts with defining the reference + * register and, usually the pc. Here are some helper macros: + */ + +#define CFA_define_reference(reg, offset) \ + .byte DW_CFA_def_cfa; \ + .uleb128 reg; \ + .uleb128 (offset); + +#define CFA_define_offset(reg, offset) \ + .byte (DW_CFA_offset + reg); \ + .uleb128 (offset); + +#define CFI_postamble(ORD) \ + .align 4; \ +end/**/_/**/ORD: +/* + * So now your code pushs stuff on the stack, you need a new location + * and the rules for what to do. This starts a running description of + * the call frame. You need to describe what changes with respect to + * the call registers as the location of the pc moves through the code. + * The following builds an FDE (fram descriptor entry?). Like the + * above, it has a preamble and a postamble. It also is tied to the CFI + * above. + * The first entry after the preamble must be the location in the code + * that the call frame is being described for. + */ +#define FDE_preamble(ORD, fde_no, initial_address, length) \ + .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \ +FDE_start/**/_/**/fde_no: \ + .long frame/**/_/**/ORD; \ + .long initial_address; \ + .long length; + +#define FDE_postamble(fde_no) \ + .align 4; \ +FDE_end/**/_/**/fde_no: +/* + * That done, you can now add registers, subtract registers, move the + * reference and even change the reference. You can also define a new + * area of code the info applies to. For discontinuous bits you should + * start a new FDE. You may have as many as you like. + */ + +/* + * To advance the address by + */ + +#define FDE_advance(bytes) \ + .byte DW_CFA_advance_loc4 \ + .long bytes + + + +/* + * With the above you can define all the register locations. But + * suppose the reference register moves... Takes the new offset NOT an + * increment. This is how esp is tracked if it is not saved. + */ + +#define CFA_define_cfa_offset(offset) \ + .byte $DW_CFA_def_cfa_offset; \ + .uleb128 (offset); +/* + * Or suppose you want to use a different reference register... + */ +#define CFA_define_cfa_register(reg) \ + .byte DW_CFA_def_cfa_register; \ + .uleb128 reg; + +#endif --- linux-2.6.8-rc1/include/linux/ext3_fs.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/ext3_fs.h 2004-07-13 17:09:35.875818920 -0700 @@ -33,11 +33,10 @@ struct statfs; #undef EXT3FS_DEBUG /* - * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files + * Define EXT3_RESERVATION to reserve data blocks for expanding files */ -#undef EXT3_PREALLOCATE /* @@@ Fix this! */ -#define EXT3_DEFAULT_PREALLOC_BLOCKS 8 - +#define EXT3_DEFAULT_RESERVE_BLOCKS 8 +#define EXT3_MAX_RESERVE_BLOCKS 1024 /* * Always enable hashed directories */ @@ -195,6 +194,32 @@ struct ext3_group_desc */ #define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ #define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ +#define EXT3_STATE_RESIZE 0x00000004 /* fake inode for resizing */ + + +/* Used to pass group descriptor data when online resize is done */ +struct ext3_new_group_input { + __u32 group; /* Group number for this data */ + __u32 block_bitmap; /* Absolute block number of block bitmap */ + __u32 inode_bitmap; /* Absolute block number of inode bitmap */ + __u32 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; +}; + +/* The struct ext3_new_group_input in kernel space, with free_blocks_count */ +struct ext3_new_group_data { + __u32 group; + __u32 block_bitmap; + __u32 inode_bitmap; + __u32 inode_table; + __u32 blocks_count; + __u16 reserved_blocks; + __u16 unused; + __u32 free_blocks_count; +}; + /* * ioctl commands @@ -203,11 +228,15 @@ struct ext3_group_desc #define EXT3_IOC_SETFLAGS _IOW('f', 2, long) #define EXT3_IOC_GETVERSION _IOR('f', 3, long) #define EXT3_IOC_SETVERSION _IOW('f', 4, long) +#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) #define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) #define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) #ifdef CONFIG_JBD_DEBUG #define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) #endif +#define EXT3_IOC_GETRSVSZ _IOR('r', 1, long) +#define EXT3_IOC_SETRSVSZ _IOW('r', 2, long) /* * Structure of an inode on the disk @@ -306,24 +335,26 @@ struct ext3_inode { /* * Mount flags */ -#define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */ -#define EXT3_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ -#define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */ -#define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */ -#define EXT3_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ -#define EXT3_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ -#define EXT3_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ -#define EXT3_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ -#define EXT3_MOUNT_NOLOAD 0x0100 /* Don't use existing journal*/ -#define EXT3_MOUNT_ABORT 0x0200 /* Fatal error detected */ -#define EXT3_MOUNT_DATA_FLAGS 0x0C00 /* Mode for data writes: */ - #define EXT3_MOUNT_JOURNAL_DATA 0x0400 /* Write data to journal */ - #define EXT3_MOUNT_ORDERED_DATA 0x0800 /* Flush data before commit */ - #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ -#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ -#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ -#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ -#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */ +#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ +#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */ +#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */ +#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ +#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ +#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ +#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ +#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ +#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */ +#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ +#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ +#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ +#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ +#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ +#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ +#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ +#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ +#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */ +#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -417,7 +448,7 @@ struct ext3_super_block { */ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __u16 s_padding1; + __u16 s_reserved_gdt_blocks; /* Per group desc for online growth */ /* * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. */ @@ -680,8 +711,7 @@ struct dir_private_info { /* balloc.c */ extern int ext3_bg_has_super(struct super_block *sb, int group); extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); -extern int ext3_new_block (handle_t *, struct inode *, unsigned long, - __u32 *, __u32 *, int *); +extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *); extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long, unsigned long); extern unsigned long ext3_count_free_blocks (struct super_block *); @@ -729,6 +759,7 @@ extern void ext3_put_inode (struct inode extern void ext3_delete_inode (struct inode *); extern int ext3_sync_inode (handle_t *, struct inode *); extern void ext3_discard_prealloc (struct inode *); +extern void ext3_discard_reservation (struct inode *); extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); extern void ext3_truncate (struct inode *); @@ -745,6 +776,13 @@ extern int ext3_orphan_del(handle_t *, s extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, __u32 start_minor_hash, __u32 *next_hash); +/* resize.c */ +extern int ext3_group_add(struct super_block *sb, + struct ext3_new_group_data *input); +extern int ext3_group_extend(struct super_block *sb, + struct ext3_super_block *es, + unsigned long n_blocks_count); + /* super.c */ extern void ext3_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); --- linux-2.6.8-rc1/include/linux/ext3_fs_i.h 2003-10-08 15:07:10.000000000 -0700 +++ 25/include/linux/ext3_fs_i.h 2004-07-13 17:09:29.978715416 -0700 @@ -18,8 +18,16 @@ #include +struct reserve_window { + struct list_head rsv_list; + __u32 rsv_start; + __u32 rsv_end; + atomic_t rsv_goal_size; + __u32 rsv_alloc_hit; +}; + /* - * second extended file system inode data in memory + * third extended file system inode data in memory */ struct ext3_inode_info { __u32 i_data[15]; @@ -57,10 +65,9 @@ struct ext3_inode_info { * allocation when we detect linearly ascending requests. */ __u32 i_next_alloc_goal; -#ifdef EXT3_PREALLOCATE - __u32 i_prealloc_block; - __u32 i_prealloc_count; -#endif + /* block reservation window */ + struct reserve_window i_rsv_window; + __u32 i_dir_start_lookup; #ifdef CONFIG_EXT3_FS_XATTR /* --- linux-2.6.8-rc1/include/linux/ext3_fs_sb.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/ext3_fs_sb.h 2004-07-13 17:09:29.978715416 -0700 @@ -59,6 +59,10 @@ struct ext3_sb_info { struct percpu_counter s_dirs_counter; struct blockgroup_lock s_blockgroup_lock; + /* head of the per fs reservation window tree */ + spinlock_t s_rsv_window_lock; + struct reserve_window s_rsv_window_head; + /* Journaling */ struct inode * s_journal_inode; struct journal_s * s_journal; --- linux-2.6.8-rc1/include/linux/fs.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/fs.h 2004-07-13 17:35:09.000000000 -0700 @@ -83,6 +83,7 @@ extern int leases_enable, dir_notify_ena #define SPECIAL 4 /* For non-blockdevice requests in request queue */ #define READ_SYNC (READ | (1 << BIO_RW_SYNC)) #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) +#define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) #define SEL_IN 1 #define SEL_OUT 2 @@ -328,7 +329,7 @@ struct backing_dev_info; struct address_space { struct inode *host; /* owner: inode, block_device */ struct radix_tree_root page_tree; /* radix tree of all pages */ - spinlock_t tree_lock; /* and spinlock protecting it */ + rwlock_t tree_lock; /* and rwlock protecting it */ unsigned long nrpages; /* number of total pages */ pgoff_t writeback_index;/* writeback starts here */ struct address_space_operations *a_ops; /* methods */ @@ -413,6 +414,7 @@ static inline int mapping_writably_mappe struct inode { struct hlist_node i_hash; struct list_head i_list; + struct list_head i_sb_list; struct list_head i_dentry; unsigned long i_ino; atomic_t i_count; @@ -620,6 +622,13 @@ extern void close_private_file(struct fi */ typedef struct files_struct *fl_owner_t; +struct file_lock_operations { + int (*fl_compare_owner)(struct file_lock *, struct file_lock *); + void (*fl_copy_lock)(struct file_lock *, struct file_lock *); + void (*fl_release_private)(struct file_lock *); + void (*fl_steal_locks)(struct file_lock *, fl_owner_t); +}; + /* that will die - we need it for nfs_lock_info */ #include @@ -643,6 +652,7 @@ struct file_lock { struct fasync_struct * fl_fasync; /* for lease break notifications */ unsigned long fl_break_time; /* for nonblocking lease breaks */ + struct file_lock_operations *fl_ops; /* Callbacks for lockmanagers */ union { struct nfs_lock_info nfs_fl; } fl_u; @@ -747,6 +757,7 @@ struct super_block { atomic_t s_active; void *s_security; + struct list_head s_inodes; /* all inodes */ struct list_head s_dirty; /* dirty inodes */ struct list_head s_io; /* parked for writeback */ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ @@ -1405,7 +1416,11 @@ extern ssize_t generic_file_aio_read(str extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *); extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t); extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *, - unsigned long, loff_t *); + unsigned long, loff_t *); +extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *, + unsigned long *, loff_t, loff_t *, size_t, size_t); +extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *, + unsigned long, loff_t, loff_t *, size_t, ssize_t); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, --- linux-2.6.8-rc1/include/linux/gfp.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/gfp.h 2004-07-13 17:09:45.096417176 -0700 @@ -73,6 +73,11 @@ struct vm_area_struct; * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets * optimized to &contig_page_data at compile-time. */ + +#ifndef HAVE_ARCH_FREE_PAGE +static inline void arch_free_page(struct page *page, int order) { } +#endif + extern struct page * FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *)); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/ghash.h 2004-07-13 17:09:46.000000000 -0700 @@ -0,0 +1,236 @@ +/* + * include/linux/ghash.h -- generic hashing with fuzzy retrieval + * + * (C) 1997 Thomas Schoebel-Theuer + * + * The algorithms implemented here seem to be a completely new invention, + * and I'll publish the fundamentals in a paper. + */ + +#ifndef _GHASH_H +#define _GHASH_H +/* HASHSIZE _must_ be a power of two!!! */ + + +#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \ +\ +struct NAME##_table {\ + TYPE * hashtable[HASHSIZE];\ + TYPE * sorted_list;\ + int nr_entries;\ +};\ +\ +struct NAME##_ptrs {\ + TYPE * next_hash;\ + TYPE * prev_hash;\ + TYPE * next_sorted;\ + TYPE * prev_sorted;\ +}; + +#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\ +\ +LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + int ix = HASHFN(elem->KEY);\ + TYPE ** base = &tbl->hashtable[ix];\ + TYPE * ptr = *base;\ + TYPE * prev = NULL;\ +\ + tbl->nr_entries++;\ + while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ + base = &ptr->PTRS.next_hash;\ + prev = ptr;\ + ptr = *base;\ + }\ + elem->PTRS.next_hash = ptr;\ + elem->PTRS.prev_hash = prev;\ + if(ptr) {\ + ptr->PTRS.prev_hash = elem;\ + }\ + *base = elem;\ +\ + ptr = prev;\ + if(!ptr) {\ + ptr = tbl->sorted_list;\ + prev = NULL;\ + } else {\ + prev = ptr->PTRS.prev_sorted;\ + }\ + while(ptr) {\ + TYPE * next = ptr->PTRS.next_hash;\ + if(next && KEYCMP(next->KEY, elem->KEY)) {\ + prev = ptr;\ + ptr = next;\ + } else if(KEYCMP(ptr->KEY, elem->KEY)) {\ + prev = ptr;\ + ptr = ptr->PTRS.next_sorted;\ + } else\ + break;\ + }\ + elem->PTRS.next_sorted = ptr;\ + elem->PTRS.prev_sorted = prev;\ + if(ptr) {\ + ptr->PTRS.prev_sorted = elem;\ + }\ + if(prev) {\ + prev->PTRS.next_sorted = elem;\ + } else {\ + tbl->sorted_list = elem;\ + }\ +}\ +\ +LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + TYPE * next = elem->PTRS.next_hash;\ + TYPE * prev = elem->PTRS.prev_hash;\ +\ + tbl->nr_entries--;\ + if(next)\ + next->PTRS.prev_hash = prev;\ + if(prev)\ + prev->PTRS.next_hash = next;\ + else {\ + int ix = HASHFN(elem->KEY);\ + tbl->hashtable[ix] = next;\ + }\ +\ + next = elem->PTRS.next_sorted;\ + prev = elem->PTRS.prev_sorted;\ + if(next)\ + next->PTRS.prev_sorted = prev;\ + if(prev)\ + prev->PTRS.next_sorted = next;\ + else\ + tbl->sorted_list = next;\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix = hashfn(pos);\ + TYPE * ptr = tbl->hashtable[ix];\ + while(ptr && KEYCMP(ptr->KEY, pos))\ + ptr = ptr->PTRS.next_hash;\ + if(ptr && !KEYEQ(ptr->KEY, pos))\ + ptr = NULL;\ + return ptr;\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix;\ + int offset;\ + TYPE * ptr;\ + TYPE * next;\ +\ + ptr = tbl->sorted_list;\ + if(!ptr || KEYCMP(pos, ptr->KEY))\ + return NULL;\ + ix = HASHFN(pos);\ + offset = HASHSIZE;\ + do {\ + offset >>= 1;\ + next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\ + if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\ + && KEYCMP(ptr->KEY, next->KEY))\ + ptr = next;\ + } while(offset);\ +\ + for(;;) {\ + next = ptr->PTRS.next_hash;\ + if(next) {\ + if(KEYCMP(next->KEY, pos)) {\ + ptr = next;\ + continue;\ + }\ + }\ + next = ptr->PTRS.next_sorted;\ + if(next && KEYCMP(next->KEY, pos)) {\ + ptr = next;\ + continue;\ + }\ + return ptr;\ + }\ + return NULL;\ +} + +/* LINKAGE - empty or "static", depending on whether you want the definitions to + * be public or not + * NAME - a string to stick in names to make this hash table type distinct from + * any others + * HASHSIZE - number of buckets + * TYPE - type of data contained in the buckets - must be a structure, one + * field is of type NAME_ptrs, another is the hash key + * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that + * field + * KEYTYPE - type of the key field within TYPE + * KEY - name of the key field within TYPE + * KEYCMP - pointer to function that compares KEYTYPEs to each other - the + * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, + * non-zero for not equal + * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE), + * it returns a number in the range 0 ... HASHSIZE - 1 + * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call + * DEF_HASH. + */ + +#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \ +\ +struct NAME##_table {\ + TYPE * hashtable[HASHSIZE];\ + int nr_entries;\ +};\ +\ +struct NAME##_ptrs {\ + TYPE * next_hash;\ + TYPE * prev_hash;\ +}; + +#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\ +\ +LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + int ix = HASHFN(elem->KEY);\ + TYPE ** base = &tbl->hashtable[ix];\ + TYPE * ptr = *base;\ + TYPE * prev = NULL;\ +\ + tbl->nr_entries++;\ + while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\ + base = &ptr->PTRS.next_hash;\ + prev = ptr;\ + ptr = *base;\ + }\ + elem->PTRS.next_hash = ptr;\ + elem->PTRS.prev_hash = prev;\ + if(ptr) {\ + ptr->PTRS.prev_hash = elem;\ + }\ + *base = elem;\ +}\ +\ +LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ +{\ + TYPE * next = elem->PTRS.next_hash;\ + TYPE * prev = elem->PTRS.prev_hash;\ +\ + tbl->nr_entries--;\ + if(next)\ + next->PTRS.prev_hash = prev;\ + if(prev)\ + prev->PTRS.next_hash = next;\ + else {\ + int ix = HASHFN(elem->KEY);\ + tbl->hashtable[ix] = next;\ + }\ +}\ +\ +LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ +{\ + int ix = HASHFN(pos);\ + TYPE * ptr = tbl->hashtable[ix];\ + while(ptr && KEYCMP(ptr->KEY, pos))\ + ptr = ptr->PTRS.next_hash;\ + return ptr;\ +} + +#endif --- linux-2.6.8-rc1/include/linux/hiddev.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/linux/hiddev.h 2004-07-13 17:09:22.000000000 -0700 @@ -128,10 +128,11 @@ struct hiddev_usage_ref { /* hiddev_usage_ref_multi is used for sending multiple bytes to a control. * It really manifests itself as setting the value of consecutive usages */ +#define HID_MAX_MULTI_USAGES 1024 struct hiddev_usage_ref_multi { struct hiddev_usage_ref uref; __u32 num_values; - __s32 values[HID_MAX_USAGES]; + __s32 values[HID_MAX_MULTI_USAGES]; }; /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags @@ -212,6 +213,11 @@ struct hiddev_usage_ref_multi { * In-kernel definitions. */ +struct hid_device; +struct hid_usage; +struct hid_field; +struct hid_report; + #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); --- linux-2.6.8-rc1/include/linux/ide.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/ide.h 2004-07-13 17:09:31.329510064 -0700 @@ -780,6 +780,7 @@ typedef struct ide_drive_s { u8 sect; /* "real" sectors per track */ u8 bios_head; /* BIOS/fdisk/LILO number of heads */ u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */ + u8 doing_barrier; /* state, 1=currently doing flush */ unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ @@ -1293,6 +1294,11 @@ extern ide_startstop_t ide_do_reset (ide extern void ide_init_drive_cmd (struct request *rq); /* + * this function returns error location sector offset in case of a write error + */ +extern u64 ide_get_error_location(ide_drive_t *, char *); + +/* * "action" parameter type for ide_do_drive_cmd() below. */ typedef enum { @@ -1664,4 +1670,11 @@ extern struct semaphore ide_cfg_sem; extern struct bus_type ide_bus_type; +/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */ +#define ide_id_has_flush_cache(id) ((id)->cfs_enable_2 & 0x3000) + +/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */ +#define ide_id_has_flush_cache_ext(id) \ + (((id)->cfs_enable_2 & 0x2400) == 0x2400) + #endif /* _IDE_H */ --- linux-2.6.8-rc1/include/linux/input.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/input.h 2004-07-13 17:09:22.105912264 -0700 @@ -527,6 +527,8 @@ struct input_absinfo { #define MSC_SERIAL 0x00 #define MSC_PULSELED 0x01 #define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 #define MSC_MAX 0x07 /* --- linux-2.6.8-rc1/include/linux/isdnif.h 2004-03-10 20:41:31.000000000 -0800 +++ 25/include/linux/isdnif.h 2004-07-13 17:09:13.000000000 -0700 @@ -502,26 +502,18 @@ typedef struct { * Parameters: * u_char pointer data * int length of data - * int Flag: 0 = Call form Kernel-Space (use memcpy, - * no schedule allowed) - * 1 = Data is in User-Space (use memcpy_fromfs, - * may schedule) * int driverId * int local channel-number (0 ...) */ - int (*writecmd)(const u_char*, int, int, int, int); + int (*writecmd)(const u_char __user *, int, int, int); /* Read raw Status replies * u_char pointer data (volatile) * int length of buffer - * int Flag: 0 = Call form Kernel-Space (use memcpy, - * no schedule allowed) - * 1 = Data is in User-Space (use memcpy_fromfs, - * may schedule) * int driverId * int local channel-number (0 ...) */ - int (*readstat)(u_char*, int, int, int, int); + int (*readstat)(u_char __user *, int, int, int); char id[20]; } isdn_if; --- linux-2.6.8-rc1/include/linux/istallion.h 2004-03-10 20:41:31.000000000 -0800 +++ 25/include/linux/istallion.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * istallion.h -- stallion intelligent multiport serial driver. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This program is free software; you can redistribute it and/or modify --- linux-2.6.8-rc1/include/linux/jbd.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/jbd.h 2004-07-13 17:09:32.309361104 -0700 @@ -840,6 +840,7 @@ struct journal_s #define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ #define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ #define JFS_LOADED 0x010 /* The journal superblock has been loaded */ +#define JFS_BARRIER 0x020 /* Use IDE barriers */ /* * Function declarations for the journaling transaction and buffer --- linux-2.6.8-rc1/include/linux/kernelcapi.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/kernelcapi.h 2004-07-13 17:09:13.000000000 -0700 @@ -81,7 +81,7 @@ u16 capi20_get_manufacturer(u32 contr, u u16 capi20_get_version(u32 contr, struct capi_version *verp); u16 capi20_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN]); u16 capi20_get_profile(u32 contr, struct capi_profile *profp); -int capi20_manufacturer(unsigned int cmd, void *data); +int capi20_manufacturer(unsigned int cmd, void __user *data); /* temporary hack XXX */ void capi20_set_callback(struct capi20_appl *ap, --- linux-2.6.8-rc1/include/linux/kernel.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/kernel.h 2004-07-13 17:09:50.722561872 -0700 @@ -134,6 +134,7 @@ extern const char *print_tainted(void); /* Values used for system_state */ extern enum system_states { SYSTEM_BOOTING, + SYSTEM_BOOTING_SCHEDULER_OK, SYSTEM_RUNNING, SYSTEM_HALT, SYSTEM_POWER_OFF, --- linux-2.6.8-rc1/include/linux/libata.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/libata.h 2004-07-13 17:09:22.000000000 -0700 @@ -32,7 +32,6 @@ /* * compile-time options */ -#undef ATA_FORCE_PIO /* do not configure or use DMA */ #undef ATA_DEBUG /* debugging output */ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ @@ -88,10 +87,7 @@ enum { /* struct ata_device stuff */ ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ - ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ - ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can - * (hopefully) flush? */ - ATA_DFLAG_LOCK_SECTORS = (1 << 4), /* don't adjust max_sectors */ + ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -111,7 +107,6 @@ enum { ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ - ATA_QCFLAG_DMA = (1 << 2), /* data delivered via DMA */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, @@ -140,6 +135,13 @@ enum { PORT_UNKNOWN = 0, PORT_ENABLED = 1, PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_SHIFT_UDMA = 0, + ATA_SHIFT_MWDMA = 8, + ATA_SHIFT_PIO = 11, }; enum pio_task_states { @@ -188,6 +190,7 @@ struct ata_probe_ent { struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int legacy_mode; unsigned long irq; @@ -215,6 +218,9 @@ struct ata_queued_cmd { struct scsi_cmnd *scsicmd; void (*scsidone)(struct scsi_cmnd *); + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned int tag; unsigned int n_elem; @@ -226,7 +232,6 @@ struct ata_queued_cmd { unsigned int cursg; unsigned int cursg_ofs; - struct ata_taskfile tf; struct scatterlist sgent; void *buf_virt; @@ -251,8 +256,10 @@ struct ata_device { unsigned int class; /* ATA_DEV_xxx */ unsigned int devno; /* 0 or 1 */ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ - unsigned int pio_mode; - unsigned int udma_mode; + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; /* ATA_SHIFT_xxx */ /* cache info about current transfer mode */ u8 xfer_protocol; /* taskfile xfer protocol */ @@ -277,8 +284,10 @@ struct ata_port { unsigned int bus_state; unsigned int port_state; unsigned int pio_mask; + unsigned int mwdma_mask; unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ + unsigned int cdb_len; struct ata_device device[ATA_MAX_DEVICES]; @@ -303,10 +312,8 @@ struct ata_port_operations { void (*dev_config) (struct ata_port *, struct ata_device *); - void (*set_piomode) (struct ata_port *, struct ata_device *, - unsigned int); - void (*set_udmamode) (struct ata_port *, struct ata_device *, - unsigned int); + void (*set_piomode) (struct ata_port *, struct ata_device *); + void (*set_dmamode) (struct ata_port *, struct ata_device *); void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); @@ -342,6 +349,7 @@ struct ata_port_info { Scsi_Host_Template *sht; unsigned long host_flags; unsigned long pio_mask; + unsigned long mwdma_mask; unsigned long udma_mask; struct ata_port_operations *port_ops; }; @@ -472,7 +480,6 @@ static inline u8 ata_wait_idle(struct at static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) { - qc->flags &= ~ATA_QCFLAG_DMA; qc->tf.ctl |= ATA_NIEN; } --- linux-2.6.8-rc1/include/linux/list.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/list.h 2004-07-13 17:09:28.964869544 -0700 @@ -6,6 +6,7 @@ #include #include #include +#include /* * These are non-NULL pointers that will result in page faults @@ -160,6 +161,8 @@ static inline void __list_del(struct lis */ static inline void list_del(struct list_head *entry) { + BUG_ON(entry->prev->next != entry); + BUG_ON(entry->next->prev != entry); __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; --- linux-2.6.8-rc1/include/linux/lockd/lockd.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/linux/lockd/lockd.h 2004-07-13 17:09:40.283148904 -0700 @@ -52,10 +52,25 @@ struct nlm_host { wait_queue_head_t h_gracewait; /* wait while reclaiming */ u32 h_state; /* pseudo-state counter */ u32 h_nsmstate; /* true remote NSM state */ - unsigned int h_count; /* reference count */ + u32 h_pidcount; /* Pseudopids */ + atomic_t h_count; /* reference count */ struct semaphore h_sema; /* mutex for pmap binding */ unsigned long h_nextrebind; /* next portmap call */ unsigned long h_expires; /* eligible for GC */ + struct list_head h_lockowners; /* Lockowners for the client */ + spinlock_t h_lock; +}; + +/* + * Map an fl_owner_t into a unique 32-bit "pid" + */ +struct nlm_lockowner { + struct list_head list; + atomic_t count; + + struct nlm_host *host; + fl_owner_t owner; + uint32_t pid; }; /* @@ -205,6 +220,8 @@ nlm_compare_locks(struct file_lock *fl1, &&(fl1->fl_type == fl2->fl_type || fl2->fl_type == F_UNLCK); } +extern struct file_lock_operations nlmsvc_lock_operations; + #endif /* __KERNEL__ */ #endif /* LINUX_LOCKD_LOCKD_H */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/lockmeter.h 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,320 @@ +/* + * Copyright (C) 1999-2002 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.h by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000 + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + * Moved machine dependent code to include/asm/lockmeter.h. + * + */ + +#ifndef _LINUX_LOCKMETER_H +#define _LINUX_LOCKMETER_H + + +/*--------------------------------------------------- + * architecture-independent lockmeter.h + *-------------------------------------------------*/ + +/* + * raybry -- version 2: added efficient hold time statistics + * requires lstat recompile, so flagged as new version + * raybry -- version 3: added global reader lock data + * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port + */ +#define LSTAT_VERSION 5 + +int lstat_update(void*, void*, int); +int lstat_update_time(void*, void*, int, uint32_t); + +/* + * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we + * need to force compatibility in the inter-communication data structure. + */ + +#if defined(CONFIG_MIPS32_COMPAT) +#define TIME_T uint32_t +#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64) +#define TIME_T uint64_t +#else +#define TIME_T time_t +#endif + +#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32) +#define POINTER void * +#else +#define POINTER int64_t +#endif + +/* + * Values for the "action" parameter passed to lstat_update. + * ZZZ - do we want a try-success status here??? + */ +#define LSTAT_ACT_NO_WAIT 0 +#define LSTAT_ACT_SPIN 1 +#define LSTAT_ACT_REJECT 2 +#define LSTAT_ACT_WW_SPIN 3 +#define LSTAT_ACT_SLEPT 4 /* UNUSED */ + +#define LSTAT_ACT_MAX_VALUES 4 /* NOTE: Increase to 5 if use ACT_SLEPT */ + +/* + * Special values for the low 2 bits of an RA passed to + * lstat_update. + */ +/* we use these values to figure out what kind of lock data */ +/* is stored in the statistics table entry at index ....... */ +#define LSTAT_RA_SPIN 0 /* spin lock data */ +#define LSTAT_RA_READ 1 /* read lock statistics */ +#define LSTAT_RA_SEMA 2 /* RESERVED */ +#define LSTAT_RA_WRITE 3 /* write lock statistics*/ + +#define LSTAT_RA(n) \ + ((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) ) + +/* + * Constants used for lock addresses in the lstat_directory + * to indicate special values of the lock address. + */ +#define LSTAT_MULTI_LOCK_ADDRESS NULL + +/* + * Maximum size of the lockstats tables. Increase this value + * if its not big enough. (Nothing bad happens if its not + * big enough although some locks will not be monitored.) + * We record overflows of this quantity in lstat_control.dir_overflows + * + * Note: The max value here must fit into the field set + * and obtained by the macro's PUT_INDEX() and GET_INDEX(). + * This value depends on how many bits are available in the + * lock word in the particular machine implementation we are on. + */ +#define LSTAT_MAX_STAT_INDEX 2000 + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This defines an entry in the lockstat directory. It contains + * information about a lock being monitored. + * A directory entry only contains the lock identification - + * counts on usage of the lock are kept elsewhere in a per-cpu + * data structure to minimize cache line pinging. + */ +typedef struct { + POINTER caller_ra; /* RA of code that set lock */ + POINTER lock_ptr; /* lock address */ + ushort next_stat_index; /* Used to link multiple locks that have the same hash table value */ +} lstat_directory_entry_t; + +/* + * A multi-dimensioned array used to contain counts for lock accesses. + * The array is 3-dimensional: + * - CPU number. Keep from thrashing cache lines between CPUs + * - Directory entry index. Identifies the lock + * - Action. Indicates what kind of contention occurred on an + * access to the lock. + * + * The index of an entry in the directory is the same as the 2nd index + * of the entry in the counts array. + */ +/* + * This table contains data for spin_locks, write locks, and read locks + * Not all data is used for all cases. In particular, the hold time + * information is not stored here for read locks since that is a global + * (e. g. cannot be separated out by return address) quantity. + * See the lstat_read_lock_counts_t structure for the global read lock + * hold time. + */ +typedef struct { + uint64_t cum_wait_ticks; /* sum of wait times */ + /* for write locks, sum of time a */ + /* writer is waiting for a reader */ + int64_t cum_hold_ticks; /* cumulative sum of holds */ + /* not used for read mode locks */ + /* must be signed. ............... */ + uint32_t max_wait_ticks; /* max waiting time */ + uint32_t max_hold_ticks; /* max holding time */ + uint64_t cum_wait_ww_ticks; /* sum times writer waits on writer*/ + uint32_t max_wait_ww_ticks; /* max wait time writer vs writer */ + /* prev 2 only used for write locks*/ + uint32_t acquire_time; /* time lock acquired this CPU */ + uint32_t count[LSTAT_ACT_MAX_VALUES]; +} lstat_lock_counts_t; + +typedef lstat_lock_counts_t lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX]; + +/* + * User request to: + * - turn statistic collection on/off, or to reset + */ +#define LSTAT_OFF 0 +#define LSTAT_ON 1 +#define LSTAT_RESET 2 +#define LSTAT_RELEASE 3 + +#define LSTAT_MAX_READ_LOCK_INDEX 1000 +typedef struct { + POINTER lock_ptr; /* address of lock for output stats */ + uint32_t read_lock_count; + int64_t cum_hold_ticks; /* sum of read lock hold times over */ + /* all callers. ....................*/ + uint32_t write_index; /* last write lock hash table index */ + uint32_t busy_periods; /* count of busy periods ended this */ + uint64_t start_busy; /* time this busy period started. ..*/ + uint64_t busy_ticks; /* sum of busy periods this lock. ..*/ + uint64_t max_busy; /* longest busy period for this lock*/ + uint32_t max_readers; /* maximum number of readers ...... */ +#ifdef USER_MODE_TESTING + rwlock_t entry_lock; /* lock for this read lock entry... */ + /* avoid having more than one rdr at*/ + /* needed for user space testing... */ + /* not needed for kernel 'cause it */ + /* is non-preemptive. ............. */ +#endif +} lstat_read_lock_counts_t; +typedef lstat_read_lock_counts_t lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX]; + +#if defined(__KERNEL__) || defined(USER_MODE_TESTING) + +#ifndef USER_MODE_TESTING +#include +#else +#include "asm_newlockmeter.h" +#endif + +/* + * Size and mask for the hash table into the directory. + */ +#define LSTAT_HASH_TABLE_SIZE 4096 /* must be 2**N */ +#define LSTAT_HASH_TABLE_MASK (LSTAT_HASH_TABLE_SIZE-1) + +#define DIRHASH(ra) ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK) + +/* + * This version eliminates the per processor lock stack. What we do is to + * store the index of the lock hash structure in unused bits in the lock + * itself. Then on unlock we can find the statistics record without doing + * any additional hash or lock stack lookup. This works for spin_locks. + * Hold time reporting is now basically as cheap as wait time reporting + * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT + * as in version 1.1.* of lockmeter. + * + * For rw_locks, we store the index of a global reader stats structure in + * the lock and the writer index is stored in the latter structure. + * For read mode locks we hash at the time of the lock to find an entry + * in the directory for reader wait time and the like. + * At unlock time for read mode locks, we update just the global structure + * so we don't need to know the reader directory index value at unlock time. + * + */ + +/* + * Protocol to change lstat_control.state + * This is complicated because we don't want the cum_hold_time for + * a rw_lock to be decremented in _read_lock_ without making sure it + * is incremented in _read_lock_ and vice versa. So here is the + * way we change the state of lstat_control.state: + * I. To Turn Statistics On + * After allocating storage, set lstat_control.state non-zero. + * This works because we don't start updating statistics for in use + * locks until the reader lock count goes to zero. + * II. To Turn Statistics Off: + * (0) Disable interrupts on this CPU + * (1) Seize the lstat_control.directory_lock + * (2) Obtain the current value of lstat_control.next_free_read_lock_index + * (3) Store a zero in lstat_control.state. + * (4) Release the lstat_control.directory_lock + * (5) For each lock in the read lock list up to the saved value + * (well, -1) of the next_free_read_lock_index, do the following: + * (a) Check validity of the stored lock address + * by making sure that the word at the saved addr + * has an index that matches this entry. If not + * valid, then skip this entry. + * (b) If there is a write lock already set on this lock, + * skip to (d) below. + * (c) Set a non-metered write lock on the lock + * (d) set the cached INDEX in the lock to zero + * (e) Release the non-metered write lock. + * (6) Re-enable interrupts + * + * These rules ensure that a read lock will not have its statistics + * partially updated even though the global lock recording state has + * changed. See put_lockmeter_info() for implementation. + * + * The reason for (b) is that there may be write locks set on the + * syscall path to put_lockmeter_info() from user space. If we do + * not do this check, then we can deadlock. A similar problem would + * occur if the lock was read locked by the current CPU. At the + * moment this does not appear to happen. + */ + +/* + * Main control structure for lockstat. Used to turn statistics on/off + * and to maintain directory info. + */ +typedef struct { + int state; + spinlock_t control_lock; /* used to serialize turning statistics on/off */ + spinlock_t directory_lock; /* for serialize adding entries to directory */ + volatile int next_free_dir_index;/* next free entry in the directory */ + /* FIXME not all of these fields are used / needed .............. */ + /* the following fields represent data since */ + /* first "lstat on" or most recent "lstat reset" */ + TIME_T first_started_time; /* time when measurement first enabled */ + TIME_T started_time; /* time when measurement last started */ + TIME_T ending_time; /* time when measurement last disabled */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when measurement last disabled */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i. e. number of times did lstat on;lstat off */ + lstat_directory_entry_t *dir; /* directory */ + int dir_overflow; /* count of times ran out of space in directory */ + int rwlock_overflow; /* count of times we couldn't allocate a rw block*/ + ushort *hashtab; /* hash table for quick dir scans */ + lstat_cpu_counts_t *counts[NR_CPUS]; /* Array of pointers to per-cpu stats */ + int next_free_read_lock_index; /* next rwlock reader (global) stats block */ + lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats */ +} lstat_control_t; + +#endif /* defined(__KERNEL__) || defined(USER_MODE_TESTING) */ + +typedef struct { + short lstat_version; /* version of the data */ + short state; /* the current state is returned */ + int maxcpus; /* Number of cpus present */ + int next_free_dir_index; /* index of the next free directory entry */ + TIME_T first_started_time; /* when measurement enabled for first time */ + TIME_T started_time; /* time in secs since 1969 when stats last turned on */ + TIME_T ending_time; /* time in secs since 1969 when stats last turned off */ + uint32_t cycleval; /* cycles per second */ +#ifdef notyet + void *kernel_magic_addr; /* address of kernel_magic */ + void *kernel_end_addr; /* contents of kernel magic (points to "end") */ +#endif + int next_free_read_lock_index; /* index of next (global) read lock stats struct */ + uint64_t started_cycles64; /* cycles when measurement last started */ + uint64_t ending_cycles64; /* cycles when stats last turned off */ + uint64_t enabled_cycles64; /* total cycles with measurement enabled */ + int intervals; /* number of measurement intervals recorded */ + /* i.e. number of times we did lstat on;lstat off*/ + int dir_overflow; /* number of times we wanted more space in directory */ + int rwlock_overflow; /* # of times we wanted more space in read_locks_count */ + struct new_utsname uts; /* info about machine where stats are measured */ + /* -T option of lockstat allows data to be */ + /* moved to another machine. ................. */ +} lstat_user_request_t; + +#endif /* _LINUX_LOCKMETER_H */ --- linux-2.6.8-rc1/include/linux/major.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/linux/major.h 2004-07-13 17:09:41.863908592 -0700 @@ -111,6 +111,8 @@ #define MDISK_MAJOR 95 +#define PACKET_MAJOR 97 + #define UBD_MAJOR 98 #define JSFD_MAJOR 99 --- linux-2.6.8-rc1/include/linux/mmzone.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/mmzone.h 2004-07-13 17:35:10.646498312 -0700 @@ -20,18 +20,6 @@ #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif -/* - * system hash table size limits - * - on large memory machines, we may want to allocate a bigger hash than that - * permitted by MAX_ORDER, so we allocate with the bootmem allocator, and are - * limited to this size - */ -#if MAX_ORDER > 14 -#define MAX_SYS_HASH_TABLE_ORDER MAX_ORDER -#else -#define MAX_SYS_HASH_TABLE_ORDER 14 -#endif - struct free_area { struct list_head free_list; unsigned long *map; --- linux-2.6.8-rc1/include/linux/mtd/mtd.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/mtd/mtd.h 2004-07-13 17:09:13.000000000 -0700 @@ -12,11 +12,6 @@ #include #include -struct kvec { - void *iov_base; /* and that should *never* hold a userland pointer */ - size_t iov_len; -}; - #endif /* __KERNEL__ */ struct erase_info_user { --- linux-2.6.8-rc1/include/linux/netdevice.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/netdevice.h 2004-07-13 17:09:13.650197728 -0700 @@ -565,7 +565,7 @@ typedef int gifconf_func_t(struct net_de extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); static inline int unregister_gifconf(unsigned int family) { - return register_gifconf(family, 0); + return register_gifconf(family, NULL); } /* --- linux-2.6.8-rc1/include/linux/nfs_fs_i.h 2003-06-14 12:18:07.000000000 -0700 +++ 25/include/linux/nfs_fs_i.h 2004-07-13 17:09:40.283148904 -0700 @@ -5,13 +5,15 @@ #include #include +struct nlm_lockowner; + /* * NFS lock info */ struct nfs_lock_info { u32 state; u32 flags; - struct nlm_host *host; + struct nlm_lockowner *owner; }; /* --- linux-2.6.8-rc1/include/linux/pagemap.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/pagemap.h 2004-07-13 17:09:51.000000000 -0700 @@ -156,6 +156,7 @@ extern void FASTCALL(unlock_page(struct static inline void lock_page(struct page *page) { + might_sleep(); if (TestSetPageLocked(page)) __lock_page(page); } --- linux-2.6.8-rc1/include/linux/pci_ids.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/pci_ids.h 2004-07-13 17:09:23.569689736 -0700 @@ -1063,21 +1063,33 @@ #define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 +#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037 +#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 +#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 +#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 +#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 +#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086 +#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6 +#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da +#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 +#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 @@ -1105,6 +1117,7 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 #define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3 #define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 @@ -1175,7 +1188,9 @@ #define PCI_VENDOR_ID_VIA 0x1106 #define PCI_DEVICE_ID_VIA_8763_0 0x0198 #define PCI_DEVICE_ID_VIA_8380_0 0x0204 +#define PCI_DEVICE_ID_VIA_3238_0 0x0238 #define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 +#define PCI_DEVICE_ID_VIA_3269_0 0x0269 #define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 #define PCI_DEVICE_ID_VIA_8363_0 0x0305 #define PCI_DEVICE_ID_VIA_8371_0 0x0391 @@ -1212,12 +1227,13 @@ #define PCI_DEVICE_ID_VIA_82C686_6 0x3068 #define PCI_DEVICE_ID_VIA_8233_0 0x3074 #define PCI_DEVICE_ID_VIA_8633_0 0x3091 -#define PCI_DEVICE_ID_VIA_8367_0 0x3099 +#define PCI_DEVICE_ID_VIA_8367_0 0x3099 #define PCI_DEVICE_ID_VIA_8653_0 0x3101 -#define PCI_DEVICE_ID_VIA_8622 0x3102 +#define PCI_DEVICE_ID_VIA_8622 0x3102 #define PCI_DEVICE_ID_VIA_8233C_0 0x3109 #define PCI_DEVICE_ID_VIA_8361 0x3112 #define PCI_DEVICE_ID_VIA_XM266 0x3116 +#define PCI_DEVICE_ID_VIA_612X 0x3119 #define PCI_DEVICE_ID_VIA_862X_0 0x3123 #define PCI_DEVICE_ID_VIA_8753_0 0x3128 #define PCI_DEVICE_ID_VIA_8233A 0x3147 @@ -1234,6 +1250,7 @@ #define PCI_DEVICE_ID_VIA_PT880 0x3258 #define PCI_DEVICE_ID_VIA_P4M400 0x3209 #define PCI_DEVICE_ID_VIA_8237 0x3227 +#define PCI_DEVICE_ID_VIA_3296_0 0x0296 #define PCI_DEVICE_ID_VIA_86C100A 0x6100 #define PCI_DEVICE_ID_VIA_8231 0x8231 #define PCI_DEVICE_ID_VIA_8231_4 0x8235 @@ -2040,6 +2057,7 @@ #define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 #define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222 #define PCI_DEVICE_ID_INTEL_7116 0x1223 +#define PCI_DEVICE_ID_INTEL_7501_0 0x254c #define PCI_DEVICE_ID_INTEL_7505_0 0x2550 #define PCI_DEVICE_ID_INTEL_7505_1 0x2552 #define PCI_DEVICE_ID_INTEL_7205_0 0x255d @@ -2145,6 +2163,8 @@ #define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 #define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 #define PCI_DEVICE_ID_INTEL_82875_IG 0x257b +#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580 +#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 #define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 #define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 #define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 --- linux-2.6.8-rc1/include/linux/percpu_counter.h 2004-01-09 00:04:32.000000000 -0800 +++ 25/include/linux/percpu_counter.h 2004-07-13 17:35:09.000000000 -0700 @@ -1,3 +1,5 @@ +#ifndef _LINUX_PERCPU_COUNTER_H +#define _LINUX_PERCPU_COUNTER_H /* * A simple "approximate counter" for use in ext2 and ext3 superblocks. * @@ -101,3 +103,5 @@ static inline void percpu_counter_dec(st { percpu_counter_mod(fbc, -1); } + +#endif /* _LINUX_PERCPU_COUNTER_H */ --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/perfctr.h 2004-07-13 17:09:35.127932616 -0700 @@ -0,0 +1,161 @@ +/* $Id: perfctr.h,v 1.78 2004/05/31 20:45:51 mikpe Exp $ + * Performance-Monitoring Counters driver + * + * Copyright (C) 1999-2004 Mikael Pettersson + */ +#ifndef _LINUX_PERFCTR_H +#define _LINUX_PERFCTR_H + +#ifdef CONFIG_PERFCTR /* don't break archs without */ + +#include + +struct perfctr_info { + unsigned int abi_version; + char driver_version[32]; + unsigned int cpu_type; + unsigned int cpu_features; + unsigned int cpu_khz; + unsigned int tsc_to_cpu_mult; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +struct perfctr_cpu_mask { + unsigned int nrwords; + unsigned int mask[1]; /* actually 'nrwords' */ +}; + +/* abi_version values: Lower 16 bits contain the CPU data version, upper + 16 bits contain the API version. Each half has a major version in its + upper 8 bits, and a minor version in its lower 8 bits. */ +#define PERFCTR_API_VERSION 0x0600 /* 6.0 */ +#define PERFCTR_ABI_VERSION ((PERFCTR_API_VERSION<<16)|PERFCTR_CPU_VERSION) + +/* cpu_features flag bits */ +#define PERFCTR_FEATURE_RDPMC 0x01 +#define PERFCTR_FEATURE_RDTSC 0x02 +#define PERFCTR_FEATURE_PCINT 0x04 + +/* user's view of mmap:ed virtual perfctr */ +struct vperfctr_state { + struct perfctr_cpu_state cpu_state; +}; + +/* virtual perfctr control object */ +struct vperfctr_control { + int si_signo; + struct perfctr_cpu_control cpu_control; + unsigned int preserve; + unsigned int _reserved1; + unsigned int _reserved2; + unsigned int _reserved3; + unsigned int _reserved4; +}; + +#else +struct perfctr_info; +struct perfctr_cpu_mask; +struct perfctr_sum_ctrs; +struct vperfctr_control; +#endif /* CONFIG_PERFCTR */ + +#ifdef __KERNEL__ + +/* + * The perfctr system calls. + */ +asmlinkage long sys_perfctr_info(struct perfctr_info __user*, + struct perfctr_cpu_mask __user*, + struct perfctr_cpu_mask __user*); +asmlinkage long sys_vperfctr_open(int tid, int creat); +asmlinkage long sys_vperfctr_control(int fd, + const struct vperfctr_control __user*); +asmlinkage long sys_vperfctr_unlink(int fd); +asmlinkage long sys_vperfctr_iresume(int fd); +asmlinkage long sys_vperfctr_read(int fd, + struct perfctr_sum_ctrs __user*, + struct vperfctr_control __user*); + +extern struct perfctr_info perfctr_info; + +#ifdef CONFIG_PERFCTR_VIRTUAL + +/* + * Virtual per-process performance-monitoring counters. + */ +struct vperfctr; /* opaque */ + +/* process management operations */ +extern struct vperfctr *__vperfctr_copy(struct vperfctr*); +extern void __vperfctr_exit(struct vperfctr*); +extern void __vperfctr_suspend(struct vperfctr*); +extern void __vperfctr_resume(struct vperfctr*); +extern void __vperfctr_sample(struct vperfctr*); +extern void __vperfctr_set_cpus_allowed(struct task_struct*, struct vperfctr*, cpumask_t); + +static inline void perfctr_copy_thread(struct thread_struct *thread) +{ + thread->perfctr = NULL; +} + +static inline void perfctr_exit_thread(struct thread_struct *thread) +{ + struct vperfctr *perfctr; + perfctr = thread->perfctr; + if (perfctr) + __vperfctr_exit(perfctr); +} + +static inline void perfctr_suspend_thread(struct thread_struct *prev) +{ + struct vperfctr *perfctr; + perfctr = prev->perfctr; + if (perfctr) + __vperfctr_suspend(perfctr); +} + +static inline void perfctr_resume_thread(struct thread_struct *next) +{ + struct vperfctr *perfctr; + perfctr = next->perfctr; + if (perfctr) + __vperfctr_resume(perfctr); +} + +static inline void perfctr_sample_thread(struct thread_struct *thread) +{ + struct vperfctr *perfctr; + perfctr = thread->perfctr; + if (perfctr) + __vperfctr_sample(perfctr); +} + +static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t new_mask) +{ +#ifdef CONFIG_PERFCTR_CPUS_FORBIDDEN_MASK + struct vperfctr *perfctr; + + task_lock(p); + perfctr = p->thread.perfctr; + if (perfctr) + __vperfctr_set_cpus_allowed(p, perfctr, new_mask); + task_unlock(p); +#endif +} + +#else /* !CONFIG_PERFCTR_VIRTUAL */ + +static inline void perfctr_copy_thread(struct thread_struct *t) { } +static inline void perfctr_exit_thread(struct thread_struct *t) { } +static inline void perfctr_suspend_thread(struct thread_struct *t) { } +static inline void perfctr_resume_thread(struct thread_struct *t) { } +static inline void perfctr_sample_thread(struct thread_struct *t) { } +static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t m) { } + +#endif /* CONFIG_PERFCTR_VIRTUAL */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PERFCTR_H */ --- linux-2.6.8-rc1/include/linux/personality.h 2003-09-08 13:58:59.000000000 -0700 +++ 25/include/linux/personality.h 2004-07-13 17:09:38.550412320 -0700 @@ -30,6 +30,7 @@ extern int abi_fake_utsname; */ enum { MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, ADDR_LIMIT_32BIT = 0x0800000, SHORT_INODE = 0x1000000, WHOLE_SECONDS = 0x2000000, --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/linux/pktcdvd.h 2004-07-13 17:09:42.000000000 -0700 @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2000 Jens Axboe + * Copyright (C) 2001-2004 Peter Osterlund + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and + * DVD-RW devices. + * + */ +#ifndef __PKTCDVD_H +#define __PKTCDVD_H + +/* + * 1 for normal debug messages, 2 is very verbose. 0 to turn it off. + */ +#define PACKET_DEBUG 1 + +#define MAX_WRITERS 8 + +/* + * How long we should hold a non-full packet before starting data gathering. + */ +#define PACKET_WAIT_TIME (HZ * 5 / 1000) + +/* + * use drive write caching -- we need deferred error handling to be + * able to sucessfully recover with this option (drive will return good + * status as soon as the cdb is validated). + */ +#if defined(CONFIG_CDROM_PKTCDVD_WCACHE) +#warning Enabling write caching, use at your own risk +#define USE_WCACHING 1 +#else +#define USE_WCACHING 0 +#endif + +/* + * No user-servicable parts beyond this point -> + */ + +#if PACKET_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define DPRINTK(fmt, args...) +#endif + +#if PACKET_DEBUG > 1 +#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args) +#else +#define VPRINTK(fmt, args...) +#endif + +/* + * device types + */ +#define PACKET_CDR 1 +#define PACKET_CDRW 2 +#define PACKET_DVDR 3 +#define PACKET_DVDRW 4 + +/* + * flags + */ +#define PACKET_WRITABLE 1 /* pd is writable */ +#define PACKET_NWA_VALID 2 /* next writable address valid */ +#define PACKET_LRA_VALID 3 /* last recorded address valid */ +#define PACKET_MERGE_SEGS 4 /* perform segment merging to keep */ + /* underlying cdrom device happy */ + +/* + * Disc status -- from READ_DISC_INFO + */ +#define PACKET_DISC_EMPTY 0 +#define PACKET_DISC_INCOMPLETE 1 +#define PACKET_DISC_COMPLETE 2 +#define PACKET_DISC_OTHER 3 + +/* + * write type, and corresponding data block type + */ +#define PACKET_MODE1 1 +#define PACKET_MODE2 2 +#define PACKET_BLOCK_MODE1 8 +#define PACKET_BLOCK_MODE2 10 + +/* + * Last session/border status + */ +#define PACKET_SESSION_EMPTY 0 +#define PACKET_SESSION_INCOMPLETE 1 +#define PACKET_SESSION_RESERVED 2 +#define PACKET_SESSION_COMPLETE 3 + +#define PACKET_MCN "4a656e734178626f65323030300000" + +#undef PACKET_USE_LS + +/* + * Very crude stats for now + */ +struct packet_stats +{ + unsigned long pkt_started; + unsigned long pkt_ended; + unsigned long secs_w; + unsigned long secs_rg; + unsigned long secs_r; +}; + +/* + * packet ioctls + */ +#define PACKET_IOCTL_MAGIC ('X') +#define PACKET_GET_STATS _IOR(PACKET_IOCTL_MAGIC, 0, struct packet_stats) +#define PACKET_SETUP_DEV _IOW(PACKET_IOCTL_MAGIC, 1, unsigned int) +#define PACKET_TEARDOWN_DEV _IOW(PACKET_IOCTL_MAGIC, 2, unsigned int) + +#ifdef __KERNEL__ +#include +#include +#include + +struct packet_settings +{ + __u8 size; /* packet size in (512 byte) sectors */ + __u8 fp; /* fixed packets */ + __u8 link_loss; /* the rest is specified + * as per Mt Fuji */ + __u8 write_type; + __u8 track_mode; + __u8 block_mode; +}; + +struct packet_cdrw +{ + struct list_head pkt_free_list; + struct list_head pkt_active_list; + spinlock_t active_list_lock; /* Serialize access to pkt_active_list */ + struct task_struct *thread; + elevator_merge_fn *elv_merge_fn; + elevator_completed_req_fn *elv_completed_req_fn; + merge_requests_fn *merge_requests_fn; +}; + +/* + * Switch to high speed reading after reading this many kilobytes + * with no interspersed writes. + */ +#define HI_SPEED_SWITCH 512 + +struct packet_iosched +{ + atomic_t attention; /* Set to non-zero when queue processing is needed */ + int writing; /* Non-zero when writing, zero when reading */ + spinlock_t lock; /* Protecting read/write queue manipulations */ + struct bio *read_queue; + struct bio *read_queue_tail; + struct bio *write_queue; + struct bio *write_queue_tail; + int high_prio_read; /* An important read request has been queued */ + int successive_reads; +}; + +/* + * 32 buffers of 2048 bytes + */ +#define PACKET_MAX_SIZE 32 +#define PAGES_PER_PACKET (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE) +#define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9) + +enum packet_data_state { + PACKET_IDLE_STATE, /* Not used at the moment */ + PACKET_WAITING_STATE, /* Waiting for more bios to arrive, so */ + /* we don't have to do as much */ + /* data gathering */ + PACKET_READ_WAIT_STATE, /* Waiting for reads to fill in holes */ + PACKET_WRITE_WAIT_STATE, /* Waiting for the write to complete */ + PACKET_RECOVERY_STATE, /* Recover after read/write errors */ + PACKET_FINISHED_STATE, /* After write has finished */ + + PACKET_NUM_STATES /* Number of possible states */ +}; + +/* + * Information needed for writing a single packet + */ +struct pktcdvd_device; + +struct packet_data +{ + struct list_head list; + + spinlock_t lock; /* Lock protecting state transitions and */ + /* orig_bios list */ + + struct bio *orig_bios; /* Original bios passed to pkt_make_request */ + struct bio *orig_bios_tail;/* that will be handled by this packet */ + int write_size; /* Total size of all bios in the orig_bios */ + /* list, measured in number of frames */ + + struct bio *w_bio; /* The bio we will send to the real CD */ + /* device once we have all data for the */ + /* packet we are going to write */ + sector_t sector; /* First sector in this packet */ + int frames; /* Number of frames in this packet */ + + enum packet_data_state state; /* Current state */ + atomic_t run_sm; /* Incremented whenever the state */ + /* machine needs to be run */ + long sleep_time; /* Set this to non-zero to make the state */ + /* machine run after this many jiffies. */ + + atomic_t io_wait; /* Number of pending IO operations */ + atomic_t io_errors; /* Number of read/write errors during IO */ + + struct bio *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */ + struct page *pages[PAGES_PER_PACKET]; + + int cache_valid; /* If non-zero, the data for the zone defined */ + /* by the sector variable is completely cached */ + /* in the pages[] vector. */ + + int id; /* ID number for debugging */ + struct pktcdvd_device *pd; +}; + +struct pktcdvd_device +{ + struct block_device *bdev; /* dev attached */ + dev_t dev; /* dev attached */ + char name[20]; + struct packet_settings settings; + struct packet_stats stats; + struct semaphore ctl_mutex; /* Serialize access to refcnt */ + int refcnt; /* Open count */ + __u8 write_speed; /* current write speed */ + __u8 read_speed; /* current read speed */ + unsigned long offset; /* start offset */ + __u8 mode_offset; /* 0 / 8 */ + __u8 type; + unsigned long flags; + __u16 mmc3_profile; + __u32 nwa; /* next writable address */ + __u32 lra; /* last recorded address */ + struct packet_cdrw cdrw; + wait_queue_head_t wqueue; + + spinlock_t lock; /* Serialize access to bio_queue */ + struct bio *bio_queue; /* Work queue of bios we need to handle */ + struct bio *bio_queue_tail; + atomic_t scan_queue; /* Set to non-zero when pkt_handle_queue */ + /* needs to be run. */ + struct packet_iosched iosched; + struct gendisk *disk; +}; + +#endif /* __KERNEL__ */ + +#endif /* __PKTCDVD_H */ --- linux-2.6.8-rc1/include/linux/pkt_sched.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/pkt_sched.h 2004-07-13 17:09:13.650197728 -0700 @@ -100,34 +100,6 @@ struct tc_prio_qopt __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ }; -/* CSZ section */ - -struct tc_csz_qopt -{ - int flows; /* Maximal number of guaranteed flows */ - unsigned char R_log; /* Fixed point position for round number */ - unsigned char delta_log; /* Log of maximal managed time interval */ - __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> CSZ band */ -}; - -struct tc_csz_copt -{ - struct tc_ratespec slice; - struct tc_ratespec rate; - struct tc_ratespec peakrate; - __u32 limit; - __u32 buffer; - __u32 mtu; -}; - -enum -{ - TCA_CSZ_UNSPEC, - TCA_CSZ_PARMS, - TCA_CSZ_RTAB, - TCA_CSZ_PTAB, -}; - /* TBF section */ struct tc_tbf_qopt @@ -437,6 +409,6 @@ struct tc_netem_qopt __u32 loss; /* random packet loss (0=none ~0=100%) */ __u32 gap; /* re-ordering gap (0 for delay all) */ __u32 duplicate; /* random packet dup (0=none ~0=100%) */ - __u32 rate; /* maximum transmit rate (bytes/sec) */ + __u32 jitter; /* random jitter in latency (us) */ }; #endif --- linux-2.6.8-rc1/include/linux/pnp.h 2004-02-17 20:48:46.000000000 -0800 +++ 25/include/linux/pnp.h 2004-07-13 17:09:24.000000000 -0700 @@ -292,6 +292,7 @@ struct pnp_driver { unsigned int flags; int (*probe) (struct pnp_dev *dev, const struct pnp_device_id *dev_id); void (*remove) (struct pnp_dev *dev); + int (*match) (struct pnp_dev *dev); struct device_driver driver; }; --- linux-2.6.8-rc1/include/linux/reiserfs_fs.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/reiserfs_fs.h 2004-07-13 17:09:31.985410352 -0700 @@ -81,7 +81,7 @@ void reiserfs_warning (struct super_bloc /** always check a condition and panic if it's false. */ #define RASSERT( cond, format, args... ) \ if( !( cond ) ) \ - reiserfs_panic( 0, "reiserfs[%i]: assertion " #cond " failed at " \ + reiserfs_panic( NULL, "reiserfs[%i]: assertion " #cond " failed at " \ __FILE__ ":%i:%s: " format "\n", \ in_interrupt() ? -1 : current -> pid, __LINE__ , __FUNCTION__ , ##args ) @@ -1777,7 +1777,8 @@ int reiserfs_end_persistent_transaction( int reiserfs_commit_page(struct inode *inode, struct page *page, unsigned from, unsigned to); int reiserfs_flush_old_commits(struct super_block *); -void reiserfs_commit_for_inode(struct inode *) ; +int reiserfs_commit_for_inode(struct inode *) ; +int reiserfs_inode_needs_commit(struct inode *) ; void reiserfs_update_inode_transaction(struct inode *) ; void reiserfs_wait_on_write_block(struct super_block *s) ; void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ; --- linux-2.6.8-rc1/include/linux/reiserfs_fs_sb.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/reiserfs_fs_sb.h 2004-07-13 17:09:31.986410200 -0700 @@ -444,6 +444,8 @@ enum reiserfs_mount_options { REISERFS_XATTRS, REISERFS_XATTRS_USER, REISERFS_POSIXACL, + REISERFS_BARRIER_NONE, + REISERFS_BARRIER_FLUSH, REISERFS_TEST1, REISERFS_TEST2, @@ -473,6 +475,8 @@ enum reiserfs_mount_options { #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) +#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE)) +#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH)) void reiserfs_file_buffer (struct buffer_head * bh, int list); extern struct file_system_type reiserfs_fs_type; --- linux-2.6.8-rc1/include/linux/sc26198.h 2003-06-14 12:18:09.000000000 -0700 +++ 25/include/linux/sc26198.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * sc26198.h -- SC26198 UART hardware info. * - * Copyright (C) 1995-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1995-1998 Stallion Technologies * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by --- linux-2.6.8-rc1/include/linux/sched.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/sched.h 2004-07-13 17:09:38.551412168 -0700 @@ -189,10 +189,26 @@ extern int sysctl_max_map_count; #include +extern unsigned long +arch_get_unmapped_area(struct file *, unsigned long, unsigned long, + unsigned long, unsigned long); +extern unsigned long +arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags); +extern void arch_unmap_area(struct vm_area_struct *area); +extern void arch_unmap_area_topdown(struct vm_area_struct *area); + + struct mm_struct { struct vm_area_struct * mmap; /* list of VMAs */ struct rb_root mm_rb; struct vm_area_struct * mmap_cache; /* last find_vma result */ + unsigned long (*get_unmapped_area) (struct file *filp, + unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags); + void (*unmap_area) (struct vm_area_struct *area); + unsigned long mmap_base; /* base of mmap area */ unsigned long free_area_cache; /* first hole */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ @@ -300,7 +316,7 @@ struct signal_struct { #define MAX_PRIO (MAX_RT_PRIO + 40) -#define rt_task(p) ((p)->prio < MAX_RT_PRIO) +#define rt_task(p) (unlikely((p)->prio < MAX_RT_PRIO)) /* * Some day this will be a full-fledged user tracking system.. @@ -561,11 +577,10 @@ do { if (atomic_dec_and_test(&(tsk)->usa #define SD_BALANCE_NEWIDLE 1 /* Balance when about to become idle */ #define SD_BALANCE_EXEC 2 /* Balance on exec */ -#define SD_BALANCE_CLONE 4 /* Balance on clone */ -#define SD_WAKE_IDLE 8 /* Wake to idle CPU on task wakeup */ -#define SD_WAKE_AFFINE 16 /* Wake task to waking CPU */ -#define SD_WAKE_BALANCE 32 /* Perform balancing at task wakeup */ -#define SD_SHARE_CPUPOWER 64 /* Domain members share cpu power */ +#define SD_WAKE_IDLE 4 /* Wake to idle CPU on task wakeup */ +#define SD_WAKE_AFFINE 8 /* Wake task to waking CPU */ +#define SD_WAKE_BALANCE 16 /* Perform balancing at task wakeup */ +#define SD_SHARE_CPUPOWER 32 /* Domain members share cpu power */ struct sched_group { struct sched_group *next; /* Must be a circular list */ @@ -614,7 +629,6 @@ struct sched_domain { .per_cpu_gain = 15, \ .flags = SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ - | SD_BALANCE_CLONE \ | SD_WAKE_AFFINE \ | SD_WAKE_IDLE \ | SD_SHARE_CPUPOWER, \ @@ -637,7 +651,6 @@ struct sched_domain { .per_cpu_gain = 100, \ .flags = SD_BALANCE_NEWIDLE \ | SD_BALANCE_EXEC \ - | SD_BALANCE_CLONE \ | SD_WAKE_AFFINE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ @@ -659,7 +672,6 @@ struct sched_domain { .cache_nice_tries = 1, \ .per_cpu_gain = 100, \ .flags = SD_BALANCE_EXEC \ - | SD_BALANCE_CLONE \ | SD_WAKE_BALANCE, \ .last_balance = jiffies, \ .balance_interval = 1, \ @@ -679,10 +691,11 @@ static inline int set_cpus_allowed(task_ extern unsigned long long sched_clock(void); +/* sched_exec is called by processes performing an exec */ #ifdef CONFIG_SMP -extern void sched_balance_exec(void); +extern void sched_exec(void); #else -#define sched_balance_exec() {} +#define sched_exec() {} #endif extern void sched_idle_next(void); @@ -741,16 +754,12 @@ extern void do_timer(struct pt_regs *); extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); extern int FASTCALL(wake_up_process(struct task_struct * tsk)); -extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk)); +extern void FASTCALL(wake_up_new_task(struct task_struct * tsk, + unsigned long clone_flags)); #ifdef CONFIG_SMP extern void kick_process(struct task_struct *tsk); - extern void FASTCALL(wake_up_forked_thread(struct task_struct * tsk)); #else static inline void kick_process(struct task_struct *tsk) { } - static inline void wake_up_forked_thread(struct task_struct * tsk) - { - wake_up_forked_process(tsk); - } #endif extern void FASTCALL(sched_fork(task_t * p)); extern void FASTCALL(sched_exit(task_t * p)); @@ -936,6 +945,9 @@ extern void unhash_process(struct task_s * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info and synchronises with * wait4(). * + * Synchronises set_cpus_allowed(), unlink, and creat of ->thread.perfctr. + * [if CONFIG_PERFCTR_VIRTUAL] + * * Nests both inside and outside of read_lock(&tasklist_lock). * It must not be nested with write_lock_irq(&tasklist_lock), * neither inside nor outside. @@ -1080,6 +1092,17 @@ static inline void set_task_cpu(struct t #endif /* CONFIG_SMP */ +#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT +extern void arch_pick_mmap_layout(struct mm_struct *mm); +#else +static inline void arch_pick_mmap_layout(struct mm_struct *mm) +{ + mm->mmap_base = TASK_UNMAPPED_BASE; + mm->get_unmapped_area = arch_get_unmapped_area; + mm->unmap_area = arch_unmap_area; +} +#endif + #endif /* __KERNEL__ */ #endif --- linux-2.6.8-rc1/include/linux/serial_core.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/serial_core.h 2004-07-13 17:09:25.000000000 -0700 @@ -86,6 +86,9 @@ /* PPC CPM type number */ #define PORT_CPM 58 +/* MPC52xx type numbers */ +#define PORT_MPC52xx 59 + #ifdef __KERNEL__ #include @@ -169,7 +172,9 @@ struct uart_port { unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ unsigned char iotype; /* io access style */ - +#ifdef CONFIG_KGDB + int kgdb; /* in use by kgdb */ +#endif #define UPIO_PORT (0) #define UPIO_HUB6 (1) #define UPIO_MEM (2) --- linux-2.6.8-rc1/include/linux/serio.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/serio.h 2004-07-13 17:09:22.106912112 -0700 @@ -17,12 +17,15 @@ #ifdef __KERNEL__ #include +#include +#include struct serio { void *private; - void *driver; - char *name; - char *phys; + void *port_data; + + char name[32]; + char phys[32]; unsigned short idbus; unsigned short idvendor; @@ -32,31 +35,43 @@ struct serio { unsigned long type; unsigned long event; + spinlock_t lock; + int (*write)(struct serio *, unsigned char); int (*open)(struct serio *); void (*close)(struct serio *); - struct serio_dev *dev; + struct serio *parent, *child; + + struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */ + + struct device dev; struct list_head node; }; +#define to_serio_port(d) container_of(d, struct serio, dev) -struct serio_dev { +struct serio_driver { void *private; - char *name; + char *description; + + int manual_bind; void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int, struct pt_regs *); - void (*connect)(struct serio *, struct serio_dev *dev); + void (*connect)(struct serio *, struct serio_driver *drv); int (*reconnect)(struct serio *); void (*disconnect)(struct serio *); void (*cleanup)(struct serio *); + struct device_driver driver; + struct list_head node; }; +#define to_serio_driver(d) container_of(d, struct serio_driver, driver) -int serio_open(struct serio *serio, struct serio_dev *dev); +int serio_open(struct serio *serio, struct serio_driver *drv); void serio_close(struct serio *serio); void serio_rescan(struct serio *serio); void serio_reconnect(struct serio *serio); @@ -64,12 +79,10 @@ irqreturn_t serio_interrupt(struct serio void serio_register_port(struct serio *serio); void serio_register_port_delayed(struct serio *serio); -void __serio_register_port(struct serio *serio); void serio_unregister_port(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio); -void __serio_unregister_port(struct serio *serio); -void serio_register_device(struct serio_dev *dev); -void serio_unregister_device(struct serio_dev *dev); +void serio_register_driver(struct serio_driver *drv); +void serio_unregister_driver(struct serio_driver *drv); static __inline__ int serio_write(struct serio *serio, unsigned char data) { @@ -79,16 +92,16 @@ static __inline__ int serio_write(struct return -1; } -static __inline__ void serio_dev_write_wakeup(struct serio *serio) +static __inline__ void serio_drv_write_wakeup(struct serio *serio) { - if (serio->dev && serio->dev->write_wakeup) - serio->dev->write_wakeup(serio); + if (serio->drv && serio->drv->write_wakeup) + serio->drv->write_wakeup(serio); } static __inline__ void serio_cleanup(struct serio *serio) { - if (serio->dev && serio->dev->cleanup) - serio->dev->cleanup(serio); + if (serio->drv && serio->drv->cleanup) + serio->drv->cleanup(serio); } #endif --- linux-2.6.8-rc1/include/linux/slab.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/slab.h 2004-07-13 17:09:19.181356864 -0700 @@ -97,6 +97,7 @@ found: return __kmalloc(size, flags); } +extern void *kcalloc(size_t, size_t, int); extern void kfree(const void *); extern unsigned int ksize(const void *); --- linux-2.6.8-rc1/include/linux/spinlock.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/spinlock.h 2004-07-13 17:09:29.274822424 -0700 @@ -15,6 +15,12 @@ #include /* for cpu relax */ #include +#ifdef CONFIG_KGDB +#include +#define SET_WHO(x, him) (x)->who = him; +#else +#define SET_WHO(x, him) +#endif /* * Must define these before including other files, inline functions need them @@ -57,6 +63,9 @@ typedef struct { const char *module; char *owner; int oline; +#ifdef CONFIG_KGDB + struct task_struct *who; +#endif } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0} @@ -68,6 +77,7 @@ typedef struct { (x)->module = __FILE__; \ (x)->owner = NULL; \ (x)->oline = 0; \ + SET_WHO(x, NULL) \ } while (0) #define CHECK_LOCK(x) \ @@ -90,6 +100,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ } while (0) /* without debugging, spin_is_locked on UP always says @@ -120,6 +131,7 @@ typedef struct { (x)->lock = 1; \ (x)->owner = __FILE__; \ (x)->oline = __LINE__; \ + SET_WHO(x, current) \ 1; \ }) @@ -186,6 +198,17 @@ typedef struct { #endif /* !SMP */ +#ifdef CONFIG_LOCKMETER +extern void _metered_spin_lock (spinlock_t *lock); +extern void _metered_spin_unlock (spinlock_t *lock); +extern int _metered_spin_trylock(spinlock_t *lock); +extern void _metered_read_lock (rwlock_t *lock); +extern void _metered_read_unlock (rwlock_t *lock); +extern void _metered_write_lock (rwlock_t *lock); +extern void _metered_write_unlock (rwlock_t *lock); +extern int _metered_write_trylock(rwlock_t *lock); +#endif + /* * Define the various spin_lock and rw_lock methods. Note we define these * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various @@ -391,6 +414,141 @@ do { \ _raw_spin_trylock(lock) ? 1 : \ ({preempt_enable(); local_bh_enable(); 0;});}) +#ifdef CONFIG_LOCKMETER +#undef spin_lock +#undef spin_trylock +#undef spin_unlock +#undef spin_lock_irqsave +#undef spin_lock_irq +#undef spin_lock_bh +#undef read_lock +#undef read_unlock +#undef write_lock +#undef write_unlock +#undef write_trylock +#undef spin_unlock_bh +#undef read_lock_irqsave +#undef read_lock_irq +#undef read_lock_bh +#undef read_unlock_bh +#undef write_lock_irqsave +#undef write_lock_irq +#undef write_lock_bh +#undef write_unlock_bh + +#define spin_lock(lock) \ +do { \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while(0) + +#define spin_trylock(lock) ({preempt_disable(); _metered_spin_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ +} while (0) + +#define spin_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_spin_lock(lock); \ +} while (0) + +#define spin_unlock_bh(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + + +#define read_lock(lock) ({preempt_disable(); _metered_read_lock(lock);}) +#define read_unlock(lock) ({_metered_read_unlock(lock); preempt_enable();}) +#define write_lock(lock) ({preempt_disable(); _metered_write_lock(lock);}) +#define write_unlock(lock) ({_metered_write_unlock(lock); preempt_enable();}) +#define write_trylock(lock) ({preempt_disable();_metered_write_trylock(lock) ? \ + 1 : ({preempt_enable(); 0;});}) +#define spin_unlock_no_resched(lock) \ +do { \ + _metered_spin_unlock(lock); \ + preempt_enable_no_resched(); \ +} while (0) + +#define read_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_read_lock(lock); \ +} while (0) + +#define read_unlock_bh(lock) \ +do { \ + _metered_read_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#define write_lock_irqsave(lock, flags) \ +do { \ + local_irq_save(flags); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_irq(lock) \ +do { \ + local_irq_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_lock_bh(lock) \ +do { \ + local_bh_disable(); \ + preempt_disable(); \ + _metered_write_lock(lock); \ +} while (0) + +#define write_unlock_bh(lock) \ +do { \ + _metered_write_unlock(lock); \ + preempt_enable(); \ + local_bh_enable(); \ +} while (0) + +#endif /* !CONFIG_LOCKMETER */ + /* "lock on reference count zero" */ #ifndef ATOMIC_DEC_AND_LOCK #include --- linux-2.6.8-rc1/include/linux/stallion.h 2004-03-10 20:41:31.000000000 -0800 +++ 25/include/linux/stallion.h 2004-07-13 17:35:11.000000000 -0700 @@ -3,7 +3,7 @@ /* * stallion.h -- stallion multiport serial driver. * - * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 Stallion Technologies * Copyright (C) 1994-1996 Greg Ungerer. * * This program is free software; you can redistribute it and/or modify --- linux-2.6.8-rc1/include/linux/sysfs.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/sysfs.h 2004-07-13 17:09:16.537758752 -0700 @@ -9,6 +9,8 @@ #ifndef _SYSFS_H_ #define _SYSFS_H_ +#include + struct kobject; struct module; @@ -68,6 +70,24 @@ sysfs_remove_dir(struct kobject *); extern int sysfs_rename_dir(struct kobject *, const char *new_name); +struct sysfs_dirent { + atomic_t s_count; + struct list_head s_sibling; + struct list_head s_children; + void * s_element; + int s_type; + umode_t s_mode; + struct dentry * s_dentry; +}; + +#define SYSFS_ROOT 0x0001 +#define SYSFS_KOBJECT 0x0002 +#define SYSFS_KOBJ_ATTR 0x0004 +#define SYSFS_KOBJ_BIN_ATTR 0x0008 +#define SYSFS_KOBJ_ATTR_GROUP 0x0010 +#define SYSFS_KOBJ_LINK 0x0020 +#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK) + extern int sysfs_create_file(struct kobject *, const struct attribute *); --- linux-2.6.8-rc1/include/linux/time.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/time.h 2004-07-13 17:09:45.096417176 -0700 @@ -41,7 +41,7 @@ struct timezone { * Have the 32 bit jiffies value wrap 5 minutes after boot * so jiffies wrap bugs show up earlier. */ -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +#define INITIAL_JIFFIES ((unsigned long)(0)) /* * Change timeval to jiffies, trying to avoid the --- linux-2.6.8-rc1/include/linux/ufs_fs.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/ufs_fs.h 2004-07-13 17:09:55.000000000 -0700 @@ -909,7 +909,6 @@ extern struct buffer_head * ufs_bread (s extern struct file_operations ufs_dir_operations; /* super.c */ -extern struct file_system_type ufs_fs_type; extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); --- linux-2.6.8-rc1/include/linux/uio.h 2003-06-14 12:18:25.000000000 -0700 +++ 25/include/linux/uio.h 2004-07-13 17:09:13.653197272 -0700 @@ -23,6 +23,15 @@ struct iovec __kernel_size_t iov_len; /* Must be size_t (1003.1g) */ }; +#ifdef __KERNEL__ + +struct kvec { + void *iov_base; /* and that should *never* hold a userland pointer */ + size_t iov_len; +}; + +#endif + /* * UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1) */ --- linux-2.6.8-rc1/include/linux/usbdevice_fs.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/usbdevice_fs.h 2004-07-13 17:09:13.000000000 -0700 @@ -63,7 +63,7 @@ struct usbdevfs_setinterface { struct usbdevfs_disconnectsignal { unsigned int signr; - void *context; + void __user *context; }; #define USBDEVFS_MAXDRIVERNAME 255 @@ -162,7 +162,7 @@ struct dev_state { wait_queue_head_t wait; /* wake up if a request completed */ unsigned int discsignr; struct task_struct *disctask; - void *disccontext; + void __user *disccontext; unsigned long ifclaimed; }; --- linux-2.6.8-rc1/include/linux/usb_gadget.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/usb_gadget.h 2004-07-13 17:09:24.000000000 -0700 @@ -6,7 +6,7 @@ * master many USB gadgets, but the gadgets are only slaved to one host. * * - * (c) Copyright 2002-2003 by David Brownell + * (C) Copyright 2002-2004 by David Brownell * All Rights Reserved. * * This software is licensed under the GNU GPL version 2. @@ -73,8 +73,6 @@ struct usb_ep; */ // NOTE this is analagous to 'struct urb' on the host side, // except that it's thinner and promotes more pre-allocation. - // - // ISSUE should this be allocated through the device? struct usb_request { void *buf; @@ -116,8 +114,8 @@ struct usb_ep_ops { dma_addr_t *dma, int gfp_flags); void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned bytes); - // NOTE: on 2.5, drivers may also use dma_map() and - // dma_sync_single_*() to manage dma overhead. + // NOTE: on 2.6, drivers may also use dma_map() and + // dma_sync_single_*() to directly manage dma overhead. int (*queue) (struct usb_ep *ep, struct usb_request *req, int gfp_flags); @@ -453,7 +451,10 @@ struct usb_gadget; struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); - int (*set_selfpowered) (struct usb_gadget *, int value); + int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); + int (*vbus_session) (struct usb_gadget *, int is_active); + int (*vbus_draw) (struct usb_gadget *, unsigned mA); + int (*pullup) (struct usb_gadget *, int is_on); int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param); }; @@ -467,6 +468,17 @@ struct usb_gadget_ops { * @speed: Speed of current connection to USB host. * @is_dualspeed: True if the controller supports both high and full speed * operation. If it does, the gadget driver must also support both. + * @is_otg: True if the USB device port uses a Mini-AB jack, so that the + * gadget driver must provide a USB OTG descriptor. + * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable + * is in the Mini-AB jack, and HNP has been used to switch roles + * so that the "A" device currently acts as A-Peripheral, not A-Host. + * @a_hnp_support: OTG device feature flag, indicating that the A-Host + * supports HNP at this port. + * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host + * only supports HNP on a different root port. + * @b_hnp_enable: OTG device feature flag, indicating that the A-Host + * enabled HNP support. * @name: Identifies the controller hardware type. Used in diagnostics * and sometimes configuration. * @dev: Driver model state for this abstract device. @@ -480,9 +492,14 @@ struct usb_gadget_ops { * * Except for the driver data, all fields in this structure are * read-only to the gadget driver. That driver data is part of the - * "driver model" infrastructure in 2.5 (and later) kernels, and for + * "driver model" infrastructure in 2.6 (and later) kernels, and for * earlier systems is grouped in a similar structure that's not known * to the rest of the kernel. + * + * Values of the three OTG device feature flags are updated before the + * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before + * driver suspend() calls. They are valid only when is_otg, and when the + * device is acting as a B-Peripheral (so is_a_peripheral is false). */ struct usb_gadget { /* readonly to gadget driver */ @@ -491,6 +508,11 @@ struct usb_gadget { struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; unsigned is_dualspeed:1; + unsigned is_otg:1; + unsigned is_a_peripheral:1; + unsigned b_hnp_enable:1; + unsigned a_hnp_support:1; + unsigned a_alt_hnp_support:1; const char *name; struct device dev; }; @@ -525,6 +547,10 @@ static inline int usb_gadget_frame_numbe * doesn't support such attempts, or its support has not been enabled * by the usb host. Drivers must return device descriptors that report * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. */ static inline int usb_gadget_wakeup (struct usb_gadget *gadget) { @@ -568,6 +594,107 @@ usb_gadget_clear_selfpowered (struct usb return gadget->ops->set_selfpowered (gadget, 0); } +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 1); +} + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw (gadget, mA); +} + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 0); +} + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_connect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 1); +} + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_connect() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_disconnect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 0); +} + + /*-------------------------------------------------------------------------*/ @@ -601,6 +728,12 @@ usb_gadget_clear_selfpowered (struct usb * means the driver will handle setup() requests needed to enumerate (and * meet "chapter 9" requirements) then do some useful work. * + * If gadget->is_otg is true, the gadget driver must provide an OTG + * descriptor during enumeration, or else fail the bind() call. In such + * cases, no USB traffic may flow until both bind() returns without + * having called usb_gadget_disconnect(), and the USB host stack has + * initialized. + * * Drivers use hardware-specific knowledge to configure the usb hardware. * endpoint addressing is only one of several hardware characteristics that * are in descriptors the ep0 implementation returns from setup() calls. @@ -634,6 +767,12 @@ usb_gadget_clear_selfpowered (struct usb * the (remote) host can't do that any longer; or an error state might * be cleared, to make the device behave identically whether or not * power is maintained. + * + * If the OTG b_hnp_enabled flag is set during a suspend() call, the + * device may use HNP to switch from "B-Peripheral" to "B-Host" mode + * (or back from "A-Peripheral" mode to the original "A-Host") if + * the gadget driver calls usb_gadget_disconnect() before the device + * is resumed. */ struct usb_gadget_driver { char *function; --- linux-2.6.8-rc1/include/linux/usb.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/linux/usb.h 2004-07-13 17:09:24.000000000 -0700 @@ -61,6 +61,13 @@ struct usb_host_interface { int extralen; }; +enum usb_interface_condition { + USB_INTERFACE_UNBOUND = 0, + USB_INTERFACE_BINDING, + USB_INTERFACE_BOUND, + USB_INTERFACE_UNBINDING, +}; + /** * struct usb_interface - what usb device drivers talk to * @altsetting: array of interface structures, one for each alternate @@ -75,6 +82,8 @@ struct usb_host_interface { * be unused. The driver should set this value in the probe() * function of the driver, after it has been assigned a minor * number from the USB core by calling usb_register_dev(). + * @condition: binding state of the interface: not bound, binding + * (in probe()), bound to a driver, or unbinding (in disconnect()) * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. * @@ -113,6 +122,7 @@ struct usb_interface { unsigned num_altsetting; /* number of alternate settings */ int minor; /* minor number this interface is bound to */ + enum usb_interface_condition condition; /* state of binding */ struct device dev; /* interface specific device info */ struct class_device *class_dev; }; @@ -279,6 +289,17 @@ struct usb_bus { struct usb_tt; +/** + * struct usb_device - kernel's representation of a USB device + * + * FIXME: Write the kerneldoc! + * + * WARNING: Drivers should not attempt to manipulate usbdev->serialize + * directly. Instead use usb_lock_device() and usb_unlock_device(). + * + * Usbcore drivers should not set usbdev->state directly. Instead use + * usb_set_device_state(). + */ struct usb_device { int devnum; /* Address on USB bus */ char devpath [16]; /* Use in messages: /port/port/... */ @@ -291,8 +312,6 @@ struct usb_device { struct semaphore serialize; unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ - unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ - /* [0] = IN, [1] = OUT */ int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ @@ -332,9 +351,15 @@ struct usb_device { extern struct usb_device *usb_get_dev(struct usb_device *dev); extern void usb_put_dev(struct usb_device *dev); -/* mostly for devices emulating SCSI over USB */ +/* for device locking -- don't manipulate usbdev->serialize directly! */ +extern void usb_lock_device(struct usb_device *udev); +extern int usb_trylock_device(struct usb_device *udev); +extern int usb_lock_device_for_reset(struct usb_device *udev, + struct usb_interface *iface); +extern void usb_unlock_device(struct usb_device *udev); + +/* USB port reset for device reinitialization */ extern int usb_reset_device(struct usb_device *dev); -extern int __usb_reset_device(struct usb_device *dev); extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); @@ -355,7 +380,7 @@ extern int usb_driver_claim_interface(st * may need to explicitly claim that lock. * */ -static int inline usb_interface_claimed(struct usb_interface *iface) { +static inline int usb_interface_claimed(struct usb_interface *iface) { return (iface->dev.driver != NULL); } @@ -657,7 +682,7 @@ typedef void (*usb_complete_t)(struct ur * calling usb_alloc_urb() and freed with a call to usb_free_urb(). * Initialization may be done using various usb_fill_*_urb() functions. URBs * are submitted using usb_submit_urb(), and pending requests may be canceled - * using usb_unlink_urb(). + * using usb_unlink_urb() or usb_kill_urb(). * * Data Transfer Buffers: * @@ -684,7 +709,9 @@ typedef void (*usb_complete_t)(struct ur * All URBs submitted must initialize dev, pipe, * transfer_flags (may be zero), complete, timeout (may be zero). * The URB_ASYNC_UNLINK transfer flag affects later invocations of - * the usb_unlink_urb() routine. + * the usb_unlink_urb() routine. Note: Failure to set URB_ASYNC_UNLINK + * with usb_unlink_urb() is deprecated. For synchronous unlinks use + * usb_kill_urb() instead. * * All URBs must also initialize * transfer_buffer and transfer_buffer_length. They may provide the @@ -762,6 +789,8 @@ struct urb void *hcpriv; /* private data for host controller */ struct list_head urb_list; /* list pointer to all active urbs */ int bandwidth; /* bandwidth for INT/ISO request */ + atomic_t use_count; /* concurrent submissions counter */ + u8 reject; /* submissions will fail */ /* public, documented fields in the urb that can be used by drivers */ struct usb_device *dev; /* (in) pointer to associated device */ @@ -897,6 +926,7 @@ extern void usb_free_urb(struct urb *urb extern struct urb *usb_get_urb(struct urb *urb); extern int usb_submit_urb(struct urb *urb, int mem_flags); extern int usb_unlink_urb(struct urb *urb); +extern void usb_kill_urb(struct urb *urb); #define HAVE_USB_BUFFERS void *usb_buffer_alloc (struct usb_device *dev, size_t size, @@ -1071,10 +1101,6 @@ void usb_sg_wait (struct usb_sg_request #define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) #define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep))) -/* Endpoint halt control/status ... likewise USE WITH CAUTION */ -#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep))) -#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep))) - static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) { --- linux-2.6.8-rc1/include/linux/videodev2.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/videodev2.h 2004-07-13 17:09:13.000000000 -0700 @@ -433,9 +433,9 @@ struct v4l2_window struct v4l2_rect w; enum v4l2_field field; __u32 chromakey; - struct v4l2_clip *clips; + struct v4l2_clip __user *clips; __u32 clipcount; - void *bitmap; + void __user *bitmap; }; --- linux-2.6.8-rc1/include/linux/videodev.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/videodev.h 2004-07-13 17:09:24.000000000 -0700 @@ -222,7 +222,7 @@ struct video_window __u32 width,height; /* Its size */ __u32 chromakey; __u32 flags; - struct video_clip *clips; /* Set only */ + struct video_clip __user *clips; /* Set only */ int clipcount; #define VIDEO_WINDOW_INTERLACE 1 #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ @@ -429,8 +429,9 @@ struct video_code #define VID_HARDWARE_CPIA2 33 #define VID_HARDWARE_VICAM 34 #define VID_HARDWARE_SF16FMR2 35 -#define VID_HARDWARE_W9968CF 36 +#define VID_HARDWARE_W9968CF 36 #define VID_HARDWARE_SAA7114H 37 +#define VID_HARDWARE_SN9C102 38 #endif /* __LINUX_VIDEODEV_H */ /* --- linux-2.6.8-rc1/include/linux/videotext.h 2003-06-14 12:18:47.000000000 -0700 +++ 25/include/linux/videotext.h 2004-07-13 17:09:13.000000000 -0700 @@ -71,7 +71,7 @@ typedef struct int pgbuf; /* buffer where page will be stored */ int start; /* start of requested part of page */ int end; /* end of requested part of page */ - void *buffer; /* pointer to beginning of destination buffer */ + void __user *buffer; /* pointer to beginning of destination buffer */ } vtx_pagereq_t; --- linux-2.6.8-rc1/include/linux/writeback.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/linux/writeback.h 2004-07-13 17:09:51.000000000 -0700 @@ -64,6 +64,7 @@ void sync_inodes(int wait); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) { + might_sleep(); if (inode->i_state & I_LOCK) __wait_on_inode(inode); } --- linux-2.6.8-rc1/include/linux/xfrm.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/linux/xfrm.h 2004-07-13 17:09:13.000000000 -0700 @@ -135,6 +135,11 @@ enum { XFRM_MSG_POLEXPIRE, #define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE + XFRM_MSG_FLUSHSA, +#define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA + XFRM_MSG_FLUSHPOLICY, +#define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY + XFRM_MSG_MAX }; @@ -242,6 +247,10 @@ struct xfrm_user_polexpire { __u8 hard; }; +struct xfrm_usersa_flush { + __u8 proto; +}; + #define XFRMGRP_ACQUIRE 1 #define XFRMGRP_EXPIRE 2 --- linux-2.6.8-rc1/include/media/saa7146_vv.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/media/saa7146_vv.h 2004-07-13 17:09:13.000000000 -0700 @@ -184,7 +184,7 @@ struct saa7146_use_ops { int(*open)(struct saa7146_dev *, struct file *); void (*release)(struct saa7146_dev *, struct file *); void (*irq_done)(struct saa7146_dev *, unsigned long status); - ssize_t (*read)(struct file *, char *, size_t, loff_t *); + ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); }; /* from saa7146_fops.c */ --- linux-2.6.8-rc1/include/media/video-buf.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/media/video-buf.h 2004-07-13 17:09:13.000000000 -0700 @@ -226,10 +226,10 @@ int videobuf_streamoff(struct file *file int videobuf_read_start(struct file *file, struct videobuf_queue *q); void videobuf_read_stop(struct file *file, struct videobuf_queue *q); ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, - char *data, size_t count, loff_t *ppos, + char __user *data, size_t count, loff_t *ppos, int vbihack); ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, - char *data, size_t count, loff_t *ppos); + char __user *data, size_t count, loff_t *ppos); unsigned int videobuf_poll_stream(struct file *file, struct videobuf_queue *q, poll_table *wait); --- linux-2.6.8-rc1/include/net/bluetooth/l2cap.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/net/bluetooth/l2cap.h 2004-07-13 17:09:13.000000000 -0700 @@ -176,6 +176,14 @@ struct l2cap_info_rsp { __u8 data[0]; } __attribute__ ((packed)); +/* info type */ +#define L2CAP_IT_CL_MTU 0x0001 +#define L2CAP_IT_FEAT_MASK 0x0002 + +/* info result */ +#define L2CAP_IR_SUCCESS 0x0000 +#define L2CAP_IR_NOTSUPP 0x0001 + /* ----- L2CAP connections ----- */ struct l2cap_chan_list { struct sock *head; --- linux-2.6.8-rc1/include/net/dst.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/net/dst.h 2004-07-13 17:09:13.657196664 -0700 @@ -149,7 +149,9 @@ void dst_release(struct dst_entry * dst) { if (dst) { if (atomic_read(&dst->__refcnt) < 1) - printk(dst_underflow_bug_msg, dst, current_text_addr()); + printk(dst_underflow_bug_msg, + atomic_read(&dst->__refcnt), + dst, current_text_addr()); atomic_dec(&dst->__refcnt); } } --- linux-2.6.8-rc1/include/net/irda/irttp.h 2003-06-14 12:18:04.000000000 -0700 +++ 25/include/net/irda/irttp.h 2004-07-13 17:09:54.000000000 -0700 @@ -210,6 +210,4 @@ static inline int irttp_is_primary(struc return(irlap_is_primary(self->lsap->lap->irlap)); } -extern struct irttp_cb *irttp; - #endif /* IRTTP_H */ --- linux-2.6.8-rc1/include/net/netrom.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/net/netrom.h 2004-07-13 17:09:54.000000000 -0700 @@ -112,9 +112,6 @@ struct nr_node { * nr_node & nr_neigh lists, refcounting and locking *********************************************************************/ -extern struct hlist_head nr_node_list; -extern struct hlist_head nr_neigh_list; - #define nr_node_hold(__nr_node) \ atomic_inc(&((__nr_node)->refcount)) --- linux-2.6.8-rc1/include/net/pkt_act.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/net/pkt_act.h 2004-07-13 17:09:13.000000000 -0700 @@ -252,7 +252,7 @@ tcf_hash_create(struct tc_st *parm, stru } spin_lock_init(&p->lock); - p->stats.lock = &p->lock; + p->stats_lock = &p->lock; p->index = parm->index ? : tcf_hash_new_index(); p->tm.install = jiffies; p->tm.lastuse = jiffies; --- linux-2.6.8-rc1/include/net/sock.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/net/sock.h 2004-07-13 17:09:13.659196360 -0700 @@ -917,25 +917,8 @@ static inline void sock_graft(struct soc write_unlock_bh(&sk->sk_callback_lock); } -static inline int sock_i_uid(struct sock *sk) -{ - int uid; - - read_lock(&sk->sk_callback_lock); - uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0; - read_unlock(&sk->sk_callback_lock); - return uid; -} - -static inline unsigned long sock_i_ino(struct sock *sk) -{ - unsigned long ino; - - read_lock(&sk->sk_callback_lock); - ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; - read_unlock(&sk->sk_callback_lock); - return ino; -} +extern int sock_i_uid(struct sock *sk); +extern unsigned long sock_i_ino(struct sock *sk); static inline struct dst_entry * __sk_dst_get(struct sock *sk) @@ -1219,7 +1202,7 @@ static inline struct page *sk_stream_all /* * Default write policy as shown to user space via poll/select/SIGIO */ -static inline int sock_writeable(struct sock *sk) +static inline int sock_writeable(const struct sock *sk) { return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf / 2); } @@ -1229,17 +1212,17 @@ static inline int gfp_any(void) return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; } -static inline long sock_rcvtimeo(struct sock *sk, int noblock) +static inline long sock_rcvtimeo(const struct sock *sk, int noblock) { return noblock ? 0 : sk->sk_rcvtimeo; } -static inline long sock_sndtimeo(struct sock *sk, int noblock) +static inline long sock_sndtimeo(const struct sock *sk, int noblock) { return noblock ? 0 : sk->sk_sndtimeo; } -static inline int sock_rcvlowat(struct sock *sk, int waitall, int len) +static inline int sock_rcvlowat(const struct sock *sk, int waitall, int len) { return (waitall ? len : min_t(int, sk->sk_rcvlowat, len)) ? : 1; } --- linux-2.6.8-rc1/include/net/tcp.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/net/tcp.h 2004-07-13 17:09:13.000000000 -0700 @@ -272,20 +272,20 @@ static __inline__ int tw_del_dead_node(s #define tcptw_sk(__sk) ((struct tcp_tw_bucket *)(__sk)) -static inline const u32 tcp_v4_rcv_saddr(const struct sock *sk) +static inline u32 tcp_v4_rcv_saddr(const struct sock *sk) { return likely(sk->sk_state != TCP_TIME_WAIT) ? inet_sk(sk)->rcv_saddr : tcptw_sk(sk)->tw_rcv_saddr; } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static inline const struct in6_addr *__tcp_v6_rcv_saddr(const struct sock *sk) +static inline struct in6_addr *__tcp_v6_rcv_saddr(const struct sock *sk) { return likely(sk->sk_state != TCP_TIME_WAIT) ? &inet6_sk(sk)->rcv_saddr : &tcptw_sk(sk)->tw_v6_rcv_saddr; } -static inline const struct in6_addr *tcp_v6_rcv_saddr(const struct sock *sk) +static inline struct in6_addr *tcp_v6_rcv_saddr(const struct sock *sk) { return sk->sk_family == AF_INET6 ? __tcp_v6_rcv_saddr(sk) : NULL; } --- linux-2.6.8-rc1/include/net/xfrm.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/include/net/xfrm.h 2004-07-13 17:09:13.661196056 -0700 @@ -818,6 +818,7 @@ extern void xfrm_replay_advance(struct x extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl); extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm4_rcv(struct sk_buff *skb); +extern int xfrm4_output(struct sk_buff **pskb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_check_size(struct sk_buff *skb); --- linux-2.6.8-rc1/include/pcmcia/cs.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/include/pcmcia/cs.h 2004-07-13 17:09:39.000000000 -0700 @@ -318,6 +318,7 @@ typedef struct error_info_t { /* Special stuff for binding drivers to sockets */ typedef struct bind_req_t { struct pcmcia_socket *Socket; + struct pcmcia_device *device; u_char Function; dev_info_t *dev_info; } bind_req_t; @@ -452,6 +453,7 @@ int pcmcia_insert_card(struct pcmcia_soc int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask); int pcmcia_report_error(client_handle_t handle, error_info_t *err); struct pci_bus *pcmcia_lookup_bus(client_handle_t handle); +struct device *pcmcia_lookup_device(client_handle_t handle); /* rsrc_mgr.c */ int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj); --- linux-2.6.8-rc1/include/pcmcia/ds.h 2003-08-22 19:23:42.000000000 -0700 +++ 25/include/pcmcia/ds.h 2004-07-13 17:09:39.000000000 -0700 @@ -151,6 +151,21 @@ struct pcmcia_driver { struct device_driver drv; }; +struct pcmcia_device { + struct device dev; + struct pcmcia_bus_socket *socket; + struct list_head device_list; + int function; + int id_mask; + cistpl_vers_1_t vers_1; + cistpl_manfid_t manfid; +}; + +#define to_pcmcia_device(n) container_of(n, struct pcmcia_device, dev) + +#define DEVICE_HAS_VERSION_INFO 0x0001 +#define DEVICE_HAS_MANF_INFO 0x0002 + /* driver registration */ int pcmcia_register_driver(struct pcmcia_driver *driver); void pcmcia_unregister_driver(struct pcmcia_driver *driver); --- linux-2.6.8-rc1/include/rxrpc/call.h 2004-02-03 20:42:39.000000000 -0800 +++ 25/include/rxrpc/call.h 2004-07-13 17:09:13.000000000 -0700 @@ -204,7 +204,7 @@ extern int rxrpc_call_read_data(struct r extern int rxrpc_call_write_data(struct rxrpc_call *call, size_t sioc, - struct iovec siov[], + struct kvec *siov, uint8_t rxhdr_flags, int alloc_flags, int dup_data, --- linux-2.6.8-rc1/include/rxrpc/message.h 2004-02-03 20:42:39.000000000 -0800 +++ 25/include/rxrpc/message.h 2004-07-13 17:09:13.000000000 -0700 @@ -44,7 +44,7 @@ struct rxrpc_message int dcount; /* data part count */ size_t dsize; /* data size */ #define RXRPC_MSG_MAX_IOCS 8 - struct iovec data[RXRPC_MSG_MAX_IOCS]; /* message data */ + struct kvec data[RXRPC_MSG_MAX_IOCS]; /* message data */ unsigned long dfree; /* bit mask indicating kfree(data[x]) if T */ }; @@ -62,7 +62,7 @@ extern int rxrpc_conn_newmsg(struct rxrp struct rxrpc_call *call, uint8_t type, int count, - struct iovec diov[], + struct kvec *diov, int alloc_flags, struct rxrpc_message **_msg); --- linux-2.6.8-rc1/include/rxrpc/transport.h 2004-02-03 20:42:39.000000000 -0800 +++ 25/include/rxrpc/transport.h 2004-07-13 17:09:55.000000000 -0700 @@ -78,8 +78,6 @@ struct rxrpc_transport volatile char error_rcvd; /* T if received ICMP error outstanding */ }; -extern struct list_head rxrpc_transports; - extern int rxrpc_create_transport(unsigned short port, struct rxrpc_transport **_trans); --- linux-2.6.8-rc1/include/scsi/scsi_device.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/scsi/scsi_device.h 2004-07-13 17:09:24.000000000 -0700 @@ -188,7 +188,7 @@ extern int scsi_device_set_state(struct extern int scsi_device_quiesce(struct scsi_device *sdev); extern void scsi_device_resume(struct scsi_device *sdev); extern const char *scsi_device_state_name(enum scsi_device_state); -static int inline scsi_device_online(struct scsi_device *sdev) +static inline int scsi_device_online(struct scsi_device *sdev) { return sdev->sdev_state != SDEV_OFFLINE; } --- linux-2.6.8-rc1/include/scsi/scsi_driver.h 2003-11-23 19:03:02.000000000 -0800 +++ 25/include/scsi/scsi_driver.h 2004-07-13 17:09:31.000000000 -0700 @@ -13,6 +13,7 @@ struct scsi_driver { int (*init_command)(struct scsi_cmnd *); void (*rescan)(struct device *); + int (*issue_flush)(struct device *, sector_t *); }; #define to_scsi_driver(drv) \ container_of((drv), struct scsi_driver, gendrv) --- linux-2.6.8-rc1/include/sound/ac97_codec.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/ac97_codec.h 2004-07-13 17:09:19.182356712 -0700 @@ -441,6 +441,7 @@ struct _snd_ac97 { unsigned short subsystem_vendor; unsigned short subsystem_device; spinlock_t reg_lock; + struct semaphore mutex; /* mutex for AD18xx multi-codecs and paging (2.3) */ unsigned short num; /* number of codec: 0 = primary, 1 = secondary */ unsigned short addr; /* physical address of codec [0-3] */ unsigned int id; /* identification of codec */ @@ -461,7 +462,6 @@ struct _snd_ac97 { unsigned short id[3]; // codec IDs (lower 16-bit word) unsigned short pcmreg[3]; // PCM registers unsigned short codec_cfg[3]; // CODEC_CFG bits - struct semaphore mutex; } ad18xx; unsigned int dev_flags; /* device specific */ } spec; @@ -484,6 +484,10 @@ static inline int ac97_can_amap(ac97_t * { return (ac97->ext_id & AC97_EI_AMAP) != 0; } +static inline int ac97_can_spdif(ac97_t * ac97) +{ + return (ac97->ext_id & AC97_EI_SPDIF) != 0; +} /* functions */ int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus); /* create new AC97 bus */ --- linux-2.6.8-rc1/include/sound/asound.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/asound.h 2004-07-13 17:09:19.000000000 -0700 @@ -274,6 +274,7 @@ enum sndrv_pcm_subformat { #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ #define SNDRV_PCM_INFO_NONATOMIC_OPS 0x00800000 /* non-atomic prepare callback */ +#define SNDRV_PCM_INFO_MMAP_IOMEM 0x01000000 /* mmap on IO memory */ enum sndrv_pcm_state { SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ --- linux-2.6.8-rc1/include/sound/control.h 2003-06-14 12:18:21.000000000 -0700 +++ 25/include/sound/control.h 2004-07-13 17:09:19.000000000 -0700 @@ -35,8 +35,7 @@ typedef struct sndrv_ctl_elem_value snd_ typedef enum sndrv_ctl_event_type snd_ctl_event_type_t; typedef struct sndrv_ctl_event snd_ctl_event_t; -#define _snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) -#define snd_kcontrol_chip(kcontrol) snd_magic_cast1(chip_t, _snd_kcontrol_chip(kcontrol), return -ENXIO) +#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) typedef int (snd_kcontrol_info_t) (snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo); typedef int (snd_kcontrol_get_t) (snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); --- linux-2.6.8-rc1/include/sound/core.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/core.h 2004-07-13 17:09:19.000000000 -0700 @@ -211,12 +211,14 @@ int snd_card_set_dev_pm_callback(snd_car void *private_data); #define snd_card_set_isa_pm_callback(card,suspend,resume,data) \ snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data) +#ifdef CONFIG_PCI #ifndef SND_PCI_PM_CALLBACKS int snd_card_pci_suspend(struct pci_dev *dev, u32 state); int snd_card_pci_resume(struct pci_dev *dev); #define SND_PCI_PM_CALLBACKS \ .suspend = snd_card_pci_suspend, .resume = snd_card_pci_resume #endif +#endif #else #define snd_power_lock(card) do { (void)(card); } while (0) #define snd_power_unlock(card) do { (void)(card); } while (0) @@ -226,8 +228,10 @@ static inline int snd_power_wait(snd_car #define snd_card_set_pm_callback(card,suspend,resume,data) -EINVAL #define snd_card_set_dev_pm_callback(card,suspend,resume,data) -EINVAL #define snd_card_set_isa_pm_callback(card,suspend,resume,data) -EINVAL +#ifdef CONFIG_PCI #define SND_PCI_PM_CALLBACKS #endif +#endif /* device.c */ @@ -279,10 +283,12 @@ void snd_memory_done(void); int snd_memory_info_init(void); int snd_memory_info_done(void); void *snd_hidden_kmalloc(size_t size, int flags); +void *snd_hidden_kcalloc(size_t n, size_t size, int flags); void snd_hidden_kfree(const void *obj); void *snd_hidden_vmalloc(unsigned long size); void snd_hidden_vfree(void *obj); #define kmalloc(size, flags) snd_hidden_kmalloc(size, flags) +#define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags) #define kfree(obj) snd_hidden_kfree(obj) #define vmalloc(size) snd_hidden_vmalloc(size) #define vfree(obj) snd_hidden_vfree(obj) @@ -300,7 +306,6 @@ void snd_hidden_vfree(void *obj); #define kfree_nocheck(obj) kfree(obj) #define vfree_nocheck(obj) vfree(obj) #endif -void *snd_kcalloc(size_t size, int flags); char *snd_kmalloc_strdup(const char *string, int flags); int copy_to_user_fromio(void __user *dst, unsigned long src, size_t count); int copy_from_user_toio(unsigned long dst, const void __user *src, size_t count); --- linux-2.6.8-rc1/include/sound/cs46xx.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/cs46xx.h 2004-07-13 17:09:19.000000000 -0700 @@ -24,6 +24,7 @@ */ #include "pcm.h" +#include "pcm-indirect.h" #include "rawmidi.h" #include "ac97_codec.h" #include "cs46xx_dsp_spos.h" @@ -1650,14 +1651,7 @@ typedef struct _snd_cs46xx_pcm_t { unsigned int ctl; unsigned int shift; /* Shift count to trasform frames in bytes */ - unsigned int sw_bufsize; - unsigned int sw_data; /* Offset to next dst (or src) in sw ring buffer */ - unsigned int sw_io; - int sw_ready; /* Bytes ready to be transferred to/from hw */ - unsigned int hw_data; /* Offset to next dst (or src) in hw ring buffer */ - unsigned int hw_io; /* Ring buffer hw pointer */ - int hw_ready; /* Bytes ready for play (or captured) in hw ring buffer */ - size_t appl_ptr; /* Last seen appl_ptr */ + snd_pcm_indirect_t pcm_rec; snd_pcm_substream_t *substream; pcm_channel_descriptor_t * pcm_channel; @@ -1695,14 +1689,7 @@ struct _snd_cs46xx { unsigned int ctl; unsigned int shift; /* Shift count to trasform frames in bytes */ - unsigned int sw_bufsize; - unsigned int sw_data; /* Offset to next dst (or src) in sw ring buffer */ - unsigned int sw_io; - int sw_ready; /* Bytes ready to be transferred to/from hw */ - unsigned int hw_data; /* Offset to next dst (or src) in hw ring buffer */ - unsigned int hw_io; /* Ring buffer hw pointer */ - int hw_ready; /* Bytes ready for play (or captured) in hw ring buffer */ - size_t appl_ptr; /* Last seen appl_ptr */ + snd_pcm_indirect_t pcm_rec; snd_pcm_substream_t *substream; } capt; --- linux-2.6.8-rc1/include/sound/driver.h 2003-06-14 12:18:07.000000000 -0700 +++ 25/include/sound/driver.h 2004-07-13 17:09:19.000000000 -0700 @@ -61,6 +61,4 @@ void snd_wrapper_vfree(void *); #undef vfree #endif -#include "sndmagic.h" - #endif /* __SOUND_DRIVER_H */ --- linux-2.6.8-rc1/include/sound/emu10k1.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/emu10k1.h 2004-07-13 17:09:19.000000000 -0700 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -887,10 +888,7 @@ typedef struct { unsigned char gpr_trigger; /* GPR containing trigger (activate) information (host) */ unsigned char gpr_running; /* GPR containing info if PCM is running (FX8010) */ unsigned char etram[32]; /* external TRAM address & data */ - unsigned int sw_data, hw_data; - unsigned int sw_io, hw_io; - unsigned int sw_ready, hw_ready; - unsigned int appl_ptr; + snd_pcm_indirect_t pcm_rec; unsigned int tram_pos; unsigned int tram_shift; snd_emu10k1_fx8010_irq_t *irq; @@ -939,7 +937,8 @@ struct _snd_emu10k1 { int APS: 1, /* APS flag */ no_ac97: 1, /* no AC'97 */ tos_link: 1, /* tos link detected */ - rear_ac97: 1; /* rear channels are on AC'97 */ + rear_ac97: 1, /* rear channels are on AC'97 */ + spk71:1; /* 7.1 configuration (Audigy 2 ZS) */ unsigned int audigy; /* is Audigy? */ unsigned int revision; /* chip revision */ unsigned int serial; /* serial number */ @@ -972,7 +971,6 @@ struct _snd_emu10k1 { snd_pcm_t *pcm; snd_pcm_t *pcm_mic; snd_pcm_t *pcm_efx; - snd_pcm_t *pcm_fx8010; spinlock_t synth_lock; void *synth; @@ -1069,6 +1067,15 @@ int snd_emu10k1_audigy_midi(emu10k1_t * /* proc interface */ int snd_emu10k1_proc_init(emu10k1_t * emu); +/* fx8010 irq handler */ +int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, + snd_fx8010_irq_handler_t *handler, + unsigned char gpr_running, + void *private_data, + snd_emu10k1_fx8010_irq_t **r_irq); +int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, + snd_emu10k1_fx8010_irq_t *irq); + #endif /* __KERNEL__ */ /* @@ -1162,6 +1169,8 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define FXBUS_PCM_RIGHT_FRONT 0x09 #define FXBUS_MIDI_REVERB 0x0c #define FXBUS_MIDI_CHORUS 0x0d +#define FXBUS_PCM_LEFT_SIDE 0x0e +#define FXBUS_PCM_RIGHT_SIDE 0x0f #define FXBUS_PT_LEFT 0x14 #define FXBUS_PT_RIGHT 0x15 @@ -1227,8 +1236,8 @@ int snd_emu10k1_proc_init(emu10k1_t * em #define A_EXTOUT_AFRONT_R 0x09 /* right */ #define A_EXTOUT_ACENTER 0x0a /* analog center */ #define A_EXTOUT_ALFE 0x0b /* analog LFE */ -/* 0x0c ?? */ -/* 0x0d ?? */ +#define A_EXTOUT_ASIDE_L 0x0c /* analog side left - Audigy 2 ZS */ +#define A_EXTOUT_ASIDE_R 0x0d /* right - Audigy 2 ZS */ #define A_EXTOUT_AREAR_L 0x0e /* analog rear left */ #define A_EXTOUT_AREAR_R 0x0f /* right */ #define A_EXTOUT_AC97_L 0x10 /* AC97 left (front) */ --- linux-2.6.8-rc1/include/sound/es1688.h 2004-05-09 21:07:28.000000000 -0700 +++ 25/include/sound/es1688.h 2004-07-13 17:09:19.000000000 -0700 @@ -55,8 +55,6 @@ struct _snd_es1688 { typedef struct _snd_es1688 es1688_t; -#define chip_t es1688_t - /* I/O ports */ #define ES1688P(codec, x) ((codec)->port + e_s_s_ESS1688##x) --- linux-2.6.8-rc1/include/sound/initval.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/initval.h 2004-07-13 17:09:19.000000000 -0700 @@ -21,20 +21,6 @@ * */ -#ifndef MODULE_GENERIC_STRING -#ifdef MODULE -#define MODULE_GENERIC_STRING(name, string) \ -static const char __module_generic_string_##name [] \ - __attribute__ ((unused, __section__(".modstring"))) = #name "=" string; -#else -#define MODULE_GENERIC_STRING(name, string) -#endif -#endif - -#define MODULE_CLASSES(val) MODULE_GENERIC_STRING(info_classes, val) -#define MODULE_DEVICES(val) MODULE_GENERIC_STRING(info_devices, val) -#define MODULE_PARM_SYNTAX(id, val) MODULE_GENERIC_STRING(info_parm_##id, val) - #define SNDRV_AUTO_PORT 1 #define SNDRV_AUTO_IRQ 0xffff #define SNDRV_AUTO_DMA 0xffff @@ -64,25 +50,6 @@ static const char __module_generic_strin #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE } #define SNDRV_DEFAULT_PTR SNDRV_DEFAULT_STR -#define SNDRV_BOOLEAN_TRUE_DESC "allows:{{0,Disabled},{1,Enabled}},default:1,dialog:check" -#define SNDRV_BOOLEAN_FALSE_DESC "allows:{{0,Disabled},{1,Enabled}},default:0,dialog:check" - -#define SNDRV_ENABLED "enable:(enable)" - -#define SNDRV_INDEX_DESC SNDRV_ENABLED ",allows:{{0,7}},unique,skill:required,dialog:list" -#define SNDRV_ID_DESC SNDRV_ENABLED ",unique" -#define SNDRV_ENABLE_DESC SNDRV_BOOLEAN_FALSE_DESC -#define SNDRV_ISAPNP_DESC SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC -#define SNDRV_DMA8_DESC SNDRV_ENABLED ",allows:{{0,1},{3}},dialog:list" -#define SNDRV_DMA16_DESC SNDRV_ENABLED ",allows:{{5,7}},dialog:list" -#define SNDRV_DMA_DESC SNDRV_ENABLED ",allows:{{0,1},{3},{5,7}},dialog:list" -#define SNDRV_IRQ_DESC SNDRV_ENABLED ",allows:{{5},{7},{9},{10,12},{14,15}},dialog:list" -#define SNDRV_DMA_SIZE_DESC SNDRV_ENABLED ",allows:{{4,128}},default:64,skill:advanced" -#define SNDRV_DMA8_SIZE_DESC SNDRV_ENABLED ",allows:{{4, 64}},default:64,skill:advanced" -#define SNDRV_DMA16_SIZE_DESC SNDRV_ENABLED ",allows:{{4,128}},default:64,skill:advanced" -#define SNDRV_PORT12_DESC SNDRV_ENABLED ",allows:{{0,0x3fff}},base:16" -#define SNDRV_PORT_DESC SNDRV_ENABLED ",allows:{{0,0xffff}},base:16" - #ifdef SNDRV_LEGACY_AUTO_PROBE static int snd_legacy_auto_probe(unsigned long *ports, int (*probe)(unsigned long port)) { --- linux-2.6.8-rc1/include/sound/pcm.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/pcm.h 2004-07-13 17:09:19.000000000 -0700 @@ -52,10 +52,8 @@ typedef struct sndrv_pcm_mmap_control sn typedef struct sndrv_mask snd_mask_t; typedef struct snd_sg_buf snd_pcm_sgbuf_t; -#define _snd_pcm_substream_chip(substream) ((substream)->private_data) -#define snd_pcm_substream_chip(substream) snd_magic_cast1(chip_t, _snd_pcm_substream_chip(substream), return -ENXIO) -#define _snd_pcm_chip(pcm) ((pcm)->private_data) -#define snd_pcm_chip(pcm) snd_magic_cast1(chip_t, _snd_pcm_chip(pcm), return -ENXIO) +#define snd_pcm_substream_chip(substream) ((substream)->private_data) +#define snd_pcm_chip(pcm) ((pcm)->private_data) typedef struct _snd_pcm_file snd_pcm_file_t; typedef struct _snd_pcm_runtime snd_pcm_runtime_t; @@ -351,7 +349,8 @@ struct _snd_pcm_runtime { unsigned char *dma_area; /* DMA area */ dma_addr_t dma_addr; /* physical bus address (not accessible from main CPU) */ size_t dma_bytes; /* size of DMA area */ - void *dma_private; /* private DMA data for the memory allocator */ + + struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */ #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ @@ -851,7 +850,7 @@ int snd_pcm_format_little_endian(snd_pcm int snd_pcm_format_big_endian(snd_pcm_format_t format); int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ -u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format); +const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian); ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); @@ -892,6 +891,22 @@ snd_pcm_sframes_t snd_pcm_lib_readv(snd_ int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime); +static inline void snd_pcm_set_runtime_buffer(snd_pcm_substream_t *substream, + struct snd_dma_buffer *bufp) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + if (bufp) { + runtime->dma_buffer_p = bufp; + runtime->dma_area = bufp->area; + runtime->dma_addr = bufp->addr; + runtime->dma_bytes = bufp->bytes; + } else { + runtime->dma_buffer_p = NULL; + runtime->dma_area = NULL; + runtime->dma_addr = 0; + runtime->dma_bytes = 0; + } +} /* * Timer interface @@ -916,7 +931,7 @@ int snd_pcm_lib_preallocate_pages_for_al int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size); int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream); -#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private) +#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data) #define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size) #define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs) struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/include/sound/pcm-indirect.h 2004-07-13 17:09:19.000000000 -0700 @@ -0,0 +1,173 @@ +/* + * Helper functions for indirect PCM data transfer + * + * Copyright (c) by Takashi Iwai + * Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SOUND_PCM_INDIRECT_H +#define __SOUND_PCM_INDIRECT_H + +#include + +typedef struct sndrv_pcm_indirect { + unsigned int hw_buffer_size; /* Byte size of hardware buffer */ + unsigned int hw_queue_size; /* Max queue size of hw buffer (0 = buffer size) */ + unsigned int hw_data; /* Offset to next dst (or src) in hw ring buffer */ + unsigned int hw_io; /* Ring buffer hw pointer */ + int hw_ready; /* Bytes ready for play (or captured) in hw ring buffer */ + unsigned int sw_buffer_size; /* Byte size of software buffer */ + unsigned int sw_data; /* Offset to next dst (or src) in sw ring buffer */ + unsigned int sw_io; /* Current software pointer in bytes */ + int sw_ready; /* Bytes ready to be transferred to/from hw */ + snd_pcm_uframes_t appl_ptr; /* Last seen appl_ptr */ +} snd_pcm_indirect_t; + +typedef void (*snd_pcm_indirect_copy_t)(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes); + +/* + * helper function for playback ack callback + */ +static inline void +snd_pcm_indirect_playback_transfer(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, + snd_pcm_indirect_copy_t copy) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; + snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; + int qsize; + + if (diff) { + if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) + diff += runtime->boundary; + rec->sw_ready += (int)frames_to_bytes(runtime, diff); + rec->appl_ptr = appl_ptr; + } + qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size; + while (rec->hw_ready < qsize && rec->sw_ready > 0) { + unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data; + unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data; + unsigned int bytes = qsize - rec->hw_ready; + if (rec->sw_ready < (int)bytes) + bytes = rec->sw_ready; + if (hw_to_end < bytes) + bytes = hw_to_end; + if (sw_to_end < bytes) + bytes = sw_to_end; + if (! bytes) + break; + copy(substream, rec, bytes); + rec->hw_data += bytes; + if (rec->hw_data == rec->hw_buffer_size) + rec->hw_data = 0; + rec->sw_data += bytes; + if (rec->sw_data == rec->sw_buffer_size) + rec->sw_data = 0; + rec->hw_ready += bytes; + rec->sw_ready -= bytes; + } +} + +/* + * helper function for playback pointer callback + * ptr = current byte pointer + */ +static inline snd_pcm_uframes_t +snd_pcm_indirect_playback_pointer(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, unsigned int ptr) +{ + int bytes = ptr - rec->hw_io; + if (bytes < 0) + bytes += rec->hw_buffer_size; + rec->hw_io = ptr; + rec->hw_ready -= bytes; + rec->sw_io += bytes; + if (rec->sw_io >= rec->sw_buffer_size) + rec->sw_io -= rec->sw_buffer_size; + if (substream->ops->ack) + substream->ops->ack(substream); + return bytes_to_frames(substream->runtime, rec->sw_io); +} + + +/* + * helper function for capture ack callback + */ +static inline void +snd_pcm_indirect_capture_transfer(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, + snd_pcm_indirect_copy_t copy) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; + snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr; + + if (diff) { + if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) + diff += runtime->boundary; + rec->sw_ready -= frames_to_bytes(runtime, diff); + rec->appl_ptr = appl_ptr; + } + while (rec->hw_ready > 0 && + rec->sw_ready < (int)rec->sw_buffer_size) { + size_t hw_to_end = rec->hw_buffer_size - rec->hw_data; + size_t sw_to_end = rec->sw_buffer_size - rec->sw_data; + size_t bytes = rec->sw_buffer_size - rec->sw_ready; + if (rec->hw_ready < (int)bytes) + bytes = rec->hw_ready; + if (hw_to_end < bytes) + bytes = hw_to_end; + if (sw_to_end < bytes) + bytes = sw_to_end; + if (! bytes) + break; + copy(substream, rec, bytes); + rec->hw_data += bytes; + if ((int)rec->hw_data == rec->hw_buffer_size) + rec->hw_data = 0; + rec->sw_data += bytes; + if (rec->sw_data == rec->sw_buffer_size) + rec->sw_data = 0; + rec->hw_ready -= bytes; + rec->sw_ready += bytes; + } +} + +/* + * helper function for capture pointer callback, + * ptr = current byte pointer + */ +static inline snd_pcm_uframes_t +snd_pcm_indirect_capture_pointer(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, unsigned int ptr) +{ + int bytes = ptr - rec->hw_io; + if (bytes < 0) + bytes += rec->hw_buffer_size; + rec->hw_io = ptr; + rec->hw_ready += bytes; + rec->sw_io += bytes; + if (rec->sw_io >= rec->sw_buffer_size) + rec->sw_io -= rec->sw_buffer_size; + if (substream->ops->ack) + substream->ops->ack(substream); + return bytes_to_frames(substream->runtime, rec->sw_io); +} + +#endif /* __SOUND_PCM_INDIRECT_H */ --- linux-2.6.8-rc1/include/sound/seq_kernel.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/seq_kernel.h 2004-07-13 17:09:19.000000000 -0700 @@ -168,6 +168,9 @@ typedef int (*snd_seq_dump_func_t)(void int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf, int in_kernel, int size_aligned); int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t func, void *private_data); +/* interface for OSS emulation */ +int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo); + /* port callback routines */ void snd_port_init_callback(snd_seq_port_callback_t *p); snd_seq_port_callback_t *snd_port_alloc_callback(void); --- linux-2.6.8-rc1/include/sound/sndmagic.h 2004-05-09 21:07:28.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,218 +0,0 @@ -#ifndef __SOUND_SNDMAGIC_H -#define __SOUND_SNDMAGIC_H - -/* - * Magic allocation, deallocation, check - * Copyright (c) 2000 by Abramo Bagnara - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#ifdef CONFIG_SND_DEBUG_MEMORY - -void *_snd_magic_kcalloc(unsigned long magic, size_t size, int flags); -void *_snd_magic_kmalloc(unsigned long magic, size_t size, int flags); - -/** - * snd_magic_kmalloc - allocate a record with a magic-prefix - * @type: the type to allocate a record (like xxx_t) - * @extra: the extra size to allocate in bytes - * @flags: the allocation condition (GFP_XXX) - * - * Allocates a record of the given type with the extra space and - * returns its pointer. The allocated record has a secret magic-key - * to be checked via snd_magic_cast() for safe casts. - * - * The allocated pointer must be released via snd_magic_kfree(). - * - * The "struct xxx" style cannot be used as the type argument - * because the magic-key constant is generated from the type-name - * string. - */ -#define snd_magic_kmalloc(type, extra, flags) \ - (type *) _snd_magic_kmalloc(type##_magic, sizeof(type) + extra, flags) -/** - * snd_magic_kcalloc - allocate a record with a magic-prefix and initialize - * @type: the type to allocate a record (like xxx_t) - * @extra: the extra size to allocate in bytes - * @flags: the allocation condition (GFP_XXX) - * - * Works like snd_magic_kmalloc() but this clears the area with zero - * automatically. - */ -#define snd_magic_kcalloc(type, extra, flags) \ - (type *) _snd_magic_kcalloc(type##_magic, sizeof(type) + extra, flags) - -/** - * snd_magic_kfree - release the allocated area - * @ptr: the pointer allocated via snd_magic_kmalloc() or snd_magic_kcalloc() - * - * Releases the memory area allocated via snd_magic_kmalloc() or - * snd_magic_kcalloc() function. - */ -void snd_magic_kfree(void *ptr); - -static inline unsigned long _snd_magic_value(void *obj) -{ - return obj == NULL ? (unsigned long)-1 : *(((unsigned long *)obj) - 1); -} - -static inline int _snd_magic_bad(void *obj, unsigned long magic) -{ - return _snd_magic_value(obj) != magic; -} - -#define snd_magic_cast1(t, expr, cmd) snd_magic_cast(t, expr, cmd) - -/** - * snd_magic_cast - check and cast the magic-allocated pointer - * @type: the type of record to cast - * @ptr: the magic-allocated pointer - * @action...: the action to do if failed - * - * This macro provides a safe cast for the given type, which was - * allocated via snd_magic_kmalloc() or snd_magic_kcallc(). - * If the pointer is invalid, i.e. the cast-type doesn't match, - * the action arguments are called with a debug message. - */ -#define snd_magic_cast(type, ptr, action...) \ - (type *) ({\ - void *__ptr = ptr;\ - unsigned long __magic = _snd_magic_value(__ptr);\ - if (__magic != type##_magic) {\ - snd_printk("bad MAGIC (0x%lx)\n", __magic);\ - action;\ - }\ - __ptr;\ -}) - -#define snd_device_t_magic 0xa15a00ff -#define snd_pcm_t_magic 0xa15a0101 -#define snd_pcm_file_t_magic 0xa15a0102 -#define snd_pcm_substream_t_magic 0xa15a0103 -#define snd_pcm_proc_private_t_magic 0xa15a0104 -#define snd_pcm_oss_file_t_magic 0xa15a0105 -#define snd_mixer_oss_t_magic 0xa15a0106 -// #define snd_pcm_sgbuf_t_magic 0xa15a0107 - -#define snd_info_private_data_t_magic 0xa15a0201 -#define snd_info_entry_t_magic 0xa15a0202 -#define snd_ctl_file_t_magic 0xa15a0301 -#define snd_kcontrol_t_magic 0xa15a0302 -#define snd_rawmidi_t_magic 0xa15a0401 -#define snd_rawmidi_file_t_magic 0xa15a0402 -#define snd_virmidi_t_magic 0xa15a0403 -#define snd_virmidi_dev_t_magic 0xa15a0404 -#define snd_timer_t_magic 0xa15a0501 -#define snd_timer_user_t_magic 0xa15a0502 -#define snd_hwdep_t_magic 0xa15a0601 -#define snd_seq_device_t_magic 0xa15a0701 - -#define es18xx_t_magic 0xa15a1101 -#define trident_t_magic 0xa15a1201 -#define es1938_t_magic 0xa15a1301 -#define cs46xx_t_magic 0xa15a1401 -#define cs46xx_pcm_t_magic 0xa15a1402 -#define ensoniq_t_magic 0xa15a1501 -#define sonicvibes_t_magic 0xa15a1601 -#define mpu401_t_magic 0xa15a1701 -#define fm801_t_magic 0xa15a1801 -#define ac97_t_magic 0xa15a1901 -#define ac97_bus_t_magic 0xa15a1902 -#define ak4531_t_magic 0xa15a1a01 -#define snd_uart16550_t_magic 0xa15a1b01 -#define emu10k1_t_magic 0xa15a1c01 -#define emu10k1_pcm_t_magic 0xa15a1c02 -#define emu10k1_midi_t_magic 0xa15a1c03 -#define snd_gus_card_t_magic 0xa15a1d01 -#define gus_pcm_private_t_magic 0xa15a1d02 -#define gus_proc_private_t_magic 0xa15a1d03 -#define tea6330t_t_magic 0xa15a1e01 -#define ad1848_t_magic 0xa15a1f01 -#define cs4231_t_magic 0xa15a2001 -#define es1688_t_magic 0xa15a2101 -#define opti93x_t_magic 0xa15a2201 -#define emu8000_t_magic 0xa15a2301 -#define emu8000_proc_private_t_magic 0xa15a2302 -#define snd_emux_t_magic 0xa15a2303 -#define snd_emux_port_t_magic 0xa15a2304 -#define sb_t_magic 0xa15a2401 -#define snd_sb_csp_t_magic 0xa15a2402 -#define snd_card_dummy_t_magic 0xa15a2501 -#define snd_card_dummy_pcm_t_magic 0xa15a2502 -#define opl3_t_magic 0xa15a2601 -#define opl4_t_magic 0xa15a2602 -#define snd_seq_dummy_port_t_magic 0xa15a2701 -#define ice1712_t_magic 0xa15a2801 -#define ad1816a_t_magic 0xa15a2901 -#define intel8x0_t_magic 0xa15a2a01 -#define es1968_t_magic 0xa15a2b01 -#define esschan_t_magic 0xa15a2b02 -#define via82xx_t_magic 0xa15a2c01 -#define pdplus_t_magic 0xa15a2d01 -#define cmipci_t_magic 0xa15a2e01 -#define ymfpci_t_magic 0xa15a2f01 -#define ymfpci_pcm_t_magic 0xa15a2f02 -#define cs4281_t_magic 0xa15a3001 -#define snd_i2c_bus_t_magic 0xa15a3101 -#define snd_i2c_device_t_magic 0xa15a3102 -#define cs8427_t_magic 0xa15a3111 -#define m3_t_magic 0xa15a3201 -#define m3_dma_t_magic 0xa15a3202 -#define nm256_t_magic 0xa15a3301 -#define nm256_dma_t_magic 0xa15a3302 -#define sam9407_t_magic 0xa15a3401 -#define pmac_t_magic 0xa15a3501 -#define ali_t_magic 0xa15a3601 -#define mtpav_t_magic 0xa15a3701 -#define mtpav_port_t_magic 0xa15a3702 -#define korg1212_t_magic 0xa15a3800 -#define opl3sa2_t_magic 0xa15a3900 -#define serialmidi_t_magic 0xa15a3a00 -#define sa11xx_uda1341_t_magic 0xa15a3b00 -#define uda1341_t_magic 0xa15a3c00 -#define l3_client_t_magic 0xa15a3d00 -#define snd_usb_audio_t_magic 0xa15a3e01 -#define usb_mixer_elem_info_t_magic 0xa15a3e02 -#define snd_usb_stream_t_magic 0xa15a3e03 -#define snd_usb_midi_t_magic 0xa15a3f01 -#define snd_usb_midi_out_endpoint_t_magic 0xa15a3f02 -#define snd_usb_midi_in_endpoint_t_magic 0xa15a3f03 -#define ak4117_t_magic 0xa15a4000 -#define psic_t_magic 0xa15a4100 -#define vx_core_t_magic 0xa15a4110 -#define vx_pipe_t_magic 0xa15a4112 -#define azf3328_t_magic 0xa15a4200 -#define snd_card_harmony_t_magic 0xa15a4300 -#define bt87x_t_magic 0xa15a4400 -#define pdacf_t_magic 0xa15a4500 -#define vortex_t_magic 0xa15a4601 -#define atiixp_t_magic 0xa15a4701 -#define amd7930_t_magic 0xa15a4801 - -#else - -#define snd_magic_kcalloc(type, extra, flags) (type *) snd_kcalloc(sizeof(type) + extra, flags) -#define snd_magic_kmalloc(type, extra, flags) (type *) kmalloc(sizeof(type) + extra, flags) -#define snd_magic_cast(type, ptr, retval) (type *) ptr -#define snd_magic_cast1(type, ptr, retval) snd_magic_cast(type, ptr, retval) -#define snd_magic_kfree kfree - -#endif - -#endif /* __SOUND_SNDMAGIC_H */ --- linux-2.6.8-rc1/include/sound/timer.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/timer.h 2004-07-13 17:09:19.000000000 -0700 @@ -40,8 +40,7 @@ typedef struct sndrv_timer_status snd_ti typedef struct sndrv_timer_read snd_timer_read_t; typedef struct sndrv_timer_tread snd_timer_tread_t; -#define _snd_timer_chip(timer) ((timer)->private_data) -#define snd_timer_chip(timer) snd_magic_cast1(chip_t, _snd_timer_chip(timer), return -ENXIO) +#define snd_timer_chip(timer) ((timer)->private_data) #define SNDRV_TIMER_DEVICES 16 --- linux-2.6.8-rc1/include/sound/version.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/version.h 2004-07-13 17:09:19.194354888 -0700 @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.4" -#define CONFIG_SND_DATE " (Mon May 17 14:31:44 2004 UTC)" +#define CONFIG_SND_VERSION "1.0.5" +#define CONFIG_SND_DATE " (Sun May 30 10:49:40 2004 UTC)" --- linux-2.6.8-rc1/include/sound/vx_core.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/include/sound/vx_core.h 2004-07-13 17:09:19.000000000 -0700 @@ -182,6 +182,7 @@ struct snd_vx_core { /* clock and audio sources */ unsigned int audio_source; /* current audio input source */ unsigned int audio_source_target; + unsigned int clock_mode; /* clock mode (VX_CLOCK_MODE_XXX) */ unsigned int clock_source; /* current clock source (INTERNAL_QUARTZ or UER_SYNC) */ unsigned int freq; /* current frequency */ unsigned int freq_detected; /* detected frequency from digital in */ @@ -364,6 +365,13 @@ enum { UER_SYNC }; +/* clock mode */ +enum { + VX_CLOCK_MODE_AUTO, /* depending on the current audio source */ + VX_CLOCK_MODE_INTERNAL, /* fixed to internal quartz */ + VX_CLOCK_MODE_EXTERNAL /* fixed to UER sync */ +}; + /* SPDIF/UER type */ enum { VX_UER_MODE_CONSUMER, --- linux-2.6.8-rc1/init/Kconfig 2004-07-11 14:13:30.000000000 -0700 +++ 25/init/Kconfig 2004-07-13 17:09:13.000000000 -0700 @@ -162,7 +162,7 @@ config AUDIT config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC64 || ARCH_S390) + depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64) default y if SECURITY_SELINUX default n help --- linux-2.6.8-rc1/init/main.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/init/main.c 2004-07-13 17:35:08.000000000 -0700 @@ -178,15 +178,28 @@ static int __init obsolete_checksetup(ch return 0; } -/* this should be approx 2 Bo*oMips to start (note initial shift), and will - still work even if initially too large, it will just take slightly longer */ +static unsigned long preset_lpj; +static int __init lpj_setup(char *str) +{ + preset_lpj = simple_strtoul(str,NULL,0); + return 1; +} + +__setup("lpj=", lpj_setup); + +/* + * This should be approx 2 Bo*oMips to start (note initial shift), and will + * still work even if initially too large, it will just take slightly longer + */ unsigned long loops_per_jiffy = (1<<12); EXPORT_SYMBOL(loops_per_jiffy); -/* This is the number of bits of precision for the loops_per_jiffy. Each - bit takes on average 1.5/HZ seconds. This (like the original) is a little - better than 1% */ +/* + * This is the number of bits of precision for the loops_per_jiffy. Each + * bit takes on average 1.5/HZ seconds. This (like the original) is a little + * better than 1% + */ #define LPS_PREC 8 void __devinit calibrate_delay(void) @@ -194,40 +207,53 @@ void __devinit calibrate_delay(void) unsigned long ticks, loopbit; int lps_precision = LPS_PREC; - loops_per_jiffy = (1<<12); + if (preset_lpj) { + loops_per_jiffy = preset_lpj; + printk("Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); + } else { + loops_per_jiffy = (1<<12); - printk("Calibrating delay loop... "); - while ((loops_per_jiffy <<= 1) != 0) { - /* wait for "start of" clock tick */ - ticks = jiffies; - while (ticks == jiffies) - /* nothing */; - /* Go .. */ - ticks = jiffies; - __delay(loops_per_jiffy); - ticks = jiffies - ticks; - if (ticks) - break; - } + printk("Calibrating delay loop... "); + while ((loops_per_jiffy <<= 1) != 0) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + + /* + * Do a binary approximation to get loops_per_jiffy set to + * equal one clock (up to lps_precision bits) + */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while (lps_precision-- && (loopbit >>= 1)) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } -/* Do a binary approximation to get loops_per_jiffy set to equal one clock - (up to lps_precision bits) */ - loops_per_jiffy >>= 1; - loopbit = loops_per_jiffy; - while ( lps_precision-- && (loopbit >>= 1) ) { - loops_per_jiffy |= loopbit; - ticks = jiffies; - while (ticks == jiffies); - ticks = jiffies; - __delay(loops_per_jiffy); - if (jiffies != ticks) /* longer than 1 tick */ - loops_per_jiffy &= ~loopbit; + /* Round the value and print it */ + printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100, + loops_per_jiffy); } -/* Round the value and print it */ - printk("%lu.%02lu BogoMIPS\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100); } static int __init debug_kernel(char *str) @@ -249,8 +275,10 @@ static int __init quiet_kernel(char *str __setup("debug", debug_kernel); __setup("quiet", quiet_kernel); -/* Unknown boot options get handed to init, unless they look like - failed parameters */ +/* + * Unknown boot options get handed to init, unless they look like + * failed parameters + */ static int __init unknown_bootoption(char *param, char *val) { /* Change NUL term back to "=", to make "param" the whole string. */ @@ -261,8 +289,10 @@ static int __init unknown_bootoption(cha if (obsolete_checksetup(param)) return 0; - /* Preemptive maintenance for "why didn't my mispelled command - line work?" */ + /* + * Preemptive maintenance for "why didn't my mispelled command + * line work?" + */ if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param); return 0; @@ -302,7 +332,8 @@ static int __init init_setup(char *str) unsigned int i; execute_command = str; - /* In case LILO is going to boot us with default command line, + /* + * In case LILO is going to boot us with default command line, * it prepends "auto" before the whole cmdline which makes * the shell think it should execute a script with such name. * So we ignore all arguments entered _before_ init=... [MJ] @@ -399,6 +430,7 @@ static void noinline rest_init(void) { kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND); numa_default_policy(); + system_state = SYSTEM_BOOTING_SCHEDULER_OK; unlock_kernel(); cpu_idle(); } @@ -466,15 +498,23 @@ asmlinkage void __init start_kernel(void */ sched_init(); + /* + * Make us the idle thread. Technically, schedule() should not be + * called from this thread, however somewhere below it might be, + * but because we are the idle thread, we just pick up running again + * when this runqueue becomes "idle". + */ + init_idle(current, smp_processor_id()); + build_all_zonelists(); page_alloc_init(); + trap_init(); printk("Kernel command line: %s\n", saved_command_line); parse_early_param(); parse_args("Booting kernel", command_line, __start___param, __stop___param - __start___param, &unknown_bootoption); sort_main_extable(); - trap_init(); rcu_init(); init_IRQ(); pidhash_init(); @@ -530,13 +570,6 @@ asmlinkage void __init start_kernel(void #endif check_bugs(); - /* - * We count on the initial thread going ok - * Like idlers init is an unlocked kernel thread, which will - * make syscalls (and thus be locked). - */ - init_idle(current, smp_processor_id()); - /* Do the rest non-__init'ed, we're now alive */ rest_init(); } --- linux-2.6.8-rc1/ipc/compat.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/ipc/compat.c 2004-07-13 17:09:13.000000000 -0700 @@ -235,24 +235,13 @@ static inline int put_compat_semid_ds(st return err; } -static inline int do_semctl(int semid, int semnum, int cmd, union semun arg) -{ - mm_segment_t old_fs; - int err; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_semctl(semid, semnum, cmd, arg); - set_fs(old_fs); - - return err; -} long compat_sys_semctl(int first, int second, int third, void __user *uptr) { union semun fourth; u32 pad; int err, err2; struct semid64_ds s64; + struct semid64_ds __user *up64; int version = compat_ipc_parse_version(&third); if (!uptr) @@ -279,16 +268,17 @@ long compat_sys_semctl(int first, int se case IPC_STAT: case SEM_STAT: - fourth.__pad = &s64; - err = do_semctl(first, second, third, fourth); + up64 = compat_alloc_user_space(sizeof(s64)); + fourth.__pad = up64; + err = sys_semctl(first, second, third, fourth); if (err < 0) break; - - if (version == IPC_64) { + if (copy_from_user(&s64, up64, sizeof(s64))) + err2 = -EFAULT; + else if (version == IPC_64) err2 = put_compat_semid64_ds(&s64, compat_ptr(pad)); - } else { + else err2 = put_compat_semid_ds(&s64, compat_ptr(pad)); - } if (err2) err = -EFAULT; break; @@ -299,11 +289,14 @@ long compat_sys_semctl(int first, int se } else { err = get_compat_semid_ds(&s64, compat_ptr(pad)); } + up64 = compat_alloc_user_space(sizeof(s64)); + if (copy_to_user(up64, &s64, sizeof(s64))) + err = -EFAULT; if (err) break; - fourth.__pad = &s64; - err = do_semctl(first, second, third, fourth); + fourth.__pad = up64; + err = sys_semctl(first, second, third, fourth); break; default: @@ -315,39 +308,30 @@ long compat_sys_semctl(int first, int se long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) { - struct msgbuf *p; - struct compat_msgbuf __user *up; - mm_segment_t old_fs; - int err; + struct msgbuf __user *p; + struct compat_msgbuf __user *up = uptr; + long type; if (first < 0) return -EINVAL; if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) return -EINVAL; - p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); - if (!p) - return -ENOMEM; - err = -EFAULT; - up = uptr; - if (get_user(p->mtype, &up->mtype) || - copy_from_user(p->mtext, &up->mtext, second)) - goto out; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_msgsnd(first, p, second, third); - set_fs(old_fs); -out: - kfree(p); - return err; + p = compat_alloc_user_space(second + sizeof(struct msgbuf)); + if (get_user(type, &up->mtype) || + put_user(type, &p->mtype) || + copy_in_user(p->mtext, up->mtext, second)) + return -EFAULT; + + return sys_msgsnd(first, p, second, third); } long compat_sys_msgrcv(int first, int second, int msgtyp, int third, int version, void __user *uptr) { - struct msgbuf *p; + struct msgbuf __user *p; struct compat_msgbuf __user *up; - mm_segment_t old_fs; + long type; int err; if (first < 0) @@ -356,34 +340,25 @@ long compat_sys_msgrcv(int first, int se return -EINVAL; if (!version) { - struct compat_ipc_kludge __user *uipck = uptr; struct compat_ipc_kludge ipck; - err = -EINVAL; if (!uptr) goto out; err = -EFAULT; - if (copy_from_user (&ipck, uipck, sizeof(ipck))) + if (copy_from_user (&ipck, uptr, sizeof(ipck))) goto out; uptr = compat_ptr(ipck.msgp); msgtyp = ipck.msgtyp; } - err = -ENOMEM; - p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); - if (!p) - goto out; - old_fs = get_fs(); - set_fs(KERNEL_DS); + p = compat_alloc_user_space(second + sizeof(struct msgbuf)); err = sys_msgrcv(first, p, second, msgtyp, third); - set_fs(old_fs); if (err < 0) - goto free_then_out; + goto out; up = uptr; - if (put_user(p->mtype, &up->mtype) || - __copy_to_user(&up->mtext, p->mtext, err)) + if (get_user(type, &p->mtype) || + put_user(type, &up->mtype) || + copy_in_user(up->mtext, p->mtext, err)) err = -EFAULT; -free_then_out: - kfree(p); out: return err; } @@ -450,24 +425,12 @@ static inline int put_compat_msqid_ds(st return err; } -static inline int do_msgctl(int first, int second, void *buf) -{ - mm_segment_t old_fs; - int err; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_msgctl(first, second, buf); - set_fs(old_fs); - - return err; -} - long compat_sys_msgctl(int first, int second, void __user *uptr) { int err, err2; struct msqid64_ds m64; int version = compat_ipc_parse_version(&second); + void __user *p; switch (second & (~IPC_64)) { case IPC_INFO: @@ -484,21 +447,25 @@ long compat_sys_msgctl(int first, int se } if (err) break; - - err = do_msgctl(first, second, &m64); + p = compat_alloc_user_space(sizeof(m64)); + if (copy_to_user(p, &m64, sizeof(m64))) + err = -EFAULT; + else + err = sys_msgctl(first, second, p); break; case IPC_STAT: case MSG_STAT: - err = do_msgctl(first, second, &m64); + p = compat_alloc_user_space(sizeof(m64)); + err = sys_msgctl(first, second, p); if (err < 0) break; - - if (version == IPC_64) { + if (copy_from_user(&m64, p, sizeof(m64))) + err2 = -EFAULT; + else if (version == IPC_64) err2 = put_compat_msqid64_ds(&m64, uptr); - } else { + else err2 = put_compat_msqid_ds(&m64, uptr); - } if (err2) err = -EFAULT; break; @@ -607,40 +574,29 @@ static inline int put_compat_shminfo(str err |= __put_user(smi->shmall, &up->shmall); } -static inline int put_compat_shm_info(struct shm_info *si, +static inline int put_compat_shm_info(struct shm_info __user *ip, struct compat_shm_info __user *uip) { int err; + struct shm_info si; - if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) + if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) || + copy_from_user(&si, ip, sizeof(si))) return -EFAULT; - err = __put_user(si->used_ids, &uip->used_ids); - err |= __put_user(si->shm_tot, &uip->shm_tot); - err |= __put_user(si->shm_rss, &uip->shm_rss); - err |= __put_user(si->shm_swp, &uip->shm_swp); - err |= __put_user(si->swap_attempts, &uip->swap_attempts); - err |= __put_user(si->swap_successes, &uip->swap_successes); - return err; -} - -static inline int do_shmctl(int shmid, int cmd, void *buf) -{ - mm_segment_t old_fs; - int err; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_shmctl(shmid, cmd, buf); - set_fs(old_fs); - + err = __put_user(si.used_ids, &uip->used_ids); + err |= __put_user(si.shm_tot, &uip->shm_tot); + err |= __put_user(si.shm_rss, &uip->shm_rss); + err |= __put_user(si.shm_swp, &uip->shm_swp); + err |= __put_user(si.swap_attempts, &uip->swap_attempts); + err |= __put_user(si.swap_successes, &uip->swap_successes); return err; } long compat_sys_shmctl(int first, int second, void __user *uptr) { + void __user *p; struct shmid64_ds s64; struct shminfo64 smi; - struct shm_info si; int err, err2; int version = compat_ipc_parse_version(&second); @@ -652,15 +608,16 @@ long compat_sys_shmctl(int first, int se break; case IPC_INFO: - err = do_shmctl(first, second, &smi); + p = compat_alloc_user_space(sizeof(smi)); + err = sys_shmctl(first, second, p); if (err < 0) break; - - if (version == IPC_64) { + if (copy_from_user(&smi, p, sizeof(smi))) + err2 = -EFAULT; + else if (version == IPC_64) err2 = put_compat_shminfo64(&smi, uptr); - } else { + else err2 = put_compat_shminfo(&smi, uptr); - } if (err2) err = -EFAULT; break; @@ -674,30 +631,35 @@ long compat_sys_shmctl(int first, int se } if (err) break; - - err = do_shmctl(first, second, &s64); + p = compat_alloc_user_space(sizeof(s64)); + if (copy_to_user(p, &s64, sizeof(s64))) + err = -EFAULT; + else + err = sys_shmctl(first, second, p); break; case IPC_STAT: case SHM_STAT: - err = do_shmctl(first, second, &s64); + p = compat_alloc_user_space(sizeof(s64)); + err = sys_shmctl(first, second, p); if (err < 0) break; - - if (version == IPC_64) { + if (copy_from_user(&s64, p, sizeof(s64))) + err2 = -EFAULT; + else if (version == IPC_64) err2 = put_compat_shmid64_ds(&s64, uptr); - } else { + else err2 = put_compat_shmid_ds(&s64, uptr); - } if (err2) err = -EFAULT; break; case SHM_INFO: - err = do_shmctl(first, second, &si); + p = compat_alloc_user_space(sizeof(struct shm_info)); + err = sys_shmctl(first, second, p); if (err < 0) break; - err2 = put_compat_shm_info(&si, uptr); + err2 = put_compat_shm_info(p, uptr); if (err2) err = -EFAULT; break; @@ -712,24 +674,14 @@ long compat_sys_shmctl(int first, int se long compat_sys_semtimedop(int semid, struct sembuf __user *tsems, unsigned nsops, const struct compat_timespec __user *timeout) { - struct timespec ts; - struct timespec __user *ts64; - - /* parameter checking precedence should mirror sys_semtimedop() */ - if (nsops < 1 || semid < 0) - return -EINVAL; - if (nsops > sc_semopm) - return -E2BIG; - if (!access_ok(VERIFY_READ, tsems, nsops * sizeof(struct sembuf))) - return -EFAULT; - if (!timeout) - return sys_semtimedop(semid, tsems, nsops, 0); - - ts64 = compat_alloc_user_space(sizeof(*ts64)); - if (get_compat_timespec(&ts, timeout)) - return -EFAULT; - if (copy_to_user(ts64, &ts, sizeof(ts))) - return -EFAULT; - + struct timespec __user *ts64 = NULL; + if (timeout) { + struct timespec ts; + ts64 = compat_alloc_user_space(sizeof(*ts64)); + if (get_compat_timespec(&ts, timeout)) + return -EFAULT; + if (copy_to_user(ts64, &ts, sizeof(ts))) + return -EFAULT; + } return sys_semtimedop(semid, tsems, nsops, ts64); } --- linux-2.6.8-rc1/ipc/compat_mq.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/ipc/compat_mq.c 2004-07-13 17:09:13.000000000 -0700 @@ -50,45 +50,29 @@ asmlinkage long compat_sys_mq_open(const int oflag, compat_mode_t mode, struct compat_mq_attr __user *u_attr) { - struct mq_attr attr; - mm_segment_t oldfs; - char *name; - long ret; - - if ((oflag & O_CREAT) == 0 || !u_attr) - return sys_mq_open(u_name, oflag, mode, 0); - - if (get_compat_mq_attr(&attr, u_attr)) - return -EFAULT; - - name = getname(u_name); - if (IS_ERR(name)) - return PTR_ERR(name); - - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_mq_open(name, oflag, mode, &attr); - set_fs(oldfs); - - putname(name); - return ret; + void __user *p = NULL; + if (u_attr && oflag & O_CREAT) { + struct mq_attr attr; + p = compat_alloc_user_space(sizeof(attr)); + if (get_compat_mq_attr(&attr, u_attr) || + copy_to_user(p, &attr, sizeof(attr))) + return -EFAULT; + } + return sys_mq_open(u_name, oflag, mode, p); } -static struct timespec __user *compat_prepare_timeout( - const struct compat_timespec __user *u_abs_timeout) +static int compat_prepare_timeout(struct timespec __user * *p, + const struct compat_timespec __user *u) { struct timespec ts; - struct timespec __user *u_ts; - - if (!u_abs_timeout) + if (!u) { + *p = NULL; return 0; - - u_ts = compat_alloc_user_space(sizeof(*u_ts)); - if (get_compat_timespec(&ts, u_abs_timeout) - || copy_to_user(u_ts, &ts, sizeof(*u_ts))) - return ERR_PTR(-EFAULT); - - return u_ts; + } + *p = compat_alloc_user_space(sizeof(ts)); + if (get_compat_timespec(&ts, u) || copy_to_user(*p, &ts, sizeof(ts))) + return -EFAULT; + return 0; } asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes, @@ -98,8 +82,7 @@ asmlinkage long compat_sys_mq_timedsend( { struct timespec __user *u_ts; - u_ts = compat_prepare_timeout(u_abs_timeout); - if (IS_ERR(u_ts)) + if (compat_prepare_timeout(&u_ts, u_abs_timeout)) return -EFAULT; return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len, @@ -112,9 +95,7 @@ asmlinkage ssize_t compat_sys_mq_timedre const struct compat_timespec __user *u_abs_timeout) { struct timespec __user *u_ts; - - u_ts = compat_prepare_timeout(u_abs_timeout); - if (IS_ERR(u_ts)) + if (compat_prepare_timeout(&u_ts, u_abs_timeout)) return -EFAULT; return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len, @@ -138,60 +119,42 @@ static int get_compat_sigevent(struct si asmlinkage long compat_sys_mq_notify(mqd_t mqdes, const struct compat_sigevent __user *u_notification) { - mm_segment_t oldfs; - struct sigevent notification; - char cookie[NOTIFY_COOKIE_LEN]; - compat_uptr_t u_cookie; - long ret; - - if (!u_notification) - return sys_mq_notify(mqdes, 0); - - if (get_compat_sigevent(¬ification, u_notification)) - return -EFAULT; - - if (notification.sigev_notify == SIGEV_THREAD) { - u_cookie = (compat_uptr_t)notification.sigev_value.sival_int; - if (copy_from_user(cookie, compat_ptr(u_cookie), - NOTIFY_COOKIE_LEN)) { + struct sigevent __user *p = NULL; + if (u_notification) { + struct sigevent n; + p = compat_alloc_user_space(sizeof(*p)); + if (get_compat_sigevent(&n, u_notification)) + return -EFAULT; + if (n.sigev_notify == SIGEV_THREAD) + n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int); + if (copy_to_user(p, &n, sizeof(*p))) return -EFAULT; - } - notification.sigev_value.sival_ptr = cookie; } - - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_mq_notify(mqdes, ¬ification); - set_fs(oldfs); - - return ret; + return sys_mq_notify(mqdes, p); } asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, const struct compat_mq_attr __user *u_mqstat, struct compat_mq_attr __user *u_omqstat) { - struct mq_attr mqstat, omqstat; - struct mq_attr *p_mqstat = 0, *p_omqstat = 0; - mm_segment_t oldfs; + struct mq_attr mqstat; + struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p)); long ret; if (u_mqstat) { - p_mqstat = &mqstat; - if (get_compat_mq_attr(p_mqstat, u_mqstat)) + if (get_compat_mq_attr(&mqstat, u_mqstat) || + copy_to_user(p, &mqstat, sizeof(mqstat))) return -EFAULT; } - - if (u_omqstat) - p_omqstat = &omqstat; - - oldfs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_mq_getsetattr(mqdes, p_mqstat, p_omqstat); - set_fs(oldfs); - + ret = sys_mq_getsetattr(mqdes, + u_mqstat ? p : NULL, + u_omqstat ? p + 1 : NULL); if (ret) return ret; - - return (u_omqstat) ? put_compat_mq_attr(&omqstat, u_omqstat) : 0; + if (u_omqstat) { + if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) || + put_compat_mq_attr(&mqstat, u_omqstat)) + return -EFAULT; + } + return 0; } --- linux-2.6.8-rc1/ipc/msg.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/ipc/msg.c 2004-07-13 17:09:43.000000000 -0700 @@ -100,14 +100,14 @@ static int newque (key_t key, int msgflg msq->q_perm.security = NULL; retval = security_msg_queue_alloc(msq); if (retval) { - ipc_rcu_free(msq, sizeof(*msq)); + ipc_rcu_putref(msq); return retval; } id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); if(id == -1) { security_msg_queue_free(msq); - ipc_rcu_free(msq, sizeof(*msq)); + ipc_rcu_putref(msq); return -ENOSPC; } @@ -163,8 +163,10 @@ static void expunge_all(struct msg_queue msr = list_entry(tmp,struct msg_receiver,r_list); tmp = tmp->next; - msr->r_msg = ERR_PTR(res); + msr->r_msg = NULL; wake_up_process(msr->r_tsk); + smp_mb(); + msr->r_msg = ERR_PTR(res); } } /* @@ -193,7 +195,7 @@ static void freeque (struct msg_queue *m } atomic_sub(msq->q_cbytes, &msg_bytes); security_msg_queue_free(msq); - ipc_rcu_free(msq, sizeof(struct msg_queue)); + ipc_rcu_putref(msq); } asmlinkage long sys_msgget (key_t key, int msgflg) @@ -525,13 +527,17 @@ static inline int pipelined_send(struct !security_msg_queue_msgrcv(msq, msg, msr->r_tsk, msr->r_msgtype, msr->r_mode)) { list_del(&msr->r_list); if(msr->r_maxsize < msg->m_ts) { - msr->r_msg = ERR_PTR(-E2BIG); + msr->r_msg = NULL; wake_up_process(msr->r_tsk); + smp_mb(); + msr->r_msg = ERR_PTR(-E2BIG); } else { - msr->r_msg = msg; + msr->r_msg = NULL; msq->q_lrpid = msr->r_tsk->pid; msq->q_rtime = get_seconds(); wake_up_process(msr->r_tsk); + smp_mb(); + msr->r_msg = msg; return 1; } } @@ -564,43 +570,49 @@ asmlinkage long sys_msgsnd (int msqid, s err=-EINVAL; if(msq==NULL) goto out_free; -retry: + err= -EIDRM; if (msg_checkid(msq,msqid)) goto out_unlock_free; - err=-EACCES; - if (ipcperms(&msq->q_perm, S_IWUGO)) - goto out_unlock_free; + for (;;) { + struct msg_sender s; - err = security_msg_queue_msgsnd(msq, msg, msgflg); - if (err) - goto out_unlock_free; + err=-EACCES; + if (ipcperms(&msq->q_perm, S_IWUGO)) + goto out_unlock_free; - if(msgsz + msq->q_cbytes > msq->q_qbytes || - 1 + msq->q_qnum > msq->q_qbytes) { - struct msg_sender s; + err = security_msg_queue_msgsnd(msq, msg, msgflg); + if (err) + goto out_unlock_free; + if(msgsz + msq->q_cbytes <= msq->q_qbytes && + 1 + msq->q_qnum <= msq->q_qbytes) { + break; + } + + /* queue full, wait: */ if(msgflg&IPC_NOWAIT) { err=-EAGAIN; goto out_unlock_free; } ss_add(msq, &s); + ipc_rcu_getref(msq); msg_unlock(msq); schedule(); - current->state= TASK_RUNNING; - msq = msg_lock(msqid); - err = -EIDRM; - if(msq==NULL) - goto out_free; + ipc_lock_by_ptr(&msq->q_perm); + ipc_rcu_putref(msq); + if (msq->q_perm.deleted) { + err = -EIDRM; + goto out_unlock_free; + } ss_del(&s); if (signal_pending(current)) { - err=-EINTR; + err=-ERESTARTNOHAND; goto out_unlock_free; } - goto retry; } msq->q_lspid = current->tgid; @@ -649,10 +661,7 @@ asmlinkage long sys_msgrcv (int msqid, s long msgtyp, int msgflg) { struct msg_queue *msq; - struct msg_receiver msr_d; - struct list_head* tmp; - struct msg_msg* msg, *found_msg; - int err; + struct msg_msg *msg; int mode; if (msqid < 0 || (long) msgsz < 0) @@ -662,62 +671,57 @@ asmlinkage long sys_msgrcv (int msqid, s msq = msg_lock(msqid); if(msq==NULL) return -EINVAL; -retry: - err = -EIDRM; + + msg = ERR_PTR(-EIDRM); if (msg_checkid(msq,msqid)) goto out_unlock; - err=-EACCES; - if (ipcperms (&msq->q_perm, S_IRUGO)) - goto out_unlock; + for (;;) { + struct msg_receiver msr_d; + struct list_head* tmp; - tmp = msq->q_messages.next; - found_msg=NULL; - while (tmp != &msq->q_messages) { - msg = list_entry(tmp,struct msg_msg,m_list); - if(testmsg(msg,msgtyp,mode) && - !security_msg_queue_msgrcv(msq, msg, current, msgtyp, mode)) { - found_msg = msg; - if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) { - found_msg=msg; - msgtyp=msg->m_type-1; - } else { - found_msg=msg; - break; - } - } - tmp = tmp->next; - } - if(found_msg) { - msg=found_msg; - if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { - err=-E2BIG; + msg = ERR_PTR(-EACCES); + if (ipcperms (&msq->q_perm, S_IRUGO)) goto out_unlock; + + msg = ERR_PTR(-EAGAIN); + tmp = msq->q_messages.next; + while (tmp != &msq->q_messages) { + struct msg_msg *walk_msg; + walk_msg = list_entry(tmp,struct msg_msg,m_list); + if(testmsg(walk_msg,msgtyp,mode) && + !security_msg_queue_msgrcv(msq, walk_msg, current, msgtyp, mode)) { + msg = walk_msg; + if(mode == SEARCH_LESSEQUAL && walk_msg->m_type != 1) { + msg=walk_msg; + msgtyp=walk_msg->m_type-1; + } else { + msg=walk_msg; + break; + } + } + tmp = tmp->next; } - list_del(&msg->m_list); - msq->q_qnum--; - msq->q_rtime = get_seconds(); - msq->q_lrpid = current->tgid; - msq->q_cbytes -= msg->m_ts; - atomic_sub(msg->m_ts,&msg_bytes); - atomic_dec(&msg_hdrs); - ss_wakeup(&msq->q_senders,0); - msg_unlock(msq); -out_success: - msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; - if (put_user (msg->m_type, &msgp->mtype) || - store_msg(msgp->mtext, msg, msgsz)) { - msgsz = -EFAULT; + if(!IS_ERR(msg)) { + /* Found a suitable message. Unlink it from the queue. */ + if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { + msg = ERR_PTR(-E2BIG); + goto out_unlock; + } + list_del(&msg->m_list); + msq->q_qnum--; + msq->q_rtime = get_seconds(); + msq->q_lrpid = current->tgid; + msq->q_cbytes -= msg->m_ts; + atomic_sub(msg->m_ts,&msg_bytes); + atomic_dec(&msg_hdrs); + ss_wakeup(&msq->q_senders,0); + msg_unlock(msq); + break; } - free_msg(msg); - return msgsz; - } else - { - /* no message waiting. Prepare for pipelined - * receive. - */ + /* No message waiting. Wait for a message */ if (msgflg & IPC_NOWAIT) { - err=-ENOMSG; + msg = ERR_PTR(-ENOMSG); goto out_unlock; } list_add_tail(&msr_d.r_list,&msq->q_receivers); @@ -727,52 +731,76 @@ out_success: if(msgflg & MSG_NOERROR) msr_d.r_maxsize = INT_MAX; else - msr_d.r_maxsize = msgsz; + msr_d.r_maxsize = msgsz; msr_d.r_msg = ERR_PTR(-EAGAIN); current->state = TASK_INTERRUPTIBLE; msg_unlock(msq); schedule(); - /* - * The below optimisation is buggy. A sleeping thread that is - * woken up checks if it got a message and if so, copies it to - * userspace and just returns without taking any locks. - * But this return to user space can be faster than the message - * send, and if the receiver immediately exits the - * wake_up_process performed by the sender will oops. + /* Lockless receive, part 1: + * Disable preemption. We don't hold a reference to the queue + * and getting a reference would defeat the idea of a lockless + * operation, thus the code relies on rcu to guarantee the + * existance of msq: + * Prior to destruction, expunge_all(-EIRDM) changes r_msg. + * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. + * rcu_read_lock() prevents preemption between reading r_msg + * and the spin_lock() inside ipc_lock_by_ptr(). + */ + rcu_read_lock(); + + /* Lockless receive, part 2: + * Wait until pipelined_send or expunge_all are outside of + * wake_up_process(). There is a race with exit(), see + * ipc/mqueue.c for the details. */ -#if 0 msg = (struct msg_msg*) msr_d.r_msg; - if(!IS_ERR(msg)) - goto out_success; -#endif + while (msg == NULL) { + cpu_relax(); + msg = (struct msg_msg*) msr_d.r_msg; + } - msq = msg_lock(msqid); + /* Lockless receive, part 3: + * If there is a message or an error then accept it without + * locking. + */ + if(msg != ERR_PTR(-EAGAIN)) { + rcu_read_unlock(); + break; + } + + /* Lockless receive, part 3: + * Acquire the queue spinlock. + */ + ipc_lock_by_ptr(&msq->q_perm); + rcu_read_unlock(); + + /* Lockless receive, part 4: + * Repeat test after acquiring the spinlock. + */ msg = (struct msg_msg*)msr_d.r_msg; - if(!IS_ERR(msg)) { - /* our message arived while we waited for - * the spinlock. Process it. - */ - if(msq) - msg_unlock(msq); - goto out_success; - } - err = PTR_ERR(msg); - if(err == -EAGAIN) { - if(!msq) - BUG(); - list_del(&msr_d.r_list); - if (signal_pending(current)) - err=-EINTR; - else - goto retry; + if(msg != ERR_PTR(-EAGAIN)) + goto out_unlock; + + list_del(&msr_d.r_list); + if (signal_pending(current)) { + msg = ERR_PTR(-ERESTARTNOHAND); +out_unlock: + msg_unlock(msq); + break; } } -out_unlock: - if(msq) - msg_unlock(msq); - return err; + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; + if (put_user (msg->m_type, &msgp->mtype) || + store_msg(msgp->mtext, msg, msgsz)) { + msgsz = -EFAULT; + } + free_msg(msg); + return msgsz; } #ifdef CONFIG_PROC_FS --- linux-2.6.8-rc1/ipc/sem.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/ipc/sem.c 2004-07-13 17:09:43.000000000 -0700 @@ -179,14 +179,14 @@ static int newary (key_t key, int nsems, sma->sem_perm.security = NULL; retval = security_sem_alloc(sma); if (retval) { - ipc_rcu_free(sma, size); + ipc_rcu_putref(sma); return retval; } id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); if(id == -1) { security_sem_free(sma); - ipc_rcu_free(sma, size); + ipc_rcu_putref(sma); return -ENOSPC; } used_sems += nsems; @@ -241,25 +241,6 @@ asmlinkage long sys_semget (key_t key, i return err; } -/* doesn't acquire the sem_lock on error! */ -static int sem_revalidate(int semid, struct sem_array* sma, int nsems, short flg) -{ - struct sem_array* smanew; - - smanew = sem_lock(semid); - if(smanew==NULL) - return -EIDRM; - if(smanew != sma || sem_checkid(sma,semid) || sma->sem_nsems != nsems) { - sem_unlock(smanew); - return -EIDRM; - } - - if (flg && ipcperms(&sma->sem_perm, flg)) { - sem_unlock(smanew); - return -EACCES; - } - return 0; -} /* Manage the doubly linked list sma->sem_pending as a FIFO: * insert new queue elements at the tail sma->sem_pending_last. */ @@ -473,7 +454,7 @@ static void freeary (struct sem_array *s used_sems -= sma->sem_nsems; size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); security_sem_free(sma); - ipc_rcu_free(sma, size); + ipc_rcu_putref(sma); } static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version) @@ -614,13 +595,24 @@ static int semctl_main(int semid, int se int i; if(nsems > SEMMSL_FAST) { + ipc_rcu_getref(sma); sem_unlock(sma); + sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) + if(sem_io == NULL) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); return -ENOMEM; - err = sem_revalidate(semid, sma, nsems, S_IRUGO); - if(err) + } + + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + if (sma->sem_perm.deleted) { + sem_unlock(sma); + err = -EIDRM; goto out_free; + } } for (i = 0; i < sma->sem_nsems; i++) @@ -636,28 +628,43 @@ static int semctl_main(int semid, int se int i; struct sem_undo *un; + ipc_rcu_getref(sma); sem_unlock(sma); if(nsems > SEMMSL_FAST) { sem_io = ipc_alloc(sizeof(ushort)*nsems); - if(sem_io == NULL) + if(sem_io == NULL) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); return -ENOMEM; + } } if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); err = -EFAULT; goto out_free; } for (i = 0; i < nsems; i++) { if (sem_io[i] > SEMVMX) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); err = -ERANGE; goto out_free; } } - err = sem_revalidate(semid, sma, nsems, S_IWUGO); - if(err) + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + if (sma->sem_perm.deleted) { + sem_unlock(sma); + err = -EIDRM; goto out_free; + } for (i = 0; i < nsems; i++) sma->sem_base[i].semval = sem_io[i]; @@ -977,11 +984,16 @@ static struct sem_undo *find_undo(int se goto out; } nsems = sma->sem_nsems; + ipc_rcu_getref(sma); sem_unlock(sma); new = (struct sem_undo *) kmalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); - if (!new) + if (!new) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); return ERR_PTR(-ENOMEM); + } memset(new, 0, sizeof(struct sem_undo) + sizeof(short)*nsems); new->semadj = (short *) &new[1]; new->semid = semid; @@ -991,13 +1003,18 @@ static struct sem_undo *find_undo(int se if (un) { unlock_semundo(); kfree(new); + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + sem_unlock(sma); goto out; } - error = sem_revalidate(semid, sma, nsems, 0); - if (error) { + ipc_lock_by_ptr(&sma->sem_perm); + ipc_rcu_putref(sma); + if (sma->sem_perm.deleted) { + sem_unlock(sma); unlock_semundo(); kfree(new); - un = ERR_PTR(error); + un = ERR_PTR(-EIDRM); goto out; } new->proc_next = ulp->proc_list; @@ -1269,8 +1286,23 @@ found: struct sem * sem = &sma->sem_base[i]; if (u->semadj[i]) { sem->semval += u->semadj[i]; + /* + * Range checks of the new semaphore value, + * not defined by sus: + * - Some unices ignore the undo entirely + * (e.g. HP UX 11i 11.22, Tru64 V5.1) + * - some cap the value (e.g. FreeBSD caps + * at 0, but doesn't enforce SEMVMX) + * + * Linux caps the semaphore value, both at 0 + * and at SEMVMX. + * + * Manfred + */ if (sem->semval < 0) - sem->semval = 0; /* shouldn't happen */ + sem->semval = 0; + if (sem->semval > SEMVMX) + sem->semval = SEMVMX; sem->sempid = current->tgid; } } --- linux-2.6.8-rc1/ipc/shm.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/ipc/shm.c 2004-07-13 17:09:43.000000000 -0700 @@ -117,7 +117,7 @@ static void shm_destroy (struct shmid_ke shmem_lock(shp->shm_file, 0); fput (shp->shm_file); security_shm_free(shp); - ipc_rcu_free(shp, sizeof(struct shmid_kernel)); + ipc_rcu_putref(shp); } /* @@ -194,7 +194,7 @@ static int newseg (key_t key, int shmflg shp->shm_perm.security = NULL; error = security_shm_alloc(shp); if (error) { - ipc_rcu_free(shp, sizeof(*shp)); + ipc_rcu_putref(shp); return error; } @@ -234,7 +234,7 @@ no_id: fput(file); no_file: security_shm_free(shp); - ipc_rcu_free(shp, sizeof(*shp)); + ipc_rcu_putref(shp); return error; } --- linux-2.6.8-rc1/ipc/util.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/ipc/util.c 2004-07-13 17:09:43.000000000 -0700 @@ -135,7 +135,6 @@ static int grow_ary(struct ipc_ids* ids, new[i].p = NULL; } old = ids->entries; - i = ids->size; /* * before setting the ids->entries to the new array, there must be a @@ -147,7 +146,7 @@ static int grow_ary(struct ipc_ids* ids, smp_wmb(); /* prevent indexing into old array based on new size. */ ids->size = newsize; - ipc_rcu_free(old, sizeof(struct ipc_id)*i); + ipc_rcu_putref(old); return ids->size; } @@ -277,25 +276,47 @@ void ipc_free(void* ptr, int size) kfree(ptr); } -struct ipc_rcu_kmalloc +/* + * rcu allocations: + * There are three headers that are prepended to the actual allocation: + * - during use: ipc_rcu_hdr. + * - during the rcu grace period: ipc_rcu_grace. + * - [only if vmalloc]: ipc_rcu_sched. + * Their lifetime doesn't overlap, thus the headers share the same memory. + * Unlike a normal union, they are right-aligned, thus some container_of + * forward/backward casting is necessary: + */ +struct ipc_rcu_hdr +{ + int refcount; + int is_vmalloc; + void *data[0]; +}; + + +struct ipc_rcu_grace { struct rcu_head rcu; /* "void *" makes sure alignment of following data is sane. */ void *data[0]; }; -struct ipc_rcu_vmalloc +struct ipc_rcu_sched { - struct rcu_head rcu; struct work_struct work; /* "void *" makes sure alignment of following data is sane. */ void *data[0]; }; +#define HDRLEN_KMALLOC (sizeof(struct ipc_rcu_grace) > sizeof(struct ipc_rcu_hdr) ? \ + sizeof(struct ipc_rcu_grace) : sizeof(struct ipc_rcu_hdr)) +#define HDRLEN_VMALLOC (sizeof(struct ipc_rcu_sched) > HDRLEN_KMALLOC ? \ + sizeof(struct ipc_rcu_sched) : HDRLEN_KMALLOC) + static inline int rcu_use_vmalloc(int size) { /* Too big for a single page? */ - if (sizeof(struct ipc_rcu_kmalloc) + size > PAGE_SIZE) + if (HDRLEN_KMALLOC + size > PAGE_SIZE) return 1; return 0; } @@ -317,16 +338,29 @@ void* ipc_rcu_alloc(int size) * workqueue if necessary (for vmalloc). */ if (rcu_use_vmalloc(size)) { - out = vmalloc(sizeof(struct ipc_rcu_vmalloc) + size); - if (out) out += sizeof(struct ipc_rcu_vmalloc); + out = vmalloc(HDRLEN_VMALLOC + size); + if (out) { + out += HDRLEN_VMALLOC; + container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1; + container_of(out, struct ipc_rcu_hdr, data)->refcount = 1; + } } else { - out = kmalloc(sizeof(struct ipc_rcu_kmalloc)+size, GFP_KERNEL); - if (out) out += sizeof(struct ipc_rcu_kmalloc); + out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL); + if (out) { + out += HDRLEN_KMALLOC; + container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0; + container_of(out, struct ipc_rcu_hdr, data)->refcount = 1; + } } return out; } +void ipc_rcu_getref(void *ptr) +{ + container_of(ptr, struct ipc_rcu_hdr, data)->refcount++; +} + /** * ipc_schedule_free - free ipc + rcu space * @@ -335,11 +369,13 @@ void* ipc_rcu_alloc(int size) */ static void ipc_schedule_free(struct rcu_head *head) { - struct ipc_rcu_vmalloc *free = - container_of(head, struct ipc_rcu_vmalloc, rcu); + struct ipc_rcu_grace *grace = + container_of(head, struct ipc_rcu_grace, rcu); + struct ipc_rcu_sched *sched = + container_of(&(grace->data[0]), struct ipc_rcu_sched, data[0]); - INIT_WORK(&free->work, vfree, free); - schedule_work(&free->work); + INIT_WORK(&sched->work, vfree, sched); + schedule_work(&sched->work); } /** @@ -350,25 +386,23 @@ static void ipc_schedule_free(struct rcu */ static void ipc_immediate_free(struct rcu_head *head) { - struct ipc_rcu_kmalloc *free = - container_of(head, struct ipc_rcu_kmalloc, rcu); + struct ipc_rcu_grace *free = + container_of(head, struct ipc_rcu_grace, rcu); kfree(free); } - - -void ipc_rcu_free(void* ptr, int size) +void ipc_rcu_putref(void *ptr) { - if (rcu_use_vmalloc(size)) { - struct ipc_rcu_vmalloc *free; - free = ptr - sizeof(*free); - call_rcu(&free->rcu, ipc_schedule_free); + if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0) + return; + + if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) { + call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu, + ipc_schedule_free); } else { - struct ipc_rcu_kmalloc *free; - free = ptr - sizeof(*free); - call_rcu(&free->rcu, ipc_immediate_free); + call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu, + ipc_immediate_free); } - } /** @@ -506,6 +540,12 @@ struct kern_ipc_perm* ipc_lock(struct ip return out; } +void ipc_lock_by_ptr(struct kern_ipc_perm *perm) +{ + rcu_read_lock(); + spin_lock(&perm->lock); +} + void ipc_unlock(struct kern_ipc_perm* perm) { spin_unlock(&perm->lock); --- linux-2.6.8-rc1/ipc/util.h 2004-06-15 23:29:48.000000000 -0700 +++ 25/ipc/util.h 2004-07-13 17:09:43.000000000 -0700 @@ -45,14 +45,20 @@ int ipcperms (struct kern_ipc_perm *ipcp */ void* ipc_alloc(int size); void ipc_free(void* ptr, int size); -/* for allocation that need to be freed by RCU - * both function can sleep + +/* + * For allocation that need to be freed by RCU. + * Objects are reference counted, they start with reference count 1. + * getref increases the refcount, the putref call that reduces the recount + * to 0 schedules the rcu destruction. Caller must guarantee locking. */ void* ipc_rcu_alloc(int size); -void ipc_rcu_free(void* arg, int size); +void ipc_rcu_getref(void *ptr); +void ipc_rcu_putref(void *ptr); struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id); struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id); +void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp); void ipc_unlock(struct kern_ipc_perm* perm); int ipc_buildid(struct ipc_ids* ids, int id, int seq); int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid); --- linux-2.6.8-rc1/kernel/exit.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/kernel/exit.c 2004-07-13 17:09:51.000000000 -0700 @@ -56,8 +56,6 @@ void release_task(struct task_struct * p struct dentry *proc_dentry; repeat: - BUG_ON(p->state < TASK_ZOMBIE); - atomic_dec(&p->user->processes); spin_lock(&p->proc_lock); proc_dentry = proc_pid_unhash(p); @@ -296,7 +294,7 @@ int allow_signal(int sig) Let the signal code know it'll be handled, so that they don't get converted to SIGKILL or just silently dropped */ - current->sighand->action[(sig)-1].sa.sa_handler = (void *)2; + current->sighand->action[(sig)-1].sa.sa_handler = (void __user *)2; } recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -755,9 +753,8 @@ static void exit_notify(struct task_stru state = TASK_ZOMBIE; if (tsk->exit_signal == -1 && tsk->ptrace == 0) state = TASK_DEAD; - tsk->state = state; - tsk->flags |= PF_DEAD; - + else + tsk->state = state; /* * Clear these here so that update_process_times() won't try to deliver * itimer, profile or rlimit signals to this task while it is in late exit. @@ -767,19 +764,14 @@ static void exit_notify(struct task_stru tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY; /* - * In the preemption case it must be impossible for the task - * to get runnable again, so use "_raw_" unlock to keep - * preempt_count elevated until we schedule(). - * - * To avoid deadlock on SMP, interrupts must be unmasked. If we - * don't, subsequently called functions (e.g, wait_task_inactive() - * via release_task()) will spin, with interrupt flags - * unwittingly blocked, until the other task sleeps. That task - * may itself be waiting for smp_call_function() to answer and - * complete, and with interrupts blocked that will never happen. + * Get a reference to it so that we can set the state + * as the last step. The state-setting only matters if the + * current task is releasing itself, to trigger the final + * put_task_struct() in finish_task_switch(). (thread self-reap) */ - _raw_write_unlock(&tasklist_lock); - local_irq_enable(); + get_task_struct(tsk); + + write_unlock_irq(&tasklist_lock); list_for_each_safe(_p, _n, &ptrace_dead) { list_del_init(_p); @@ -788,9 +780,17 @@ static void exit_notify(struct task_stru } /* If the process is dead, release it - nobody will wait for it */ - if (state == TASK_DEAD) + if (state == TASK_DEAD) { release_task(tsk); + write_lock_irq(&tasklist_lock); + tsk->state = state; + _raw_write_unlock(&tasklist_lock); + local_irq_enable(); + } else + preempt_disable(); + tsk->flags |= PF_DEAD; + put_task_struct(tsk); } asmlinkage NORET_TYPE void do_exit(long code) --- linux-2.6.8-rc1/kernel/fork.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/kernel/fork.c 2004-07-13 17:09:38.000000000 -0700 @@ -279,7 +279,7 @@ static inline int dup_mmap(struct mm_str mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; - mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->free_area_cache = oldmm->mmap_base; mm->map_count = 0; mm->rss = 0; cpus_clear(mm->cpu_vm_mask); @@ -1033,6 +1033,17 @@ struct task_struct *copy_process(unsigne /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); + + /* + * The task hasn't been attached yet, so cpus_allowed mask cannot + * have changed. The cpus_allowed mask of the parent may have + * changed after it was copied first time, and it may then move to + * another CPU - so we re-copy it here and set the child's CPU to + * the parent's CPU. This avoids alot of nasty races. + */ + p->cpus_allowed = current->cpus_allowed; + set_task_cpu(p, smp_processor_id()); + /* * Check for pending SIGKILL! The new thread should not be allowed * to slip out of an OOM kill. (or normal SIGKILL.) @@ -1204,32 +1215,13 @@ long do_fork(unsigned long clone_flags, set_tsk_thread_flag(p, TIF_SIGPENDING); } - if (!(clone_flags & CLONE_STOPPED)) { - /* - * Do the wakeup last. On SMP we treat fork() and - * CLONE_VM separately, because fork() has already - * created cache footprint on this CPU (due to - * copying the pagetables), hence migration would - * probably be costy. Threads on the other hand - * have less traction to the current CPU, and if - * there's an imbalance then the scheduler can - * migrate this fresh thread now, before it - * accumulates a larger cache footprint: - */ - if (clone_flags & CLONE_VM) - wake_up_forked_thread(p); + if (likely(!(clone_flags & CLONE_IDLETASK))) { + if (!(clone_flags & CLONE_STOPPED)) + wake_up_new_task(p, clone_flags); else - wake_up_forked_process(p); - } else { - int cpu = get_cpu(); - - p->state = TASK_STOPPED; - if (cpu_is_offline(task_cpu(p))) - set_task_cpu(p, cpu); - - put_cpu(); + p->state = TASK_STOPPED; + ++total_forks; } - ++total_forks; if (unlikely (trace)) { current->ptrace_message = pid; @@ -1240,12 +1232,7 @@ long do_fork(unsigned long clone_flags, wait_for_completion(&vfork); if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); - } else - /* - * Let the child process run first, to avoid most of the - * COW overhead when the child exec()s afterwards. - */ - set_need_resched(); + } } return pid; } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/kernel/lockmeter.c 2004-07-13 17:09:29.000000000 -0700 @@ -0,0 +1,1178 @@ +/* + * Copyright (C) 1999,2000 Silicon Graphics, Inc. + * + * Written by John Hawkes (hawkes@sgi.com) + * Based on klstat.c by Jack Steiner (steiner@sgi.com) + * + * Modified by Ray Bryant (raybry@us.ibm.com) + * Changes Copyright (C) 2000 IBM, Inc. + * Added save of index in spinlock_t to improve efficiency + * of "hold" time reporting for spinlocks + * Added support for hold time statistics for read and write + * locks. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ASSERT(cond) +#define bzero(loc,size) memset(loc,0,size) + +/*<---------------------------------------------------*/ +/* lockmeter.c */ +/*>---------------------------------------------------*/ + +static lstat_control_t lstat_control __cacheline_aligned = + { LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED, + 19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 }; + +static ushort lstat_make_dir_entry(void *, void *); + +/* + * lstat_lookup + * + * Given a RA, locate the directory entry for the lock. + */ +static ushort +lstat_lookup(void *lock_ptr, void *caller_ra) +{ + ushort index; + lstat_directory_entry_t *dirp; + + dirp = lstat_control.dir; + + index = lstat_control.hashtab[DIRHASH(caller_ra)]; + while (dirp[index].caller_ra != caller_ra) { + if (index == 0) { + return lstat_make_dir_entry(lock_ptr, caller_ra); + } + index = dirp[index].next_stat_index; + } + + if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) { + dirp[index].lock_ptr = NULL; + } + + return index; +} + +/* + * lstat_make_dir_entry + * Called to add a new lock to the lock directory. + */ +static ushort +lstat_make_dir_entry(void *lock_ptr, void *caller_ra) +{ + lstat_directory_entry_t *dirp; + ushort index, hindex; + unsigned long flags; + + /* lock the table without recursively reentering this metering code */ + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + hindex = DIRHASH(caller_ra); + index = lstat_control.hashtab[hindex]; + dirp = lstat_control.dir; + while (index && dirp[index].caller_ra != caller_ra) + index = dirp[index].next_stat_index; + + if (index == 0) { + if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) { + index = lstat_control.next_free_dir_index++; + lstat_control.dir[index].caller_ra = caller_ra; + lstat_control.dir[index].lock_ptr = lock_ptr; + lstat_control.dir[index].next_stat_index = + lstat_control.hashtab[hindex]; + lstat_control.hashtab[hindex] = index; + } else { + lstat_control.dir_overflow++; + } + } + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +int +lstat_update(void *lock_ptr, void *caller_ra, int action) +{ + int index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +int +lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks) +{ + ushort index; + int cpu; + + ASSERT(action < LSTAT_ACT_MAX_VALUES); + + if (lstat_control.state == LSTAT_OFF) + return 0; + + index = lstat_lookup(lock_ptr, caller_ra); + cpu = THIS_CPU_NUMBER; + (*lstat_control.counts[cpu])[index].count[action]++; + (*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks; + if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks) + (*lstat_control.counts[cpu])[index].max_wait_ticks = ticks; + + (*lstat_control.counts[cpu])[index].acquire_time = get_cycles(); + + return index; +} + +void +_metered_spin_lock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + _raw_spin_lock(lock_ptr); /* do the real lock */ + PUT_INDEX(lock_ptr, 0); /* clean index in case lockmetering */ + /* gets turned on before unlock */ + } else { + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + int index; + + if (_raw_spin_trylock(lock_ptr)) { + index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + } else { + uint32_t start_cycles = get_cycles(); + _raw_spin_lock(lock_ptr); /* do the real lock */ + index = lstat_update_time(lock_ptr, this_pc, + LSTAT_ACT_SPIN, get_cycles() - start_cycles); + } + /* save the index in the lock itself for use in spin unlock */ + PUT_INDEX(lock_ptr, index); + } +} + +int +_metered_spin_trylock(spinlock_t * lock_ptr) +{ + if (lstat_control.state == LSTAT_OFF) { + return _raw_spin_trylock(lock_ptr); + } else { + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_SPIN); + + if ((retval = _raw_spin_trylock(lock_ptr))) { + int index = lstat_update(lock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* + * save the index in the lock itself for use in spin + * unlock + */ + PUT_INDEX(lock_ptr, index); + } else { + lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; + } +} + +void +_metered_spin_unlock(spinlock_t * lock_ptr) +{ + int index = -1; + + if (lstat_control.state != LSTAT_OFF) { + index = GET_INDEX(lock_ptr); + /* + * If statistics were turned off when we set the lock, + * then the index can be zero. If that is the case, + * then collect no stats on this call. + */ + if (index > 0) { + uint32_t hold_time; + int cpu = THIS_CPU_NUMBER; + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[index].acquire_time; + (*lstat_control.counts[cpu])[index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[index]. + max_hold_ticks = hold_time; + } + } + + /* make sure we don't have a stale index value saved */ + PUT_INDEX(lock_ptr, 0); + _raw_spin_unlock(lock_ptr); /* do the real unlock */ +} + +/* + * allocate the next global read lock structure and store its index + * in the rwlock at "lock_ptr". + */ +uint32_t +alloc_rwlock_struct(rwlock_t * rwlock_ptr) +{ + int index; + unsigned long flags; + int cpu = THIS_CPU_NUMBER; + + /* If we've already overflowed, then do a quick exit */ + if (lstat_control.next_free_read_lock_index > + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + return 0; + } + + local_irq_save(flags); + _raw_spin_lock(&lstat_control.directory_lock); + + /* It is possible this changed while we were waiting for the directory_lock */ + if (lstat_control.state == LSTAT_OFF) { + index = 0; + goto unlock; + } + + /* It is possible someone else got here first and set the index */ + if ((index = GET_RWINDEX(rwlock_ptr)) == 0) { + /* + * we can't turn on read stats for this lock while there are + * readers (this would mess up the running hold time sum at + * unlock time) + */ + if (RWLOCK_READERS(rwlock_ptr) != 0) { + index = 0; + goto unlock; + } + + /* + * if stats are turned on after being off, we may need to + * return an old index from when the statistics were on last + * time. + */ + for (index = 1; index < lstat_control.next_free_read_lock_index; + index++) + if ((*lstat_control.read_lock_counts[cpu])[index]. + lock_ptr == rwlock_ptr) + goto put_index_and_unlock; + + /* allocate the next global read lock structure */ + if (lstat_control.next_free_read_lock_index >= + LSTAT_MAX_READ_LOCK_INDEX) { + lstat_control.rwlock_overflow++; + index = 0; + goto unlock; + } + index = lstat_control.next_free_read_lock_index++; + + /* + * initialize the global read stats data structure for each + * cpu + */ + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + (*lstat_control.read_lock_counts[cpu])[index].lock_ptr = + rwlock_ptr; + } +put_index_and_unlock: + /* store the index for the read lock structure into the lock */ + PUT_RWINDEX(rwlock_ptr, index); + } + +unlock: + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); + return index; +} + +void +_metered_read_lock(rwlock_t * rwlock_ptr) +{ + void *this_pc; + uint32_t start_cycles; + int index; + int cpu; + unsigned long flags; + int readers_before, readers_after; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_READ); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) + index = alloc_rwlock_struct(rwlock_ptr); + + readers_before = RWLOCK_READERS(rwlock_ptr); + if (_raw_read_trylock(rwlock_ptr)) { + /* + * We have decremented the lock to count a new reader, + * and have confirmed that no writer has it locked. + */ + /* update statistics if enabled */ + if (index > 0) { + local_irq_save(flags); + lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* preserve value of TSC so cum_hold_ticks and start_busy use same value */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index]. + cum_hold_ticks -= cycles64; + + /* record time and cpu of start of busy period */ + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } + + return; + } + /* If we get here, then we could not quickly grab the read lock */ + + start_cycles = get_cycles(); /* start counting the wait time */ + + /* Now spin until read_lock is successful */ + _raw_read_lock(rwlock_ptr); + + lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN, + get_cycles() - start_cycles); + + /* update statistics if they are enabled for this lock */ + if (index > 0) { + local_irq_save(flags); + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -= + cycles64; + + /* this is not perfect (some race conditions are possible) */ + if (readers_before == 0) { + (*lstat_control.read_lock_counts[cpu])[index]. + start_busy = cycles64; + PUT_RW_CPU(rwlock_ptr, cpu); + } + readers_after = RWLOCK_READERS(rwlock_ptr); + if (readers_after > + (*lstat_control.read_lock_counts[cpu])[index].max_readers) + (*lstat_control.read_lock_counts[cpu])[index]. + max_readers = readers_after; + local_irq_restore(flags); + } +} + +void +_metered_read_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + unsigned long flags; + uint64_t busy_length; + uint64_t cycles64; + + if (lstat_control.state == LSTAT_OFF) { + _raw_read_unlock(rwlock_ptr); + return; + } + + index = GET_RWINDEX(rwlock_ptr); + cpu = THIS_CPU_NUMBER; + + if (index > 0) { + local_irq_save(flags); + /* + * preserve value of TSC so cum_hold_ticks and busy_ticks are + * consistent. + */ + cycles64 = get_cycles64(); + (*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks += + cycles64; + (*lstat_control.read_lock_counts[cpu])[index].read_lock_count++; + + /* + * once again, this is not perfect (some race conditions are + * possible) + */ + if (RWLOCK_READERS(rwlock_ptr) == 1) { + int cpu1 = GET_RW_CPU(rwlock_ptr); + uint64_t last_start_busy = + (*lstat_control.read_lock_counts[cpu1])[index]. + start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_periods++; + if (cycles64 > last_start_busy) { + busy_length = cycles64 - last_start_busy; + (*lstat_control.read_lock_counts[cpu])[index]. + busy_ticks += busy_length; + if (busy_length > + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy) + (*lstat_control. + read_lock_counts[cpu])[index]. + max_busy = busy_length; + } + } + local_irq_restore(flags); + } + _raw_read_unlock(rwlock_ptr); +} + +void +_metered_write_lock(rwlock_t * rwlock_ptr) +{ + uint32_t start_cycles; + void *this_pc; + uint32_t spin_ticks = 0; /* in anticipation of a potential wait */ + int index; + int write_index = 0; + int cpu; + enum { + writer_writer_conflict, + writer_reader_conflict + } why_wait = writer_writer_conflict; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_lock(rwlock_ptr); + /* clean index in case lockmetering turns on before an unlock */ + PUT_RWINDEX(rwlock_ptr, 0); + return; + } + + this_pc = LSTAT_RA(LSTAT_RA_WRITE); + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* allocate the global stats entry for this lock, if needed */ + if (index == 0) { + index = alloc_rwlock_struct(rwlock_ptr); + } + + if (_raw_write_trylock(rwlock_ptr)) { + /* We acquired the lock on the first try */ + write_index = lstat_update((void *) rwlock_ptr, this_pc, + LSTAT_ACT_NO_WAIT); + /* save the write_index for use in unlock if stats enabled */ + if (index > 0) + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + return; + } + + /* If we get here, then we could not quickly grab the write lock */ + start_cycles = get_cycles(); /* start counting the wait time */ + + why_wait = RWLOCK_READERS(rwlock_ptr) ? + writer_reader_conflict : writer_writer_conflict; + + /* Now set the lock and wait for conflicts to disappear */ + _raw_write_lock(rwlock_ptr); + + spin_ticks = get_cycles() - start_cycles; + + /* update stats -- if enabled */ + if (index > 0 && spin_ticks) { + if (why_wait == writer_reader_conflict) { + /* waited due to a reader holding the lock */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_SPIN, spin_ticks); + } else { + /* + * waited due to another writer holding the lock + */ + write_index = lstat_update_time((void *)rwlock_ptr, + this_pc, LSTAT_ACT_WW_SPIN, spin_ticks); + (*lstat_control.counts[cpu])[write_index]. + cum_wait_ww_ticks += spin_ticks; + if (spin_ticks > + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks) { + (*lstat_control.counts[cpu])[write_index]. + max_wait_ww_ticks = spin_ticks; + } + } + + /* save the directory index for use on write_unlock */ + (*lstat_control.read_lock_counts[cpu])[index]. + write_index = write_index; + } +} + +void +_metered_write_unlock(rwlock_t * rwlock_ptr) +{ + int index; + int cpu; + int write_index; + uint32_t hold_time; + + if (lstat_control.state == LSTAT_OFF) { + _raw_write_unlock(rwlock_ptr); + return; + } + + cpu = THIS_CPU_NUMBER; + index = GET_RWINDEX(rwlock_ptr); + + /* update statistics if stats enabled for this lock */ + if (index > 0) { + write_index = + (*lstat_control.read_lock_counts[cpu])[index].write_index; + + hold_time = get_cycles() - + (*lstat_control.counts[cpu])[write_index].acquire_time; + (*lstat_control.counts[cpu])[write_index].cum_hold_ticks += + (uint64_t) hold_time; + if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks < + hold_time) + (*lstat_control.counts[cpu])[write_index]. + max_hold_ticks = hold_time; + } + _raw_write_unlock(rwlock_ptr); +} + +int +_metered_write_trylock(rwlock_t * rwlock_ptr) +{ + int retval; + void *this_pc = LSTAT_RA(LSTAT_RA_WRITE); + + if ((retval = _raw_write_trylock(rwlock_ptr))) { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT); + } else { + lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT); + } + + return retval; +} + +static void +init_control_space(void) +{ + /* Set all control space pointers to null and indices to "empty" */ + int cpu; + + /* + * Access CPU_CYCLE_FREQUENCY at the outset, which in some + * architectures may trigger a runtime calculation that uses a + * spinlock. Let's do this before lockmetering is turned on. + */ + if (CPU_CYCLE_FREQUENCY == 0) + BUG(); + + lstat_control.hashtab = NULL; + lstat_control.dir = NULL; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + lstat_control.counts[cpu] = NULL; + lstat_control.read_lock_counts[cpu] = NULL; + } +} + +static int +reset_lstat_data(void) +{ + int cpu, flags; + + flags = 0; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + lstat_control.dir_overflow = 0; + lstat_control.rwlock_overflow = 0; + + lstat_control.started_cycles64 = 0; + lstat_control.ending_cycles64 = 0; + lstat_control.enabled_cycles64 = 0; + lstat_control.first_started_time = 0; + lstat_control.started_time = 0; + lstat_control.ending_time = 0; + lstat_control.intervals = 0; + + /* + * paranoia -- in case someone does a "lockstat reset" before + * "lockstat on" + */ + if (lstat_control.hashtab) { + bzero(lstat_control.hashtab, + LSTAT_HASH_TABLE_SIZE * sizeof (short)); + bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t)); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + bzero(lstat_control.counts[cpu], + sizeof (lstat_cpu_counts_t)); + bzero(lstat_control.read_lock_counts[cpu], + sizeof (lstat_read_lock_cpu_counts_t)); + } + } +#ifdef NOTDEF + _raw_spin_unlock(&lstat_control.directory_lock); + local_irq_restore(flags); +#endif + return 1; +} + +static void +release_control_space(void) +{ + /* + * Called when either (1) allocation of kmem + * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter. + * Assume that all pointers have been initialized to zero, + * i.e., nonzero pointers are valid addresses. + */ + int cpu; + + if (lstat_control.hashtab) { + kfree(lstat_control.hashtab); + lstat_control.hashtab = NULL; + } + + if (lstat_control.dir) { + vfree(lstat_control.dir); + lstat_control.dir = NULL; + } + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (lstat_control.counts[cpu]) { + vfree(lstat_control.counts[cpu]); + lstat_control.counts[cpu] = NULL; + } + if (lstat_control.read_lock_counts[cpu]) { + kfree(lstat_control.read_lock_counts[cpu]); + lstat_control.read_lock_counts[cpu] = NULL; + } + } +} + +int +get_lockmeter_info_size(void) +{ + return sizeof (lstat_user_request_t) + + num_online_cpus() * sizeof (lstat_cpu_counts_t) + + num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t) + + (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t)); +} + +ssize_t +get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index) +{ + lstat_user_request_t req; + struct timeval tv; + ssize_t next_ret_bcount; + ssize_t actual_ret_bcount = 0; + int cpu; + + *last_index = 0; /* a one-shot read */ + + req.lstat_version = LSTAT_VERSION; + req.state = lstat_control.state; + req.maxcpus = num_online_cpus(); + req.cycleval = CPU_CYCLE_FREQUENCY; +#ifdef notyet + req.kernel_magic_addr = (void *) &_etext; + req.kernel_end_addr = (void *) &_etext; +#endif + req.uts = system_utsname; + req.intervals = lstat_control.intervals; + + req.first_started_time = lstat_control.first_started_time; + req.started_time = lstat_control.started_time; + req.started_cycles64 = lstat_control.started_cycles64; + + req.next_free_dir_index = lstat_control.next_free_dir_index; + req.next_free_read_lock_index = lstat_control.next_free_read_lock_index; + req.dir_overflow = lstat_control.dir_overflow; + req.rwlock_overflow = lstat_control.rwlock_overflow; + + if (lstat_control.state == LSTAT_OFF) { + if (req.intervals == 0) { + /* mesasurement is off and no valid data present */ + next_ret_bcount = sizeof (lstat_user_request_t); + req.enabled_cycles64 = 0; + + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + return actual_ret_bcount; + } else { + /* + * measurement is off but valid data present + * fetch time info from lstat_control + */ + req.ending_time = lstat_control.ending_time; + req.ending_cycles64 = lstat_control.ending_cycles64; + req.enabled_cycles64 = lstat_control.enabled_cycles64; + } + } else { + /* + * this must be a read while data active--use current time, + * etc + */ + do_gettimeofday(&tv); + req.ending_time = tv.tv_sec; + req.ending_cycles64 = get_cycles64(); + req.enabled_cycles64 = req.ending_cycles64 - + req.started_cycles64 + lstat_control.enabled_cycles64; + } + + next_ret_bcount = sizeof (lstat_user_request_t); + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; + + copy_to_user(buffer, (void *) &req, next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + if (!lstat_control.counts[0]) /* not initialized? */ + return actual_ret_bcount; + + next_ret_bcount = sizeof (lstat_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if ((actual_ret_bcount + next_ret_bcount) > max_len) + return actual_ret_bcount; /* leave early */ + copy_to_user(buffer + actual_ret_bcount, + lstat_control.counts[cpu], next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + next_ret_bcount = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + if (((actual_ret_bcount + next_ret_bcount) > max_len) + || !lstat_control.dir) + return actual_ret_bcount; /* leave early */ + + copy_to_user(buffer + actual_ret_bcount, lstat_control.dir, + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + + next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t); + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + if (actual_ret_bcount + next_ret_bcount > max_len) + return actual_ret_bcount; + copy_to_user(buffer + actual_ret_bcount, + lstat_control.read_lock_counts[cpu], + next_ret_bcount); + actual_ret_bcount += next_ret_bcount; + } + + return actual_ret_bcount; +} + +/* + * Writing to the /proc lockmeter node enables or disables metering. + * based upon the first byte of the "written" data. + * The following values are defined: + * LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement + * subsequent calls just turn on measurement + * LSTAT_OFF: turns off measurement + * LSTAT_RESET: resets statistics + * LSTAT_RELEASE: releases statistics storage + * + * This allows one to accumulate statistics over several lockstat runs: + * + * lockstat on + * lockstat off + * ...repeat above as desired... + * lockstat get + * ...now start a new set of measurements... + * lockstat reset + * lockstat on + * ... + * + */ +ssize_t +put_lockmeter_info(const char *buffer, size_t len) +{ + int error = 0; + int dirsize, countsize, read_lock_countsize, hashsize; + int cpu; + char put_char; + int i, read_lock_blocks; + unsigned long flags; + rwlock_t *lock_ptr; + struct timeval tv; + + if (len <= 0) + return -EINVAL; + + _raw_spin_lock(&lstat_control.control_lock); + + get_user(put_char, buffer); + switch (put_char) { + + case LSTAT_OFF: + if (lstat_control.state != LSTAT_OFF) { + /* + * To avoid seeing read lock hold times in an + * inconsisent state, we have to follow this protocol + * to turn off statistics + */ + local_irq_save(flags); + /* + * getting this lock will stop any read lock block + * allocations + */ + _raw_spin_lock(&lstat_control.directory_lock); + /* + * keep any more read lock blocks from being + * allocated + */ + lstat_control.state = LSTAT_OFF; + /* record how may read lock blocks there are */ + read_lock_blocks = + lstat_control.next_free_read_lock_index; + _raw_spin_unlock(&lstat_control.directory_lock); + /* now go through the list of read locks */ + cpu = THIS_CPU_NUMBER; + for (i = 1; i < read_lock_blocks; i++) { + lock_ptr = + (*lstat_control.read_lock_counts[cpu])[i]. + lock_ptr; + /* is this saved lock address still valid? */ + if (GET_RWINDEX(lock_ptr) == i) { + /* + * lock address appears to still be + * valid because we only hold one lock + * at a time, this can't cause a + * deadlock unless this is a lock held + * as part of the current system call + * path. At the moment there + * are no READ mode locks held to get + * here from user space, so we solve + * this by skipping locks held in + * write mode. + */ + if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) { + PUT_RWINDEX(lock_ptr, 0); + continue; + } + /* + * now we know there are no read + * holders of this lock! stop + * statistics collection for this + * lock + */ + _raw_write_lock(lock_ptr); + PUT_RWINDEX(lock_ptr, 0); + _raw_write_unlock(lock_ptr); + } + /* + * it may still be possible for the hold time + * sum to be negative e.g. if a lock is + * reallocated while "busy" we will have to fix + * this up in the data reduction program. + */ + } + local_irq_restore(flags); + lstat_control.intervals++; + lstat_control.ending_cycles64 = get_cycles64(); + lstat_control.enabled_cycles64 += + lstat_control.ending_cycles64 - + lstat_control.started_cycles64; + do_gettimeofday(&tv); + lstat_control.ending_time = tv.tv_sec; + /* + * don't deallocate the structures -- we may do a + * lockstat on to add to the data that is already + * there. Use LSTAT_RELEASE to release storage + */ + } else { + error = -EBUSY; /* already OFF */ + } + break; + + case LSTAT_ON: + if (lstat_control.state == LSTAT_OFF) { +#ifdef DEBUG_LOCKMETER + printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n", + THIS_CPU_NUMBER); +#endif + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + + dirsize = LSTAT_MAX_STAT_INDEX * + sizeof (lstat_directory_entry_t); + hashsize = + (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = + sizeof (lstat_read_lock_cpu_counts_t); +#ifdef DEBUG_LOCKMETER + printk(" dirsize:%d", dirsize); + printk(" hashsize:%d", hashsize); + printk(" countsize:%d", countsize); + printk(" read_lock_countsize:%d\n", + read_lock_countsize); +#endif +#ifdef DEBUG_LOCKMETER + { + int secs; + unsigned long cycles; + uint64_t cycles64; + + do_gettimeofday(&tv); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles(); + cycles64 = get_cycles64(); + secs = tv.tv_sec; + do { + do_gettimeofday(&tv); + } while (secs == tv.tv_sec); + cycles = get_cycles() - cycles; + cycles64 = get_cycles64() - cycles; + printk("lockmeter: cycleFrequency:%d " + "cycles:%d cycles64:%d\n", + CPU_CYCLE_FREQUENCY, cycles, cycles64); + } +#endif + + /* + * if this is the first call, allocate storage and + * initialize + */ + if (!lstat_control.hashtab) { + + spin_lock_init(&lstat_control.directory_lock); + + /* guarantee all pointers at zero */ + init_control_space(); + + lstat_control.hashtab = + kmalloc(hashsize, GFP_KERNEL); + if (!lstat_control.hashtab) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of hashtab\n"); +#endif + } + lstat_control.dir = vmalloc(dirsize); + if (!lstat_control.dir) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of dir\n"); +#endif + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + lstat_control.counts[cpu] = + vmalloc(countsize); + if (!lstat_control.counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error vmalloc of " + "counts[%d]\n", cpu); +#endif + } + lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + kmalloc(read_lock_countsize, + GFP_KERNEL); + if (!lstat_control. + read_lock_counts[cpu]) { + error = -ENOSPC; +#ifdef DEBUG_LOCKMETER + printk("!!error kmalloc of " + "read_lock_counts[%d]\n", + cpu); +#endif + } + } + } + + if (error) { + /* + * One or more kmalloc failures -- free + * everything + */ + release_control_space(); + } else { + + if (!reset_lstat_data()) { + error = -EINVAL; + break; + }; + + /* + * record starting and ending times and the + * like + */ + if (lstat_control.intervals == 0) { + do_gettimeofday(&tv); + lstat_control.first_started_time = + tv.tv_sec; + } + lstat_control.started_cycles64 = get_cycles64(); + do_gettimeofday(&tv); + lstat_control.started_time = tv.tv_sec; + + lstat_control.state = LSTAT_ON; + } + } else { + error = -EBUSY; /* already ON */ + } + break; + + case LSTAT_RESET: + if (lstat_control.state == LSTAT_OFF) { + if (!reset_lstat_data()) + error = -EINVAL; + } else { + error = -EBUSY; /* still on; can't reset */ + } + break; + + case LSTAT_RELEASE: + if (lstat_control.state == LSTAT_OFF) { + release_control_space(); + lstat_control.intervals = 0; + lstat_control.enabled_cycles64 = 0; + } else { + error = -EBUSY; + } + break; + + default: + error = -EINVAL; + } /* switch */ + + _raw_spin_unlock(&lstat_control.control_lock); + return error ? error : len; +} + +#ifdef USER_MODE_TESTING +/* following used for user mode testing */ +void +lockmeter_init() +{ + int dirsize, hashsize, countsize, read_lock_countsize, cpu; + + printf("lstat_control is at %x size=%d\n", &lstat_control, + sizeof (lstat_control)); + printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t)); + lstat_control.state = LSTAT_ON; + + lstat_control.directory_lock = SPIN_LOCK_UNLOCKED; + lstat_control.next_free_dir_index = 1; /* 0 is for overflows */ + lstat_control.next_free_read_lock_index = 1; + + dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t); + hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort); + countsize = sizeof (lstat_cpu_counts_t); + read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t); + + lstat_control.hashtab = (ushort *) malloc(hashsize); + + if (lstat_control.hashtab == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", + __LINE__); + exit(0); + } + + lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize); + + if (lstat_control.dir == 0) { + printf("malloc failure for at line %d in lockmeter.c\n", cpu, + __LINE__); + exit(0); + } + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + int j, k; + j = (int) (lstat_control.counts[cpu] = + (lstat_cpu_counts_t *) malloc(countsize)); + k = (int) (lstat_control.read_lock_counts[cpu] = + (lstat_read_lock_cpu_counts_t *) + malloc(read_lock_countsize)); + if (j * k == 0) { + printf("malloc failure for cpu=%d at line %d in " + "lockmeter.c\n", cpu, __LINE__); + exit(0); + } + } + + memset(lstat_control.hashtab, 0, hashsize); + memset(lstat_control.dir, 0, dirsize); + + for (cpu = 0; cpu < num_online_cpus(); cpu++) { + memset(lstat_control.counts[cpu], 0, countsize); + memset(lstat_control.read_lock_counts[cpu], 0, + read_lock_countsize); + } +} + +asm(" \ +.align 4 \ +.globl __write_lock_failed \ +__write_lock_failed: \ + " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) \ +1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) \ + jne 1b \ +\ + " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) \ + jnz __write_lock_failed \ + ret \ +\ +\ +.align 4 \ +.globl __read_lock_failed \ +__read_lock_failed: \ + lock ; incl (%eax) \ +1: cmpl $1,(%eax) \ + js 1b \ +\ + lock ; decl (%eax) \ + js __read_lock_failed \ + ret \ +"); +#endif + +EXPORT_SYMBOL(_metered_spin_lock); +EXPORT_SYMBOL(_metered_spin_unlock); +EXPORT_SYMBOL(_metered_spin_trylock); +EXPORT_SYMBOL(_metered_read_lock); +EXPORT_SYMBOL(_metered_read_unlock); +EXPORT_SYMBOL(_metered_write_lock); +EXPORT_SYMBOL(_metered_write_unlock); --- linux-2.6.8-rc1/kernel/Makefile 2004-07-11 14:13:30.000000000 -0700 +++ 25/kernel/Makefile 2004-07-13 17:09:29.000000000 -0700 @@ -12,6 +12,7 @@ obj-y = sched.o fork.o exec_domain.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o +obj-$(CONFIG_LOCKMETER) += lockmeter.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o --- linux-2.6.8-rc1/kernel/pid.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/kernel/pid.c 2004-07-13 17:09:28.000000000 -0700 @@ -122,6 +122,8 @@ return_pid: } if (!offset || !atomic_read(&map->nr_free)) { + if (!offset) + map--; next_map: map = next_free_map(map, &max_steps); if (!map) @@ -268,6 +270,9 @@ void switch_exec_pids(task_t *leader, ta * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or * more. */ +#ifdef CONFIG_KGDB +int kgdb_pid_init_done; /* so we don't call prior to... */ +#endif void __init pidhash_init(void) { int i, j, pidhash_size; @@ -289,6 +294,9 @@ void __init pidhash_init(void) for (j = 0; j < pidhash_size; j++) INIT_LIST_HEAD(&pid_hash[i][j]); } +#ifdef CONFIG_KGDB + kgdb_pid_init_done++; +#endif } void __init pidmap_init(void) --- linux-2.6.8-rc1/kernel/profile.c 2003-07-27 12:14:40.000000000 -0700 +++ 25/kernel/profile.c 2004-07-13 17:09:50.000000000 -0700 @@ -18,10 +18,18 @@ int prof_on; int __init profile_setup(char * str) { int par; + + if (!strncmp(str, "schedule", 8)) { + prof_on = 2; + printk(KERN_INFO "kernel schedule profiling enabled\n"); + if (str[7] == ',') + str += 8; + } if (get_option(&str,&par)) { prof_shift = par; prof_on = 1; - printk(KERN_INFO "kernel profiling enabled\n"); + printk(KERN_INFO "kernel profiling enabled (shift: %ld)\n", + prof_shift); } return 1; } --- linux-2.6.8-rc1/kernel/sched.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/kernel/sched.c 2004-07-13 17:09:50.000000000 -0700 @@ -39,7 +39,9 @@ #include #include #include +#include #include +#include #include @@ -864,6 +866,11 @@ int fastcall wake_up_state(task_t *p, un return try_to_wake_up(p, state, 0); } +#ifdef CONFIG_SMP +static int find_idlest_cpu(struct task_struct *p, int this_cpu, + struct sched_domain *sd); +#endif + /* * Perform scheduler related setup for a newly forked process p. * p is forked by current. @@ -903,7 +910,7 @@ void fastcall sched_fork(task_t *p) p->first_time_slice = 1; current->time_slice >>= 1; p->timestamp = sched_clock(); - if (!current->time_slice) { + if (unlikely(!current->time_slice)) { /* * This case is rare, it happens when the parent has only * a single jiffy left from its timeslice. Taking the @@ -919,43 +926,80 @@ void fastcall sched_fork(task_t *p) } /* - * wake_up_forked_process - wake up a freshly forked process. + * wake_up_new_task - wake up a newly created task for the first time. * * This function will do some initial scheduler statistics housekeeping - * that must be done for every newly created process. + * that must be done for every newly created context, then puts the task + * on the runqueue and wakes it. */ -void fastcall wake_up_forked_process(task_t * p) +void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags) { unsigned long flags; - runqueue_t *rq = task_rq_lock(current, &flags); + int this_cpu, cpu; + runqueue_t *rq; + + rq = task_rq_lock(p, &flags); + cpu = task_cpu(p); + this_cpu = smp_processor_id(); BUG_ON(p->state != TASK_RUNNING); /* * We decrease the sleep average of forking parents * and children as well, to keep max-interactive tasks - * from forking tasks that are max-interactive. + * from forking tasks that are max-interactive. The parent + * (current) is done further down, under its lock. */ - current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) * - PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); - p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) * CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); p->interactive_credit = 0; p->prio = effective_prio(p); - set_task_cpu(p, smp_processor_id()); - if (unlikely(!current->array)) + if (likely(cpu == this_cpu)) { + if (!(clone_flags & CLONE_VM)) { + /* + * The VM isn't cloned, so we're in a good position to + * do child-runs-first in anticipation of an exec. This + * usually avoids a lot of COW overhead. + */ + if (unlikely(!current->array)) + __activate_task(p, rq); + else { + p->prio = current->prio; + list_add_tail(&p->run_list, ¤t->run_list); + p->array = current->array; + p->array->nr_active++; + rq->nr_running++; + } + set_need_resched(); + } else + /* Run child last */ + __activate_task(p, rq); + } else { + runqueue_t *this_rq = cpu_rq(this_cpu); + + /* + * Not the local CPU - must adjust timestamp. This should + * get optimised away in the !CONFIG_SMP case. + */ + p->timestamp = (p->timestamp - this_rq->timestamp_last_tick) + + rq->timestamp_last_tick; __activate_task(p, rq); - else { - p->prio = current->prio; - list_add_tail(&p->run_list, ¤t->run_list); - p->array = current->array; - p->array->nr_active++; - rq->nr_running++; + if (TASK_PREEMPTS_CURR(p, rq)) + resched_task(rq->curr); + + current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) * + PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); + } + + if (unlikely(cpu != this_cpu)) { + task_rq_unlock(rq, &flags); + rq = task_rq_lock(current, &flags); } + current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) * + PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); task_rq_unlock(rq, &flags); } @@ -973,18 +1017,16 @@ void fastcall sched_exit(task_t * p) unsigned long flags; runqueue_t *rq; - local_irq_save(flags); - if (p->first_time_slice) { - p->parent->time_slice += p->time_slice; - if (unlikely(p->parent->time_slice > MAX_TIMESLICE)) - p->parent->time_slice = MAX_TIMESLICE; - } - local_irq_restore(flags); /* * If the child was a (relative-) CPU hog then decrease * the sleep_avg of the parent as well. */ rq = task_rq_lock(p->parent, &flags); + if (p->first_time_slice) { + p->parent->time_slice += p->time_slice; + if (unlikely(p->parent->time_slice > MAX_TIMESLICE)) + p->parent->time_slice = MAX_TIMESLICE; + } if (p->sleep_avg < p->parent->sleep_avg) p->parent->sleep_avg = p->parent->sleep_avg / (EXIT_WEIGHT + 1) * EXIT_WEIGHT + p->sleep_avg / @@ -1084,7 +1126,7 @@ unsigned long nr_running(void) { unsigned long i, sum = 0; - for_each_cpu(i) + for_each_online_cpu(i) sum += cpu_rq(i)->nr_running; return sum; @@ -1120,6 +1162,15 @@ unsigned long nr_iowait(void) return sum; } +enum idle_type +{ + IDLE, + NOT_IDLE, + NEWLY_IDLE, +}; + +#ifdef CONFIG_SMP + /* * double_rq_lock - safely lock two runqueues * @@ -1154,14 +1205,20 @@ static void double_rq_unlock(runqueue_t spin_unlock(&rq2->lock); } -enum idle_type +/* + * double_lock_balance - lock the busiest runqueue, this_rq is locked already. + */ +static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest) { - IDLE, - NOT_IDLE, - NEWLY_IDLE, -}; - -#ifdef CONFIG_SMP + if (unlikely(!spin_trylock(&busiest->lock))) { + if (busiest < this_rq) { + spin_unlock(&this_rq->lock); + spin_lock(&busiest->lock); + spin_lock(&this_rq->lock); + } else + spin_lock(&busiest->lock); + } +} /* * find_idlest_cpu - find the least busy runqueue. @@ -1210,89 +1267,6 @@ static int find_idlest_cpu(struct task_s } /* - * wake_up_forked_thread - wake up a freshly forked thread. - * - * This function will do some initial scheduler statistics housekeeping - * that must be done for every newly created context, and it also does - * runqueue balancing. - */ -void fastcall wake_up_forked_thread(task_t * p) -{ - unsigned long flags; - int this_cpu = get_cpu(), cpu; - struct sched_domain *tmp, *sd = NULL; - runqueue_t *this_rq = cpu_rq(this_cpu), *rq; - - /* - * Find the largest domain that this CPU is part of that - * is willing to balance on clone: - */ - for_each_domain(this_cpu, tmp) - if (tmp->flags & SD_BALANCE_CLONE) - sd = tmp; - if (sd) - cpu = find_idlest_cpu(p, this_cpu, sd); - else - cpu = this_cpu; - - local_irq_save(flags); -lock_again: - rq = cpu_rq(cpu); - double_rq_lock(this_rq, rq); - - BUG_ON(p->state != TASK_RUNNING); - - /* - * We did find_idlest_cpu() unlocked, so in theory - * the mask could have changed - just dont migrate - * in this case: - */ - if (unlikely(!cpu_isset(cpu, p->cpus_allowed))) { - cpu = this_cpu; - double_rq_unlock(this_rq, rq); - goto lock_again; - } - /* - * We decrease the sleep average of forking parents - * and children as well, to keep max-interactive tasks - * from forking tasks that are max-interactive. - */ - current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) * - PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); - - p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) * - CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); - - p->interactive_credit = 0; - - p->prio = effective_prio(p); - set_task_cpu(p, cpu); - - if (cpu == this_cpu) { - if (unlikely(!current->array)) - __activate_task(p, rq); - else { - p->prio = current->prio; - list_add_tail(&p->run_list, ¤t->run_list); - p->array = current->array; - p->array->nr_active++; - rq->nr_running++; - } - } else { - /* Not the local CPU - must adjust timestamp */ - p->timestamp = (p->timestamp - this_rq->timestamp_last_tick) - + rq->timestamp_last_tick; - __activate_task(p, rq); - if (TASK_PREEMPTS_CURR(p, rq)) - resched_task(rq->curr); - } - - double_rq_unlock(this_rq, rq); - local_irq_restore(flags); - put_cpu(); -} - -/* * If dest_cpu is allowed for this process, migrate the task to it. * This is accomplished by forcing the cpu_allowed mask to only * allow dest_cpu, which will force the cpu onto dest_cpu. Then @@ -1325,13 +1299,13 @@ out: } /* - * sched_balance_exec(): find the highest-level, exec-balance-capable + * sched_exec(): find the highest-level, exec-balance-capable * domain and try to migrate the task to the least loaded CPU. * * execve() is a valuable balancing opportunity, because at this point * the task has the smallest effective memory and cache footprint. */ -void sched_balance_exec(void) +void sched_exec(void) { struct sched_domain *tmp, *sd = NULL; int new_cpu, this_cpu = get_cpu(); @@ -1357,21 +1331,6 @@ out: } /* - * double_lock_balance - lock the busiest runqueue, this_rq is locked already. - */ -static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest) -{ - if (unlikely(!spin_trylock(&busiest->lock))) { - if (busiest < this_rq) { - spin_unlock(&this_rq->lock); - spin_lock(&busiest->lock); - spin_lock(&this_rq->lock); - } else - spin_lock(&busiest->lock); - } -} - -/* * pull_task - move a task from a remote runqueue to the local runqueue. * Both runqueues must be locked. */ @@ -2027,7 +1986,7 @@ void scheduler_tick(int user_ticks, int * timeslice. This makes it possible for interactive tasks * to use up their timeslices at their highest priority levels. */ - if (unlikely(rt_task(p))) { + if (rt_task(p)) { /* * RR tasks need a special form of timeslice management. * FIFO tasks have no timeslices. @@ -2191,6 +2150,7 @@ asmlinkage void __sched schedule(void) unsigned long run_time; int cpu, idx; + WARN_ON(system_state == SYSTEM_BOOTING); /* * Test if we are atomic. Since do_exit() needs to call into * schedule() atomically, we ignore that path for now. @@ -2202,12 +2162,25 @@ asmlinkage void __sched schedule(void) dump_stack(); } } +#ifdef kern_profile + if (unlikely(prof_on == 2)) + __do_profile((unsigned long)__builtin_return_address(0)); +#endif need_resched: preempt_disable(); prev = current; rq = this_rq(); + /* + * The idle thread is not allowed to schedule! + * Remove this check after it has been exercised a bit. + */ + if (unlikely(current == rq->idle) && current->state != TASK_RUNNING) { + printk(KERN_ERR "bad: scheduling from the idle thread!\n"); + dump_stack(); + } + release_kernel_lock(prev); now = sched_clock(); if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG)) @@ -2312,7 +2285,7 @@ switch_tasks: reacquire_kernel_lock(current); preempt_enable_no_resched(); - if (test_thread_flag(TIF_NEED_RESCHED)) + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) goto need_resched; } @@ -2605,6 +2578,13 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); +#ifdef CONFIG_KGDB +struct task_struct *kgdb_get_idle(int this_cpu) +{ + return cpu_rq(this_cpu)->idle; +} +#endif + #ifdef __ARCH_WANT_SYS_NICE /* @@ -3014,7 +2994,7 @@ asmlinkage long sys_sched_yield(void) * (special rule: RT tasks will just roundrobin in the active * array.) */ - if (unlikely(rt_task(current))) + if (rt_task(current)) target = rq->active; dequeue_task(current, array); @@ -3267,21 +3247,20 @@ void show_state(void) void __devinit init_idle(task_t *idle, int cpu) { - runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(task_cpu(idle)); + runqueue_t *rq = cpu_rq(cpu); unsigned long flags; - local_irq_save(flags); - double_rq_lock(idle_rq, rq); - - idle_rq->curr = idle_rq->idle = idle; - deactivate_task(idle, rq); + idle->sleep_avg = 0; + idle->interactive_credit = 0; idle->array = NULL; idle->prio = MAX_PRIO; idle->state = TASK_RUNNING; set_task_cpu(idle, cpu); - double_rq_unlock(idle_rq, rq); + + spin_lock_irqsave(&rq->lock, flags); + rq->curr = rq->idle = idle; set_tsk_need_resched(idle); - local_irq_restore(flags); + spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ #ifdef CONFIG_PREEMPT @@ -3333,6 +3312,8 @@ int set_cpus_allowed(task_t *p, cpumask_ migration_req_t req; runqueue_t *rq; + perfctr_set_cpus_allowed(p, new_mask); + rq = task_rq_lock(p, &flags); if (!cpus_intersects(new_mask, cpu_online_map)) { ret = -EINVAL; @@ -3349,6 +3330,7 @@ int set_cpus_allowed(task_t *p, cpumask_ task_rq_unlock(rq, &flags); wake_up_process(rq->migration_thread); wait_for_completion(&req.done); + tlb_migrate_finish(p->mm); return 0; } out: @@ -3362,7 +3344,7 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed); * Move (not current) task off this cpu, onto dest cpu. We're doing * this because either it can't run here any more (set_cpus_allowed() * away from this CPU, or CPU going down), or because we're - * attempting to rebalance this task on exec (sched_balance_exec). + * attempting to rebalance this task on exec (sched_exec). * * So we race with normal scheduler movements, but that's OK, as long * as the task is no longer on this CPU. @@ -3956,15 +3938,6 @@ void __init sched_init(void) __set_bit(MAX_PRIO, array->bitmap); } } - /* - * We have to do a little magic to get the first - * thread right in SMP mode. - */ - rq = this_rq(); - rq->curr = current; - rq->idle = current; - set_task_cpu(current, smp_processor_id()); - wake_up_forked_process(current); /* * The boot idle thread does lazy MMU switching as well: --- linux-2.6.8-rc1/kernel/sys.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/kernel/sys.c 2004-07-13 17:09:33.000000000 -0700 @@ -280,6 +280,12 @@ cond_syscall(compat_get_mempolicy) cond_syscall(sys_pciconfig_read) cond_syscall(sys_pciconfig_write) cond_syscall(sys_pciconfig_iobase) +cond_syscall(sys_perfctr_info) +cond_syscall(sys_vperfctr_open) +cond_syscall(sys_vperfctr_control) +cond_syscall(sys_vperfctr_unlink) +cond_syscall(sys_vperfctr_iresume) +cond_syscall(sys_vperfctr_read) static int set_one_prio(struct task_struct *p, int niceval, int error) { --- linux-2.6.8-rc1/kernel/timer.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/kernel/timer.c 2004-07-13 17:09:33.000000000 -0700 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -835,6 +836,7 @@ static void update_one_process(struct ta do_process_times(p, user, system); do_it_virt(p, user); do_it_prof(p); + perfctr_sample_thread(&p->thread); } /* --- linux-2.6.8-rc1/lib/bitmap.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/lib/bitmap.c 2004-07-13 17:09:21.000000000 -0700 @@ -408,3 +408,79 @@ int bitmap_parse(const char __user *ubuf return 0; } EXPORT_SYMBOL(bitmap_parse); + +/** + * bitmap_find_free_region - find a contiguous aligned mem region + * @bitmap: an array of unsigned longs corresponding to the bitmap + * @bits: number of bits in the bitmap + * @order: region size to find (size is actually 1< BITS_PER_LONG) + return -EINVAL; + + /* make a mask of the order */ + mask = (1ul << (pages - 1)); + mask += mask - 1; + + /* run up the bitmap pages bits at a time */ + for (i = 0; i < bits; i += pages) { + int index = BITS_TO_LONGS(i); + int offset = i - (index * BITS_PER_LONG); + if((bitmap[index] & (mask << offset)) == 0) { + /* set region in bimap */ + bitmap[index] |= (mask << offset); + return i; + } + } + return -ENOMEM; +} +EXPORT_SYMBOL(bitmap_find_free_region); + +/** + * bitmap_release_region - release allocated bitmap region + * @bitmap: a pointer to the bitmap + * @pos: the beginning of the region + * @order: the order of the bits to release (number is 1< - - * void idr_init(struct idr *idp) - - * This function is use to set up the handle (idp) that you will pass - * to the rest of the functions. The structure is defined in the - * header. - - * int idr_pre_get(struct idr *idp, unsigned gfp_mask) - - * This function should be called prior to locking and calling the - * following function. It pre allocates enough memory to satisfy the - * worst possible allocation. Unless gfp_mask is GFP_ATOMIC, it can - * sleep, so must not be called with any spinlocks held. If the system is - * REALLY out of memory this function returns 0, other wise 1. - - * int idr_get_new(struct idr *idp, void *ptr, int *id); - - * This is the allocate id function. It should be called with any - * required locks. In fact, in the SMP case, you MUST lock prior to - * calling this function to avoid possible out of memory problems. - * If memory is required, it will return -EAGAIN, you should unlock - * and go back to the idr_pre_get() call. If the idr is full, it - * will return a -ENOSPC. ptr is the pointer you want associated - * with the id. The value is returned in the "id" field. idr_get_new() - * returns a value in the range 0 ... 0x7fffffff - - * int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id); - - * Like idr_get_new(), but the returned id is guaranteed to be at or - * above start_id. - - * void *idr_find(struct idr *idp, int id); - - * returns the "ptr", given the id. A NULL return indicates that the - * id is not valid (or you passed NULL in the idr_get_new(), shame on - * you). This function must be called with a spinlock that prevents - * calling either idr_get_new() or idr_remove() or idr_find() while it - * is working. - - * void idr_remove(struct idr *idp, int id); - - * removes the given id, freeing that slot and any memory that may - * now be unused. See idr_find() for locking restrictions. - - * int idr_full(struct idr *idp); - - * Returns true if the idr is full and false if not. - */ - - #ifndef TEST // to test in user space... #include #include @@ -106,11 +32,8 @@ #include #include - static kmem_cache_t *idr_layer_cache; - - static struct idr_layer *alloc_layer(struct idr *idp) { struct idr_layer *p; @@ -137,6 +60,18 @@ static void free_layer(struct idr *idp, spin_unlock(&idp->lock); } +/** + * idr_pre_get - reserver resources for idr allocation + * @idp: idr handle + * @gfp_mask: memory allocation flags + * + * This function should be called prior to locking and calling the + * following function. It preallocates enough memory to satisfy + * the worst possible allocation. + * + * If the system is REALLY out of memory this function returns 0, + * otherwise 1. + */ int idr_pre_get(struct idr *idp, unsigned gfp_mask) { while (idp->id_free_cnt < IDR_FREE_MAX) { @@ -271,6 +206,22 @@ build_up: return(v); } +/** + * idr_get_new_above - allocate new idr entry above a start id + * @idp: idr handle + * @ptr: pointer you want associated with the ide + * @start_id: id to start search at + * @id: pointer to the allocated handle + * + * This is the allocate id function. It should be called with any + * required locks. + * + * If memory is required, it will return -EAGAIN, you should unlock + * and go back to the idr_pre_get() call. If the idr is full, it will + * return -ENOSPC. + * + * @id returns a value in the range 0 ... 0x7fffffff + */ int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id) { int rv; @@ -290,6 +241,21 @@ int idr_get_new_above(struct idr *idp, v } EXPORT_SYMBOL(idr_get_new_above); +/** + * idr_get_new - allocate new idr entry + * @idp: idr handle + * @ptr: pointer you want associated with the ide + * @id: pointer to the allocated handle + * + * This is the allocate id function. It should be called with any + * required locks. + * + * If memory is required, it will return -EAGAIN, you should unlock + * and go back to the idr_pre_get() call. If the idr is full, it will + * return -ENOSPC. + * + * @id returns a value in the range 0 ... 0x7fffffff + */ int idr_get_new(struct idr *idp, void *ptr, int *id) { int rv; @@ -338,6 +304,11 @@ static void sub_remove(struct idr *idp, } } +/** + * idr_remove - remove the given id and free it's slot + * idp: idr handle + * id: uniqueue key + */ void idr_remove(struct idr *idp, int id) { struct idr_layer *p; @@ -365,6 +336,17 @@ void idr_remove(struct idr *idp, int id) } EXPORT_SYMBOL(idr_remove); +/** + * idr_find - return pointer for given id + * @idp: idr handle + * @id: lookup key + * + * Return the pointer given the id it has been registered with. A %NULL + * return indicates that @id is not valid or you passed %NULL in + * idr_get_new(). + * + * The caller must serialize idr_find() vs idr_get_new() and idr_remove(). + */ void *idr_find(struct idr *idp, int id) { int n; @@ -372,17 +354,13 @@ void *idr_find(struct idr *idp, int id) n = idp->layers * IDR_BITS; p = idp->top; -#if 0 - /* - * This tests to see if bits outside the current tree are - * present. If so, tain't one of ours! - */ - if ( unlikely( (id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))) - return NULL; -#endif + /* Mask off upper bits we don't use for the search. */ id &= MAX_ID_MASK; + if (id >= (1 << n)) + return NULL; + while (n > 0 && p) { n -= IDR_BITS; p = p->ary[(id >> n) & IDR_MASK]; @@ -405,6 +383,13 @@ static int init_id_cache(void) return 0; } +/** + * idr_init - initialize idr handle + * @idp: idr handle + * + * This function is use to set up the handle (@idp) that you will pass + * to the rest of the functions. + */ void idr_init(struct idr *idp) { init_id_cache(); @@ -412,4 +397,3 @@ void idr_init(struct idr *idp) spin_lock_init(&idp->lock); } EXPORT_SYMBOL(idr_init); - --- linux-2.6.8-rc1/lib/kobject.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/lib/kobject.c 2004-07-13 17:09:21.000000000 -0700 @@ -537,7 +537,8 @@ void kset_unregister(struct kset * k) * @name: object's name. * * Lock kset via @kset->subsys, and iterate over @kset->list, - * looking for a matching kobject. Return object if found. + * looking for a matching kobject. If matching object is found + * take a reference and return the object. */ struct kobject * kset_find_obj(struct kset * kset, const char * name) @@ -548,8 +549,8 @@ struct kobject * kset_find_obj(struct ks down_read(&kset->subsys->rwsem); list_for_each(entry,&kset->list) { struct kobject * k = to_kobj(entry); - if (kobject_name(k) && (!strcmp(kobject_name(k),name))) { - ret = k; + if (kobject_name(k) && !strcmp(kobject_name(k),name)) { + ret = kobject_get(k); break; } } --- linux-2.6.8-rc1/lib/radix-tree.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/lib/radix-tree.c 2004-07-13 17:09:27.000000000 -0700 @@ -136,13 +136,12 @@ out: static inline void tag_set(struct radix_tree_node *node, int tag, int offset) { - if (!test_bit(offset, &node->tags[tag][0])) - __set_bit(offset, &node->tags[tag][0]); + set_bit(offset, &node->tags[tag][0]); } static inline void tag_clear(struct radix_tree_node *node, int tag, int offset) { - __clear_bit(offset, &node->tags[tag][0]); + clear_bit(offset, &node->tags[tag][0]); } static inline int tag_get(struct radix_tree_node *node, int tag, int offset) @@ -321,6 +320,11 @@ EXPORT_SYMBOL(radix_tree_lookup); * * Returns the address of the tagged item. Setting a tag on a not-present * item is a bug. + * + * radix_tree_tag_set() atomically sets the tag and does not actually + * change the overall tree structure. Consequently it is sufficient that + * the caller use an rwlock in read-mode while running + * radix_tree_tag_set(). */ void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, int tag) @@ -362,6 +366,11 @@ EXPORT_SYMBOL(radix_tree_tag_set); * * Returns the address of the tagged item on success, else NULL. ie: * has the same return value and semantics as radix_tree_lookup(). + * + * radix_tree_tag_clear() atomically sets the tag and does not actually + * change the overall tree structure. Consequently it is sufficient that + * the caller use an rwlock in read-mode while running + * radix_tree_tag_clear(). */ void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, int tag) --- linux-2.6.8-rc1/MAINTAINERS 2004-07-11 14:13:26.000000000 -0700 +++ 25/MAINTAINERS 2004-07-13 17:35:11.000000000 -0700 @@ -1218,6 +1218,12 @@ W: http://sf.net/projects/kernel-janitor W: http://developer.osdl.org/rddunlap/kj-patches/ S: Maintained +KGDB FOR I386 PLATFORM +P: George Anzinger +M: george@mvista.com +L: linux-net@vger.kernel.org +S: Supported + KERNEL NFSD P: Neil Brown M: neilb@cse.unsw.edu.au @@ -1661,6 +1667,12 @@ M: george@mvista.com L: linux-net@vger.kernel.org S: Supported +PERFORMANCE-MONITORING COUNTERS DRIVER +P: Mikael Pettersson +M: mikpe@csd.uu.se +W: http://www.csd.uu.se/~mikpe/linux/perfctr/ +S: Maintained + PNP SUPPORT P: Adam Belay M: ambx1@neo.rr.com @@ -1969,11 +1981,6 @@ M: jbglaw@lug-owl.de L: linux-kernel@vger.kernel.org S: Maintained -STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS -M: support@stallion.oz.au -W: http://www.stallion.com -S: Supported - STARFIRE/DURALAN NETWORK DRIVER P: Ion Badulescu M: ionut@cs.columbia.edu --- linux-2.6.8-rc1/Makefile 2004-07-11 14:13:26.000000000 -0700 +++ 25/Makefile 2004-07-13 17:35:09.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 8 -EXTRAVERSION =-rc1 +EXTRAVERSION =-rc1-mm1 NAME=Zonked Quokka # *DOCUMENTATION* @@ -465,6 +465,7 @@ endif ifdef CONFIG_DEBUG_INFO CFLAGS += -g +AFLAGS += -g endif # warn about C99 declaration after statement @@ -534,6 +535,8 @@ endef # set -e makes the rule exit immediately on error +# Note: Ensure that there are no undefined symbols in the final +# linked image. Not doing this can lead to silent link failures. define rule_vmlinux__ +set -e; \ $(if $(filter .tmp_kallsyms%,$^),, \ @@ -545,6 +548,12 @@ define rule_vmlinux__ $(if $($(quiet)cmd_vmlinux__), \ echo ' $($(quiet)cmd_vmlinux__)' &&) \ $(cmd_vmlinux__); \ + if $(OBJDUMP) --syms $@ | egrep -q '^([^R]|R[^E]|RE[^G])[^w]*\*UND\*'; then \ + echo 'ldchk: $@: final image has undefined symbols:'; \ + $(NM) $@ | sed 's/^ *U \(.*\)/ \1/p;d'; \ + $(RM) -f $@; \ + exit 1; \ + fi; \ echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd endef @@ -632,14 +641,24 @@ $(vmlinux-dirs): prepare-all scripts # A multi level approach is used. prepare1 is updated first, then prepare0. # prepare-all is the collection point for the prepare targets. -.PHONY: prepare-all prepare prepare0 prepare1 +.PHONY: prepare-all prepare prepare0 prepare1 prepare2 + +# prepare 2 generate Makefile to be placed in output directory, if +# using a seperate output directory. This allows convinient use +# of make in output directory +prepare2: + $(Q)if [ ! $(srctree) -ef $(objtree) ]; then \ + $(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ + $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) \ + > $(objtree)/Makefile; \ + fi # prepare1 is used to check if we are building in a separate output directory, # and if so do: # 1) Check that make has not been executed in the kernel src $(srctree) # 2) Create the include2 directory, used for the second asm symlink -prepare1: +prepare1: prepare2 ifneq ($(KBUILD_SRC),) @echo ' Using $(srctree) as source for kernel' $(Q)if [ -h $(srctree)/include/asm -o -f $(srctree)/.config ]; then \ @@ -749,6 +768,12 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_B modules_prepare: prepare-all scripts # Target to install modules +# Modules are pr. default installed in /lib/modules/$(KERNELRELEASE)/... +# Within this directory create two symlinks: +# build => link to the directory containing the output files of the kernel build +# source => link to the directory containing the source for the kernel +# source and build are equal except for the case when the kernel is build using +# a separate output directory .PHONY: modules_install modules_install: _modinst_ _modinst_post @@ -760,9 +785,13 @@ _modinst_: sleep 1; \ fi @rm -rf $(MODLIB)/kernel - @rm -f $(MODLIB)/build + @rm -f $(MODLIB)/source @mkdir -p $(MODLIB)/kernel - @ln -s $(TOPDIR) $(MODLIB)/build + @ln -s $(srctree) $(MODLIB)/source + @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \ + rm -f $(MODLIB)/build ; \ + ln -s $(objtree) $(MODLIB)/build ; \ + fi $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst # If System.map exists, run depmod. This deliberately does not have a --- linux-2.6.8-rc1/mm/filemap.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/filemap.c 2004-07-13 17:35:09.000000000 -0700 @@ -122,9 +122,9 @@ void remove_from_page_cache(struct page if (unlikely(!PageLocked(page))) PAGE_BUG(page); - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); } static inline int sync_page(struct page *page) @@ -261,7 +261,7 @@ int add_to_page_cache(struct page *page, int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); if (error == 0) { - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); error = radix_tree_insert(&mapping->page_tree, offset, page); if (!error) { page_cache_get(page); @@ -271,7 +271,7 @@ int add_to_page_cache(struct page *page, mapping->nrpages++; pagecache_acct(1); } - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); radix_tree_preload_end(); } return error; @@ -444,11 +444,11 @@ struct page * find_get_page(struct addre * We scan the hash list read-only. Addition to and removal from * the hash-list needs a held write-lock. */ - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page) page_cache_get(page); - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -461,11 +461,11 @@ struct page *find_trylock_page(struct ad { struct page *page; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); page = radix_tree_lookup(&mapping->page_tree, offset); if (page && TestSetPageLocked(page)) page = NULL; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -487,15 +487,15 @@ struct page *find_lock_page(struct addre { struct page *page; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); repeat: page = radix_tree_lookup(&mapping->page_tree, offset); if (page) { page_cache_get(page); if (TestSetPageLocked(page)) { - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); lock_page(page); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); /* Has the page been truncated while we slept? */ if (page->mapping != mapping || page->index != offset) { @@ -505,7 +505,7 @@ repeat: } } } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return page; } @@ -579,12 +579,12 @@ unsigned find_get_pages(struct address_s unsigned int i; unsigned int ret; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); ret = radix_tree_gang_lookup(&mapping->page_tree, (void **)pages, start, nr_pages); for (i = 0; i < ret; i++) page_cache_get(pages[i]); - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return ret; } @@ -598,14 +598,14 @@ unsigned find_get_pages_tag(struct addre unsigned int i; unsigned int ret; - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); ret = radix_tree_gang_lookup_tag(&mapping->page_tree, (void **)pages, *index, nr_pages, tag); for (i = 0; i < ret; i++) page_cache_get(pages[i]); if (ret) *index = pages[ret - 1]->index + 1; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); return ret; } @@ -838,7 +838,7 @@ int file_read_actor(read_descriptor_t *d */ if (!fault_in_pages_writeable(desc->buf, size)) { kaddr = kmap_atomic(page, KM_USER0); - left = __copy_to_user(desc->buf, kaddr + offset, size); + left = __copy_to_user_inatomic(desc->buf, kaddr + offset, size); kunmap_atomic(kaddr, KM_USER0); if (left == 0) goto success; @@ -1640,7 +1640,7 @@ filemap_copy_from_user(struct page *page int left; kaddr = kmap_atomic(page, KM_USER0); - left = __copy_from_user(kaddr + offset, buf, bytes); + left = __copy_from_user_inatomic(kaddr + offset, buf, bytes); kunmap_atomic(kaddr, KM_USER0); if (left != 0) { @@ -1663,7 +1663,7 @@ __filemap_copy_from_user_iovec(char *vad int copy = min(bytes, iov->iov_len - base); base = 0; - left = __copy_from_user(vaddr, buf, copy); + left = __copy_from_user_inatomic(vaddr, buf, copy); copied += copy; bytes -= copy; vaddr += copy; @@ -1812,116 +1812,64 @@ inline int generic_write_checks(struct f EXPORT_SYMBOL(generic_write_checks); -/* - * Write to a file through the page cache. - * Called under i_sem for S_ISREG files. - * - * We put everything into the page cache prior to writing it. This is not a - * problem when writing full pages. With partial pages, however, we first have - * to read the data into the cache, then dirty the page, and finally schedule - * it for writing by marking it dirty. - * okir@monad.swb.de - */ ssize_t -generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) +generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long *nr_segs, loff_t pos, loff_t *ppos, + size_t count, size_t ocount) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t written; + + if (count != ocount) + *nr_segs = iov_shorten((struct iovec *)iov, *nr_segs, count); + + written = generic_file_direct_IO(WRITE, iocb, iov, pos, *nr_segs); + if (written > 0) { + loff_t end = pos + written; + if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { + i_size_write(inode, end); + mark_inode_dirty(inode); + } + *ppos = end; + } + + /* + * Sync the fs metadata but not the minor inode changes and + * of course not the data as we did direct DMA for the IO. + * i_sem is held, which protects generic_osync_inode() from + * livelocking. + */ + if (written >= 0 && file->f_flags & O_SYNC) + generic_osync_inode(inode, mapping, OSYNC_METADATA); + if (written == count && !is_sync_kiocb(iocb)) + written = -EIOCBQUEUED; + return written; +} + +EXPORT_SYMBOL(generic_file_direct_write); + +ssize_t +generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t pos, loff_t *ppos, + size_t count, ssize_t written) { struct file *file = iocb->ki_filp; struct address_space * mapping = file->f_mapping; struct address_space_operations *a_ops = mapping->a_ops; - size_t ocount; /* original count */ - size_t count; /* after file limit checks */ struct inode *inode = mapping->host; long status = 0; - loff_t pos; struct page *page; struct page *cached_page = NULL; - const int isblk = S_ISBLK(inode->i_mode); - ssize_t written; - ssize_t err; size_t bytes; struct pagevec lru_pvec; const struct iovec *cur_iov = iov; /* current iovec */ size_t iov_base = 0; /* offset in the current iovec */ - unsigned long seg; char __user *buf; - ocount = 0; - for (seg = 0; seg < nr_segs; seg++) { - const struct iovec *iv = &iov[seg]; - - /* - * If any segment has a negative length, or the cumulative - * length ever wraps negative then return -EINVAL. - */ - ocount += iv->iov_len; - if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) - return -EINVAL; - if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) - continue; - if (seg == 0) - return -EFAULT; - nr_segs = seg; - ocount -= iv->iov_len; /* This segment is no good */ - break; - } - - count = ocount; - pos = *ppos; pagevec_init(&lru_pvec, 0); - /* We can write back this queue in page reclaim */ - current->backing_dev_info = mapping->backing_dev_info; - written = 0; - - err = generic_write_checks(file, &pos, &count, isblk); - if (err) - goto out; - - if (count == 0) - goto out; - - err = remove_suid(file->f_dentry); - if (err) - goto out; - - inode_update_time(inode, 1); - - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ - if (unlikely(file->f_flags & O_DIRECT)) { - if (count != ocount) - nr_segs = iov_shorten((struct iovec *)iov, - nr_segs, count); - written = generic_file_direct_IO(WRITE, iocb, - iov, pos, nr_segs); - if (written > 0) { - loff_t end = pos + written; - if (end > i_size_read(inode) && !isblk) { - i_size_write(inode, end); - mark_inode_dirty(inode); - } - *ppos = end; - } - /* - * Sync the fs metadata but not the minor inode changes and - * of course not the data as we did direct DMA for the IO. - * i_sem is held, which protects generic_osync_inode() from - * livelocking. - */ - if (written >= 0 && file->f_flags & O_SYNC) - status = generic_osync_inode(inode, mapping, OSYNC_METADATA); - if (written == count && !is_sync_kiocb(iocb)) - written = -EIOCBQUEUED; - if (written < 0 || written == count) - goto out_status; - /* - * direct-io write to a hole: fall through to buffered I/O - * for completing the rest of the request. - */ - pos += written; - count -= written; - } - buf = iov->iov_base + written; /* handle partial DIO write */ do { unsigned long index; @@ -2016,12 +1964,85 @@ generic_file_aio_write_nolock(struct kio if (unlikely(file->f_flags & O_DIRECT) && written) status = filemap_write_and_wait(mapping); -out_status: - err = written ? written : status; -out: pagevec_lru_add(&lru_pvec); + return written ? written : status; +} + +EXPORT_SYMBOL(generic_file_buffered_write); + +ssize_t +generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) +{ + struct file *file = iocb->ki_filp; + struct address_space * mapping = file->f_mapping; + size_t ocount; /* original count */ + size_t count; /* after file limit checks */ + struct inode *inode = mapping->host; + unsigned long seg; + loff_t pos; + ssize_t written; + ssize_t err; + + ocount = 0; + for (seg = 0; seg < nr_segs; seg++) { + const struct iovec *iv = &iov[seg]; + + /* + * If any segment has a negative length, or the cumulative + * length ever wraps negative then return -EINVAL. + */ + ocount += iv->iov_len; + if (unlikely((ssize_t)(ocount|iv->iov_len) < 0)) + return -EINVAL; + if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) + continue; + if (seg == 0) + return -EFAULT; + nr_segs = seg; + ocount -= iv->iov_len; /* This segment is no good */ + break; + } + + count = ocount; + pos = *ppos; + + /* We can write back this queue in page reclaim */ + current->backing_dev_info = mapping->backing_dev_info; + written = 0; + + err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); + if (err) + goto out; + + if (count == 0) + goto out; + + err = remove_suid(file->f_dentry); + if (err) + goto out; + + inode_update_time(inode, 1); + + /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ + if (unlikely(file->f_flags & O_DIRECT)) { + written = generic_file_direct_write(iocb, iov, + &nr_segs, pos, ppos, count, ocount); + if (written < 0 || written == count) + goto out; + /* + * direct-io write to a hole: fall through to buffered I/O + * for completing the rest of the request. + */ + pos += written; + count -= written; + } + + written = generic_file_buffered_write(iocb, iov, nr_segs, + pos, ppos, count, written); +out: current->backing_dev_info = NULL; - return err; + return written ? written : err; } EXPORT_SYMBOL(generic_file_aio_write_nolock); --- linux-2.6.8-rc1/mm/memory.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/memory.c 2004-07-13 17:35:42.000000000 -0700 @@ -567,12 +567,15 @@ int unmap_vmas(struct mmu_gather **tlbp, zap_bytes -= block; if ((long)zap_bytes > 0) continue; - if (!atomic && need_resched()) { + if (!atomic) { int fullmm = tlb_is_full_mm(*tlbp); + tlb_finish_mmu(*tlbp, tlb_start, start); - cond_resched_lock(&mm->page_table_lock); - *tlbp = tlb_gather_mmu(mm, fullmm); + spin_unlock(&mm->page_table_lock); + cond_resched(); tlb_start_valid = 0; + spin_lock(&mm->page_table_lock); + *tlbp = tlb_gather_mmu(mm, fullmm); } zap_bytes = ZAP_BLOCK_SIZE; } @@ -705,7 +708,9 @@ int get_user_pages(struct task_struct *t struct page **pages, struct vm_area_struct **vmas) { int i; + int vm_io; unsigned int flags; + int nr_pages = 0; /* * Require read or write permissions. @@ -727,7 +732,7 @@ int get_user_pages(struct task_struct *t pte_t *pte; if (write) /* user gate pages are read-only */ return i ? : -EFAULT; - pgd = pgd_offset(mm, pg); + pgd = pgd_offset_gate(mm, pg); if (!pgd) return i ? : -EFAULT; pmd = pmd_offset(pgd, pg); @@ -753,9 +758,11 @@ int get_user_pages(struct task_struct *t continue; } - if (!vma || (pages && (vma->vm_flags & VM_IO)) - || !(flags & vma->vm_flags)) - return i ? : -EFAULT; + if (!vma) + return i ? i : -EFAULT; + vm_io = vma->vm_flags & VM_IO; + if ((pages && vm_io) || !(flags & vma->vm_flags)) + return i ? i : -EFAULT; if (is_vm_hugetlb_page(vma)) { i = follow_hugetlb_page(mm, vma, pages, vmas, @@ -764,8 +771,21 @@ int get_user_pages(struct task_struct *t } spin_lock(&mm->page_table_lock); do { - struct page *map; + struct page *map = NULL; int lookup_write = write; + + if ((++nr_pages & 63) == 0) { + spin_unlock(&mm->page_table_lock); + cpu_relax(); + spin_lock(&mm->page_table_lock); + } + + /* + * We don't follow pagetables for VM_IO regions - they + * may have no pageframes. + */ + if (vm_io) + goto no_follow; while (!(map = follow_page(mm, start, lookup_write))) { /* * Shortcut for anonymous pages. We don't want @@ -817,6 +837,7 @@ int get_user_pages(struct task_struct *t if (!PageReserved(pages[i])) page_cache_get(pages[i]); } +no_follow: if (vmas) vmas[i] = vma; i++; --- linux-2.6.8-rc1/mm/mempool.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/mempool.c 2004-07-13 17:09:51.000000000 -0700 @@ -194,6 +194,7 @@ void * mempool_alloc(mempool_t *pool, in DEFINE_WAIT(wait); int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO); + might_sleep_if(gfp_mask & __GFP_WAIT); repeat_alloc: element = pool->alloc(gfp_nowait|__GFP_NOWARN, pool->pool_data); if (likely(element != NULL)) --- linux-2.6.8-rc1/mm/mmap.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/mmap.c 2004-07-13 17:09:38.000000000 -0700 @@ -1013,7 +1013,7 @@ EXPORT_SYMBOL(do_mmap_pgoff); * This function "knows" that -ENOMEM has the bits set. */ #ifndef HAVE_ARCH_UNMAPPED_AREA -static inline unsigned long +unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { @@ -1057,12 +1057,116 @@ full_search: addr = vma->vm_end; } } -#else -extern unsigned long -arch_get_unmapped_area(struct file *, unsigned long, unsigned long, - unsigned long, unsigned long); #endif +void arch_unmap_area(struct vm_area_struct *area) +{ + /* + * Is this a new hole at the lowest possible address? + */ + if (area->vm_start >= TASK_UNMAPPED_BASE && + area->vm_start < area->vm_mm->free_area_cache) + area->vm_mm->free_area_cache = area->vm_start; +} + +/* + * This mmap-allocator allocates new areas top-down from below the + * stack's low limit (the base): + */ +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma, *prev_vma; + struct mm_struct *mm = current->mm; + unsigned long base = mm->mmap_base, addr = addr0; + int first_time = 1; + + /* requested length too big for entire address space */ + if (len > TASK_SIZE) + return -ENOMEM; + + /* dont allow allocations above current base */ + if (mm->free_area_cache > base) + mm->free_area_cache = base; + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + +try_again: + /* make sure it can fit in the remaining address space */ + if (mm->free_area_cache < len) + goto fail; + + /* either no address requested or cant fit in requested address hole */ + addr = (mm->free_area_cache - len) & PAGE_MASK; + do { + /* + * Lookup failure means no vma is above this address, + * i.e. return with success: + */ + if (!(vma = find_vma_prev(mm, addr, &prev_vma))) + return addr; + + /* + * new region fits between prev_vma->vm_end and + * vma->vm_start, use it: + */ + if (addr+len <= vma->vm_start && + (!prev_vma || (addr >= prev_vma->vm_end))) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr); + else + /* pull free_area_cache down to the first hole */ + if (mm->free_area_cache == vma->vm_end) + mm->free_area_cache = vma->vm_start; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + } while (len <= vma->vm_start); + +fail: + /* + * if hint left us with no space for the requested + * mapping then try again: + */ + if (first_time) { + mm->free_area_cache = base; + first_time = 0; + goto try_again; + } + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + mm->free_area_cache = TASK_UNMAPPED_BASE; + addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + /* + * Restore the topdown base: + */ + mm->free_area_cache = base; + + return addr; +} + +void arch_unmap_area_topdown(struct vm_area_struct *area) +{ + /* + * Is this a new hole at the highest possible address? + */ + if (area->vm_end > area->vm_mm->free_area_cache) + area->vm_mm->free_area_cache = area->vm_end; +} + unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) @@ -1097,7 +1201,7 @@ get_unmapped_area(struct file *file, uns return file->f_op->get_unmapped_area(file, addr, len, pgoff, flags); - return arch_get_unmapped_area(file, addr, len, pgoff, flags); + return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); } EXPORT_SYMBOL(get_unmapped_area); @@ -1387,13 +1491,7 @@ static void unmap_vma(struct mm_struct * area->vm_mm->total_vm -= len >> PAGE_SHIFT; if (area->vm_flags & VM_LOCKED) area->vm_mm->locked_vm -= len >> PAGE_SHIFT; - /* - * Is this a new hole at the lowest possible address? - */ - if (area->vm_start >= TASK_UNMAPPED_BASE && - area->vm_start < area->vm_mm->free_area_cache) - area->vm_mm->free_area_cache = area->vm_start; - + area->vm_mm->unmap_area(area); remove_vm_struct(area); } --- linux-2.6.8-rc1/mm/msync.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/msync.c 2004-07-13 17:35:41.000000000 -0700 @@ -92,8 +92,8 @@ static inline int filemap_sync_pmd_range return error; } -static int filemap_sync(struct vm_area_struct * vma, unsigned long address, - size_t size, unsigned int flags) +static int __filemap_sync(struct vm_area_struct *vma, unsigned long address, + size_t size, unsigned int flags) { pgd_t * dir; unsigned long end = address + size; @@ -131,6 +131,30 @@ static int filemap_sync(struct vm_area_s return error; } +#ifdef CONFIG_PREEMPT +static int filemap_sync(struct vm_area_struct *vma, unsigned long address, + size_t size, unsigned int flags) +{ + const size_t chunk = 64 * 1024; /* bytes */ + int error = 0; + + while (size) { + size_t sz = min(size, chunk); + + error |= __filemap_sync(vma, address, sz, flags); + address += sz; + size -= sz; + } + return error; +} +#else +static int filemap_sync(struct vm_area_struct *vma, unsigned long address, + size_t size, unsigned int flags) +{ + return __filemap_sync(vma, address, size, flags); +} +#endif + /* * MS_SYNC syncs the entire file - including mappings. * --- linux-2.6.8-rc1/mm/page_alloc.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/page_alloc.c 2004-07-13 17:35:10.000000000 -0700 @@ -279,6 +279,8 @@ void __free_pages_ok(struct page *page, LIST_HEAD(list); int i; + arch_free_page(page, order); + mod_page_state(pgfree, 1 << order); for (i = 0 ; i < (1 << order) ; ++i) free_pages_check(__FUNCTION__, page + i); @@ -509,6 +511,8 @@ static void fastcall free_hot_cold_page( struct per_cpu_pages *pcp; unsigned long flags; + arch_free_page(page, 0); + kernel_map_pages(page, 1, 0); inc_page_state(pgfree); free_pages_check(__FUNCTION__, page); @@ -2000,31 +2004,30 @@ void *__init alloc_large_system_hash(con unsigned int *_hash_shift, unsigned int *_hash_mask) { - unsigned long mem, max, log2qty, size; + unsigned long max, log2qty, size; void *table; - /* round applicable memory size up to nearest megabyte */ - mem = consider_highmem ? nr_all_pages : nr_kernel_pages; - mem += (1UL << (20 - PAGE_SHIFT)) - 1; - mem >>= 20 - PAGE_SHIFT; - mem <<= 20 - PAGE_SHIFT; - - /* limit to 1 bucket per 2^scale bytes of low memory (rounded up to - * nearest power of 2 in size) */ - if (scale > PAGE_SHIFT) - mem >>= (scale - PAGE_SHIFT); - else - mem <<= (PAGE_SHIFT - scale); - - mem = 1UL << (long_log2(mem) + 1); + /* allow the kernel cmdline to have a say */ + if (!numentries) { + /* round applicable memory size up to nearest megabyte */ + numentries = consider_highmem ? nr_all_pages : nr_kernel_pages; + numentries += (1UL << (20 - PAGE_SHIFT)) - 1; + numentries >>= 20 - PAGE_SHIFT; + numentries <<= 20 - PAGE_SHIFT; + + /* limit to 1 bucket per 2^scale bytes of low memory */ + if (scale > PAGE_SHIFT) + numentries >>= (scale - PAGE_SHIFT); + else + numentries <<= (PAGE_SHIFT - scale); + } + /* rounded up to nearest power of 2 in size */ + numentries = 1UL << (long_log2(numentries) + 1); - /* limit allocation size */ - max = (1UL << (PAGE_SHIFT + MAX_SYS_HASH_TABLE_ORDER)) / bucketsize; - if (max > mem) - max = mem; + /* limit allocation size to 1/16 total memory */ + max = ((nr_all_pages << PAGE_SHIFT)/16) / bucketsize; - /* allow the kernel cmdline to have a say */ - if (!numentries || numentries > max) + if (numentries > max) numentries = max; log2qty = long_log2(numentries); --- linux-2.6.8-rc1/mm/page-writeback.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/mm/page-writeback.c 2004-07-13 17:09:27.000000000 -0700 @@ -582,7 +582,7 @@ int __set_page_dirty_nobuffers(struct pa struct address_space *mapping = page_mapping(page); if (mapping) { - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); mapping = page_mapping(page); if (page_mapping(page)) { /* Race with truncate? */ BUG_ON(page_mapping(page) != mapping); @@ -591,7 +591,7 @@ int __set_page_dirty_nobuffers(struct pa radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); if (mapping->host) { /* !PageAnon && !swapper_space */ __mark_inode_dirty(mapping->host, @@ -666,17 +666,17 @@ int test_clear_page_dirty(struct page *p unsigned long flags; if (mapping) { - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); if (TestClearPageDirty(page)) { radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); if (!mapping->backing_dev_info->memory_backed) dec_page_state(nr_dirty); return 1; } - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); return 0; } return TestClearPageDirty(page); @@ -723,15 +723,15 @@ int __clear_page_dirty(struct page *page if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); if (TestClearPageDirty(page)) { radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); return 1; } - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); return 0; } return TestClearPageDirty(page); @@ -745,13 +745,13 @@ int test_clear_page_writeback(struct pag if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); ret = TestClearPageWriteback(page); if (ret) radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_WRITEBACK); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestClearPageWriteback(page); } @@ -766,7 +766,7 @@ int test_set_page_writeback(struct page if (mapping) { unsigned long flags; - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); ret = TestSetPageWriteback(page); if (!ret) radix_tree_tag_set(&mapping->page_tree, @@ -776,7 +776,7 @@ int test_set_page_writeback(struct page radix_tree_tag_clear(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); } else { ret = TestSetPageWriteback(page); } @@ -794,9 +794,9 @@ int mapping_tagged(struct address_space unsigned long flags; int ret; - spin_lock_irqsave(&mapping->tree_lock, flags); + read_lock_irqsave(&mapping->tree_lock, flags); ret = radix_tree_tagged(&mapping->page_tree, tag); - spin_unlock_irqrestore(&mapping->tree_lock, flags); + read_unlock_irqrestore(&mapping->tree_lock, flags); return ret; } EXPORT_SYMBOL(mapping_tagged); --- linux-2.6.8-rc1/mm/readahead.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/mm/readahead.c 2004-07-13 17:09:27.000000000 -0700 @@ -234,7 +234,7 @@ __do_page_cache_readahead(struct address /* * Preallocate as many pages as we will need. */ - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); for (page_idx = 0; page_idx < nr_to_read; page_idx++) { unsigned long page_offset = offset + page_idx; @@ -245,16 +245,16 @@ __do_page_cache_readahead(struct address if (page) continue; - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); page = page_cache_alloc_cold(mapping); - spin_lock_irq(&mapping->tree_lock); + read_lock_irq(&mapping->tree_lock); if (!page) break; page->index = page_offset; list_add(&page->lru, &page_pool); ret++; } - spin_unlock_irq(&mapping->tree_lock); + read_unlock_irq(&mapping->tree_lock); /* * Now start the IO. We ignore I/O errors - if the page is not --- linux-2.6.8-rc1/mm/slab.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/slab.c 2004-07-13 17:35:41.000000000 -0700 @@ -2434,6 +2434,27 @@ void kmem_cache_free (kmem_cache_t *cach EXPORT_SYMBOL(kmem_cache_free); /** + * kcalloc - allocate memory for an array. The memory is set to zero. + * @n: number of elements. + * @size: element size. + * @flags: the type of memory to allocate. + */ +void *kcalloc(size_t n, size_t size, int flags) +{ + void *ret = NULL; + + if (n != 0 && size > INT_MAX / n) + return ret; + + ret = kmalloc(n * size, flags); + if (ret) + memset(ret, 0, n * size); + return ret; +} + +EXPORT_SYMBOL(kcalloc); + +/** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. * @@ -2624,6 +2645,10 @@ static void enable_cpucache (kmem_cache_ if (limit > 32) limit = 32; #endif +#ifdef CONFIG_PREEMPT + if (limit > 16) + limit = 16; +#endif err = do_tune_cpucache(cachep, limit, (limit+1)/2, shared); if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", --- linux-2.6.8-rc1/mm/swapfile.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/swapfile.c 2004-07-13 17:09:27.000000000 -0700 @@ -290,10 +290,10 @@ static int exclusive_swap_page(struct pa /* Is the only swap cache user the cache itself? */ if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the swapcache lock held.. */ - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); if (page_count(page) == 2) retval = 1; - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); } @@ -361,13 +361,13 @@ int remove_exclusive_swap_page(struct pa retval = 0; if (p->swap_map[swp_offset(entry)] == 1) { /* Recheck the page count with the swapcache lock held.. */ - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); if ((page_count(page) == 2) && !PageWriteback(page)) { __delete_from_swap_cache(page); SetPageDirty(page); retval = 1; } - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); @@ -391,12 +391,12 @@ void free_swap_and_cache(swp_entry_t ent p = swap_info_get(entry); if (p) { if (swap_entry_free(p, swp_offset(entry)) == 1) { - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (page && TestSetPageLocked(page)) page = NULL; - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); } swap_info_put(p); } --- linux-2.6.8-rc1/mm/swap_state.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/mm/swap_state.c 2004-07-13 17:09:27.000000000 -0700 @@ -35,7 +35,7 @@ static struct backing_dev_info swap_back struct address_space swapper_space = { .page_tree = RADIX_TREE_INIT(GFP_ATOMIC), - .tree_lock = SPIN_LOCK_UNLOCKED, + .tree_lock = RW_LOCK_UNLOCKED, .a_ops = &swap_aops, .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), .backing_dev_info = &swap_backing_dev_info, @@ -74,7 +74,7 @@ static int __add_to_swap_cache(struct pa BUG_ON(PagePrivate(page)); error = radix_tree_preload(gfp_mask); if (!error) { - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); error = radix_tree_insert(&swapper_space.page_tree, entry.val, page); if (!error) { @@ -85,7 +85,7 @@ static int __add_to_swap_cache(struct pa total_swapcache_pages++; pagecache_acct(1); } - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); radix_tree_preload_end(); } return error; @@ -212,9 +212,9 @@ void delete_from_swap_cache(struct page entry.val = page->private; - spin_lock_irq(&swapper_space.tree_lock); + write_lock_irq(&swapper_space.tree_lock); __delete_from_swap_cache(page); - spin_unlock_irq(&swapper_space.tree_lock); + write_unlock_irq(&swapper_space.tree_lock); swap_free(entry); page_cache_release(page); @@ -313,13 +313,13 @@ struct page * lookup_swap_cache(swp_entr { struct page *page; - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (page) { page_cache_get(page); INC_CACHE_INFO(find_success); } - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); INC_CACHE_INFO(find_total); return page; } @@ -342,12 +342,12 @@ struct page *read_swap_cache_async(swp_e * called after lookup_swap_cache() failed, re-calling * that would confuse statistics. */ - spin_lock_irq(&swapper_space.tree_lock); + read_lock_irq(&swapper_space.tree_lock); found_page = radix_tree_lookup(&swapper_space.page_tree, entry.val); if (found_page) page_cache_get(found_page); - spin_unlock_irq(&swapper_space.tree_lock); + read_unlock_irq(&swapper_space.tree_lock); if (found_page) break; --- linux-2.6.8-rc1/mm/truncate.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/truncate.c 2004-07-13 17:35:41.000000000 -0700 @@ -74,13 +74,13 @@ invalidate_complete_page(struct address_ if (PagePrivate(page) && !try_to_release_page(page, 0)) return 0; - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); if (PageDirty(page)) { - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); return 0; } __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); ClearPageUptodate(page); page_cache_release(page); /* pagecache ref */ return 1; @@ -155,6 +155,7 @@ void truncate_inode_pages(struct address next = start; for ( ; ; ) { + cond_resched(); if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { if (next == start) break; --- linux-2.6.8-rc1/mm/vmalloc.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/vmalloc.c 2004-07-13 17:09:21.000000000 -0700 @@ -179,11 +179,26 @@ int map_vm_area(struct vm_struct *area, return err; } +#define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */ + struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end) { struct vm_struct **p, *tmp, *area; - unsigned long addr = start; + unsigned long align = 1; + unsigned long addr; + + if (flags & VM_IOREMAP) { + int bit = fls(size); + + if (bit > IOREMAP_MAX_ORDER) + bit = IOREMAP_MAX_ORDER; + else if (bit < PAGE_SHIFT) + bit = PAGE_SHIFT; + + align = 1ul << bit; + } + addr = ALIGN(start, align); area = kmalloc(sizeof(*area), GFP_KERNEL); if (unlikely(!area)) @@ -200,13 +215,17 @@ struct vm_struct *__get_vm_area(unsigned write_lock(&vmlist_lock); for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) { - if ((unsigned long)tmp->addr < addr) + if ((unsigned long)tmp->addr < addr) { + if((unsigned long)tmp->addr + tmp->size >= addr) + addr = ALIGN(tmp->size + + (unsigned long)tmp->addr, align); continue; + } if ((size + addr) < addr) goto out; if (size + addr <= (unsigned long)tmp->addr) goto found; - addr = tmp->size + (unsigned long)tmp->addr; + addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align); if (addr > end - size) goto out; } --- linux-2.6.8-rc1/mm/vmscan.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/mm/vmscan.c 2004-07-13 17:09:27.000000000 -0700 @@ -474,7 +474,7 @@ static int shrink_list(struct list_head if (!mapping) goto keep_locked; /* truncate got there first */ - spin_lock_irq(&mapping->tree_lock); + write_lock_irq(&mapping->tree_lock); /* * The non-racy check for busy page. It is critical to check @@ -482,7 +482,7 @@ static int shrink_list(struct list_head * not in use by anybody. (pagecache + us == 2) */ if (page_count(page) != 2 || PageDirty(page)) { - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); goto keep_locked; } @@ -490,7 +490,7 @@ static int shrink_list(struct list_head if (PageSwapCache(page)) { swp_entry_t swap = { .val = page->private }; __delete_from_swap_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); swap_free(swap); __put_page(page); /* The pagecache ref */ goto free_it; @@ -498,7 +498,7 @@ static int shrink_list(struct list_head #endif /* CONFIG_SWAP */ __remove_from_page_cache(page); - spin_unlock_irq(&mapping->tree_lock); + write_unlock_irq(&mapping->tree_lock); __put_page(page); free_it: --- linux-2.6.8-rc1/net/atm/clip.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/atm/clip.c 2004-07-13 17:09:13.000000000 -0700 @@ -998,7 +998,7 @@ static int __init atm_clip_init(void) /* so neigh_ifdown() doesn't complain */ clip_tbl.proxy_timer.data = 0; - clip_tbl.proxy_timer.function = 0; + clip_tbl.proxy_timer.function = NULL; init_timer(&clip_tbl.proxy_timer); skb_queue_head_init(&clip_tbl.proxy_queue); --- linux-2.6.8-rc1/net/atm/signaling.c 2003-10-08 15:07:10.000000000 -0700 +++ 25/net/atm/signaling.c 2004-07-13 17:09:13.000000000 -0700 @@ -135,7 +135,7 @@ static int sigd_send(struct atm_vcc *vcc lock_sock(vcc->sk); if (vcc->sk->sk_ack_backlog == vcc->sk->sk_max_ack_backlog) { - sigd_enq(0,as_reject,vcc,NULL,NULL); + sigd_enq(NULL,as_reject,vcc,NULL,NULL); goto as_indicate_complete; } vcc->sk->sk_ack_backlog++; --- linux-2.6.8-rc1/net/bluetooth/af_bluetooth.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/bluetooth/af_bluetooth.c 2004-07-13 17:09:13.000000000 -0700 @@ -354,7 +354,7 @@ static int __init bt_init(void) /* Init socket cache */ bt_sock_cache = kmem_cache_create("bt_sock", sizeof(struct bt_sock), 0, - SLAB_HWCACHE_ALIGN, 0, 0); + SLAB_HWCACHE_ALIGN, NULL, NULL); if (!bt_sock_cache) { BT_ERR("Socket cache creation failed"); --- linux-2.6.8-rc1/net/bluetooth/hci_sysfs.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/bluetooth/hci_sysfs.c 2004-07-13 17:09:13.000000000 -0700 @@ -91,7 +91,7 @@ static int bt_hotplug(struct class_devic if ((size <= 0) || (i >= num_envp)) return -ENOMEM; - envp[i] = 0; + envp[i] = NULL; return 0; } #endif --- linux-2.6.8-rc1/net/bluetooth/l2cap.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/bluetooth/l2cap.c 2004-07-13 17:09:13.000000000 -0700 @@ -57,7 +57,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.2" +#define VERSION "2.3" static struct proto_ops l2cap_sock_ops; @@ -718,8 +718,7 @@ fail: return err; } -static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len) +static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; int err = 0; @@ -1444,7 +1443,7 @@ static inline int l2cap_connect_rsp(stru struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; struct sock *sk; - char req[128]; + u8 req[128]; scid = __le16_to_cpu(rsp->scid); dcid = __le16_to_cpu(rsp->dcid); @@ -1481,7 +1480,7 @@ static inline int l2cap_config_req(struc { struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; u16 dcid, flags; - u8 rsp[64]; + u8 rsp[64]; struct sock *sk; int result; @@ -1633,6 +1632,35 @@ static inline int l2cap_disconnect_rsp(s return 0; } +static inline int l2cap_info_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_info_req *req = (struct l2cap_info_req *) data; + struct l2cap_info_rsp rsp; + u16 type; + + type = __le16_to_cpu(req->type); + + BT_DBG("type 0x%4.4x", type); + + rsp.type = __cpu_to_le16(type); + rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP); + l2cap_send_rsp(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp); + return 0; +} + +static inline int l2cap_info_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) +{ + struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; + u16 type, result; + + type = __le16_to_cpu(rsp->type); + result = __le16_to_cpu(rsp->result); + + BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + + return 0; +} + static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { u8 *data = skb->data; @@ -1657,6 +1685,10 @@ static inline void l2cap_sig_channel(str } switch (cmd.code) { + case L2CAP_COMMAND_REJ: + /* FIXME: We should process this */ + break; + case L2CAP_CONN_REQ: err = l2cap_connect_req(conn, &cmd, data); break; @@ -1681,17 +1713,19 @@ static inline void l2cap_sig_channel(str err = l2cap_disconnect_rsp(conn, &cmd, data); break; - case L2CAP_COMMAND_REJ: - /* FIXME: We should process this */ - break; - case L2CAP_ECHO_REQ: l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); break; case L2CAP_ECHO_RSP: + break; + case L2CAP_INFO_REQ: + err = l2cap_info_req(conn, &cmd, data); + break; + case L2CAP_INFO_RSP: + err = l2cap_info_rsp(conn, &cmd, data); break; default: @@ -1704,7 +1738,7 @@ static inline void l2cap_sig_channel(str struct l2cap_cmd_rej rej; BT_DBG("error %d", err); - /* FIXME: Map err to a valid reason. */ + /* FIXME: Map err to a valid reason */ rej.reason = __cpu_to_le16(0); l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); } @@ -1737,7 +1771,7 @@ static inline int l2cap_data_channel(str /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. * But we don't have any other choice. L2CAP doesn't - * provide flow control mechanism */ + * provide flow control mechanism. */ if (!sock_queue_rcv_skb(sk, skb)) goto done; @@ -2210,7 +2244,7 @@ EXPORT_SYMBOL(l2cap_load); module_init(l2cap_init); module_exit(l2cap_exit); -MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); --- linux-2.6.8-rc1/net/bridge/br_device.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/bridge/br_device.c 2004-07-13 17:09:13.000000000 -0700 @@ -89,6 +89,15 @@ static int br_dev_stop(struct net_device return 0; } +static int br_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || new_mtu > br_min_mtu(dev->priv)) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; +} + static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) { return -1; @@ -105,6 +114,7 @@ void br_dev_setup(struct net_device *dev dev->hard_start_xmit = br_dev_xmit; dev->open = br_dev_open; dev->set_multicast_list = br_dev_set_multicast_list; + dev->change_mtu = br_change_mtu; dev->destructor = free_netdev; SET_MODULE_OWNER(dev); dev->stop = br_dev_stop; --- linux-2.6.8-rc1/net/bridge/br_forward.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/bridge/br_forward.c 2004-07-13 17:09:13.000000000 -0700 @@ -23,6 +23,7 @@ static inline int should_deliver(const s const struct sk_buff *skb) { if (skb->dev == p->dev || + skb->len > p->dev->mtu || p->state != BR_STATE_FORWARDING) return 0; --- linux-2.6.8-rc1/net/bridge/br_if.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/bridge/br_if.c 2004-07-13 17:09:13.000000000 -0700 @@ -295,6 +295,24 @@ int br_del_bridge(const char *name) return ret; } +int br_min_mtu(const struct net_bridge *br) +{ + const struct net_bridge_port *p; + int mtu = 0; + + ASSERT_RTNL(); + + if (list_empty(&br->port_list)) + mtu = 1500; + else { + list_for_each_entry(p, &br->port_list, list) { + if (!mtu || p->dev->mtu < mtu) + mtu = p->dev->mtu; + } + } + return mtu; +} + /* called with RTNL */ int br_add_if(struct net_bridge *br, struct net_device *dev) { @@ -328,6 +346,8 @@ int br_add_if(struct net_bridge *br, str if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP)) br_stp_enable_port(p); spin_unlock_bh(&br->lock); + + br->dev->mtu = br_min_mtu(br); } return err; --- linux-2.6.8-rc1/net/bridge/br_notify.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/bridge/br_notify.c 2004-07-13 17:09:13.000000000 -0700 @@ -47,6 +47,10 @@ static int br_device_event(struct notifi spin_unlock_bh(&br->lock); break; + case NETDEV_CHANGEMTU: + br->dev->mtu = br_min_mtu(br); + break; + case NETDEV_DOWN: if (br->dev->flags & IFF_UP) { spin_lock_bh(&br->lock); --- linux-2.6.8-rc1/net/bridge/br_private.h 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/bridge/br_private.h 2004-07-13 17:09:13.000000000 -0700 @@ -168,6 +168,7 @@ extern int br_add_if(struct net_bridge * struct net_device *dev); extern int br_del_if(struct net_bridge *br, struct net_device *dev); +extern int br_min_mtu(const struct net_bridge *br); /* br_input.c */ extern int br_handle_frame_finish(struct sk_buff *skb); --- linux-2.6.8-rc1/net/core/dev.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/core/dev.c 2004-07-13 17:09:26.000000000 -0700 @@ -1577,7 +1577,6 @@ static void sample_queue(unsigned long d } #endif - /** * netif_rx - post buffer to the network code * @skb: buffer to post @@ -1967,7 +1966,6 @@ static void net_rx_action(struct softirq unsigned long start_time = jiffies; int budget = netdev_max_backlog; - local_irq_disable(); while (!list_empty(&queue->poll_list)) { @@ -1993,6 +1991,10 @@ static void net_rx_action(struct softirq dev_put(dev); local_irq_disable(); } + +#ifdef CONFIG_KGDBOE + kgdb_process_breakpoint(); +#endif } out: local_irq_enable(); --- linux-2.6.8-rc1/net/core/pktgen.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/core/pktgen.c 2004-07-13 17:09:13.000000000 -0700 @@ -1355,7 +1355,7 @@ static int __init init(void) pginfos[i].udp_dst_max = 9; sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i); - pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0); + pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, NULL); if (!pginfos[i].proc_ent) { printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR); goto cleanup_mem; @@ -1366,7 +1366,7 @@ static int __init init(void) pginfos[i].proc_ent->owner = THIS_MODULE; sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i); - pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0); + pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, NULL); if (!pginfos[i].busy_proc_ent) { printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR); goto cleanup_mem; --- linux-2.6.8-rc1/net/core/sock.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/core/sock.c 2004-07-13 17:09:13.678193472 -0700 @@ -711,6 +711,27 @@ void sock_rfree(struct sk_buff *skb) atomic_sub(skb->truesize, &sk->sk_rmem_alloc); } + +int sock_i_uid(struct sock *sk) +{ + int uid; + + read_lock(&sk->sk_callback_lock); + uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0; + read_unlock(&sk->sk_callback_lock); + return uid; +} + +unsigned long sock_i_ino(struct sock *sk) +{ + unsigned long ino; + + read_lock(&sk->sk_callback_lock); + ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; + read_unlock(&sk->sk_callback_lock); + return ino; +} + /* * Allocate a skb from the socket's send buffer. */ @@ -1379,6 +1400,8 @@ EXPORT_SYMBOL(sock_rmalloc); EXPORT_SYMBOL(sock_setsockopt); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); +EXPORT_SYMBOL(sock_i_uid); +EXPORT_SYMBOL(sock_i_ino); #ifdef CONFIG_SYSCTL EXPORT_SYMBOL(sysctl_optmem_max); EXPORT_SYMBOL(sysctl_rmem_max); --- linux-2.6.8-rc1/net/econet/af_econet.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/econet/af_econet.c 2004-07-13 17:09:13.000000000 -0700 @@ -1091,7 +1091,7 @@ static int econet_notifier(struct notifi if (edev) { if (net2dev_map[0] == dev) - net2dev_map[0] = 0; + net2dev_map[0] = NULL; net2dev_map[edev->net] = NULL; kfree(edev); dev->ec_ptr = NULL; --- linux-2.6.8-rc1/net/ipv4/ah4.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/ah4.c 2004-07-13 17:09:13.000000000 -0700 @@ -67,52 +67,24 @@ static int ah_output(struct sk_buff **ps char buf[60]; } tmp_iph; - if ((*pskb)->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - if (err) - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, *pskb); - if (err) - goto error; + top_iph = (*pskb)->nh.iph; + iph = &tmp_iph.iph; - iph = (*pskb)->nh.iph; - if (x->props.mode) { - err = xfrm4_tunnel_check_size(*pskb); + iph->tos = top_iph->tos; + iph->ttl = top_iph->ttl; + iph->frag_off = top_iph->frag_off; + iph->daddr = top_iph->daddr; + + if (top_iph->ihl != 5) { + memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); + err = ip_clear_mutable_options(top_iph, &top_iph->daddr); if (err) goto error; - top_iph = (struct iphdr*)skb_push(*pskb, x->props.header_len); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = iph->tos; - if (x->props.flags & XFRM_STATE_NOECN) - IP_ECN_clear(top_iph); - top_iph->frag_off = iph->frag_off & ~htons(IP_MF|IP_OFFSET); - if (!(iph->frag_off&htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memcpy(&tmp_iph, top_iph, 20); - memset(&(IPCB(*pskb)->opt), 0, sizeof(struct ip_options)); - ah = (struct ip_auth_hdr*)(top_iph+1); - ah->nexthdr = IPPROTO_IPIP; - } else { - memcpy(&tmp_iph, (*pskb)->data, iph->ihl*4); - top_iph = (struct iphdr*)skb_push(*pskb, x->props.header_len); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - if (top_iph->ihl != 5) { - err = ip_clear_mutable_options(top_iph, &top_iph->daddr); - if (err) - goto error; - } - ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); - ah->nexthdr = iph->protocol; } - iph = &tmp_iph.iph; + ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4); + ah->nexthdr = top_iph->protocol; + top_iph->tos = 0; top_iph->tot_len = htons((*pskb)->len); top_iph->frag_off = 0; @@ -128,31 +100,19 @@ static int ah_output(struct sk_buff **ps ah->spi = x->id.spi; ah->seq_no = htonl(++x->replay.oseq); ahp->icv(ahp, *pskb, ah->auth_data); + top_iph->tos = iph->tos; top_iph->ttl = iph->ttl; top_iph->frag_off = iph->frag_off; - if (!x->props.mode) { - top_iph->daddr = iph->daddr; - if (iph->ihl != 5) - memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); - } - ip_send_check(top_iph); + top_iph->daddr = iph->daddr; + if (top_iph->ihl != 5) + memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); - (*pskb)->nh.raw = (*pskb)->data; + ip_send_check(top_iph); - x->curlft.bytes += (*pskb)->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if (((*pskb)->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; + err = 0; error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(*pskb); return err; } --- linux-2.6.8-rc1/net/ipv4/esp4.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/esp4.c 2004-07-13 17:09:13.000000000 -0700 @@ -23,7 +23,7 @@ int esp_output(struct sk_buff **pskb) int err; struct dst_entry *dst = (*pskb)->dst; struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; + struct iphdr *top_iph; struct ip_esp_hdr *esph; struct crypto_tfm *tfm; struct esp_data *esp; @@ -32,32 +32,9 @@ int esp_output(struct sk_buff **pskb) int clen; int alen; int nfrags; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; - - if ((*pskb)->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - if (err) - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, *pskb); - if (err) - goto error; - if (x->props.mode) { - err = xfrm4_tunnel_check_size(*pskb); - if (err) - goto error; - } else { - /* Strip IP header in transport mode. Save it. */ - iph = (*pskb)->nh.iph; - memcpy(&tmp_iph, iph, iph->ihl*4); - __skb_pull(*pskb, iph->ihl*4); - } + /* Strip IP+ESP header. */ + __skb_pull(*pskb, (*pskb)->h.raw - (*pskb)->data); /* Now skb is pure payload to encrypt */ err = -ENOMEM; @@ -85,35 +62,11 @@ int esp_output(struct sk_buff **pskb) *(u8*)(trailer->tail + clen-(*pskb)->len - 2) = (clen - (*pskb)->len)-2; pskb_put(*pskb, trailer, clen - (*pskb)->len); - iph = (*pskb)->nh.iph; - if (x->props.mode) { - top_iph = (struct iphdr*)skb_push(*pskb, x->props.header_len); - esph = (struct ip_esp_hdr*)(top_iph+1); - *(u8*)(trailer->tail - 1) = IPPROTO_IPIP; - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = iph->tos; /* DS disclosed */ - if (x->props.flags & XFRM_STATE_NOECN) - IP_ECN_clear(top_iph); - top_iph->tot_len = htons((*pskb)->len + alen); - top_iph->frag_off = iph->frag_off&htons(IP_DF); - if (!(top_iph->frag_off)) - ip_select_ident(top_iph, dst, NULL); - top_iph->ttl = iph->ttl; /* TTL disclosed */ - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memset(&(IPCB(*pskb)->opt), 0, sizeof(struct ip_options)); - } else { - esph = (struct ip_esp_hdr*)skb_push(*pskb, x->props.header_len); - top_iph = (struct iphdr*)skb_push(*pskb, iph->ihl*4); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - iph = &tmp_iph.iph; - top_iph->tot_len = htons((*pskb)->len + alen); - top_iph->check = 0; - top_iph->frag_off = iph->frag_off; - *(u8*)(trailer->tail - 1) = iph->protocol; - } + __skb_push(*pskb, (*pskb)->data - (*pskb)->nh.raw); + top_iph = (*pskb)->nh.iph; + esph = (struct ip_esp_hdr *)((*pskb)->nh.raw + top_iph->ihl*4); + top_iph->tot_len = htons((*pskb)->len + alen); + *(u8*)(trailer->tail - 1) = top_iph->protocol; /* this is non-NULL only with UDP Encapsulation */ if (x->encap) { @@ -124,7 +77,7 @@ int esp_output(struct sk_buff **pskb) uh = (struct udphdr *)esph; uh->source = encap->encap_sport; uh->dest = encap->encap_dport; - uh->len = htons((*pskb)->len + alen - sizeof(struct iphdr)); + uh->len = htons((*pskb)->len + alen - top_iph->ihl*4); uh->check = 0; switch (encap->encap_type) { @@ -176,21 +129,9 @@ int esp_output(struct sk_buff **pskb) ip_send_check(top_iph); - (*pskb)->nh.raw = (*pskb)->data; - - x->curlft.bytes += (*pskb)->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if (((*pskb)->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; + err = 0; error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(*pskb); return err; } --- linux-2.6.8-rc1/net/ipv4/ipcomp.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/ipcomp.c 2004-07-13 17:09:13.000000000 -0700 @@ -121,28 +121,6 @@ out: return err; } -static void ipcomp_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb) -{ - struct dst_entry *dst = skb->dst; - struct iphdr *iph, *top_iph; - - iph = skb->nh.iph; - top_iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr)); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = iph->tos; - top_iph->tot_len = htons(skb->len); - if (!(iph->frag_off&htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - skb->nh.raw = skb->data; -} - static int ipcomp_output(struct sk_buff **pskb) { int err; @@ -153,39 +131,17 @@ static int ipcomp_output(struct sk_buff struct ipcomp_data *ipcd = x->data; int hdr_len = 0; - if ((*pskb)->ip_summed == CHECKSUM_HW) { - err = skb_checksum_help(pskb, 0); - if (err) - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_state_check(x, *pskb); - if (err) - goto error; - - if (x->props.mode) { - err = xfrm4_tunnel_check_size(*pskb); - if (err) - goto error; - } else { - /* Don't bother compressing */ - iph = (*pskb)->nh.iph; - hdr_len = iph->ihl * 4; - } + iph = (*pskb)->nh.iph; + iph->tot_len = htons((*pskb)->len); + hdr_len = iph->ihl * 4; if (((*pskb)->len - hdr_len) < ipcd->threshold) { + /* Don't bother compressing */ if (x->props.mode) { - ipcomp_tunnel_encap(x, *pskb); - iph = (*pskb)->nh.iph; - iph->protocol = IPPROTO_IPIP; ip_send_check(iph); } goto out_ok; } - if (x->props.mode) - ipcomp_tunnel_encap(x, *pskb); - if ((skb_is_nonlinear(*pskb) || skb_cloned(*pskb)) && skb_linearize(*pskb, GFP_ATOMIC) != 0) { err = -ENOMEM; @@ -197,7 +153,6 @@ static int ipcomp_output(struct sk_buff if (err == -EMSGSIZE) { if (x->props.mode) { iph = (*pskb)->nh.iph; - iph->protocol = IPPROTO_IPIP; ip_send_check(iph); } goto out_ok; @@ -207,36 +162,19 @@ static int ipcomp_output(struct sk_buff /* Install ipcomp header, convert into ipcomp datagram. */ iph = (*pskb)->nh.iph; - if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN)) - IP_ECN_clear(iph); iph->tot_len = htons((*pskb)->len); - iph->check = 0; ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4); - ipch->nexthdr = x->props.mode ? IPPROTO_IPIP : iph->protocol; + ipch->nexthdr = iph->protocol; ipch->flags = 0; ipch->cpi = htons((u16 )ntohl(x->id.spi)); iph->protocol = IPPROTO_COMP; ip_send_check(iph); - (*pskb)->nh.raw = (*pskb)->data; out_ok: - x->curlft.bytes += (*pskb)->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - - if (((*pskb)->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - err = NET_XMIT_BYPASS; + err = 0; -out_exit: - return err; error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(*pskb); - goto out_exit; + return err; } static void ipcomp4_err(struct sk_buff *skb, u32 info) --- linux-2.6.8-rc1/net/ipv4/ipmr.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/ipmr.c 2004-07-13 17:09:13.000000000 -0700 @@ -109,7 +109,9 @@ static int ip_mr_forward(struct sk_buff static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); +#ifdef CONFIG_IP_PIMSM_V2 static struct net_protocol pim_protocol; +#endif static struct timer_list ipmr_expire_timer; @@ -1702,7 +1704,7 @@ static struct file_operations ipmr_vif_f .open = ipmr_vif_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; struct ipmr_mfc_iter { @@ -1737,6 +1739,9 @@ static struct mfc_cache *ipmr_mfc_seq_id static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) { + struct ipmr_mfc_iter *it = seq->private; + it->cache = NULL; + it->ct = 0; return *pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1) : SEQ_START_TOKEN; } @@ -1846,7 +1851,6 @@ static int ipmr_mfc_open(struct inode *i if (rc) goto out_kfree; - memset(s, 0, sizeof(*s)); seq = file->private_data; seq->private = s; out: @@ -1862,7 +1866,7 @@ static struct file_operations ipmr_mfc_f .open = ipmr_mfc_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; #endif --- linux-2.6.8-rc1/net/ipv4/ip_output.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/ip_output.c 2004-07-13 17:09:13.682192864 -0700 @@ -498,10 +498,6 @@ int ip_fragment(struct sk_buff *skb, int skb_headroom(frag) < hlen) goto slow_path; - /* Correct socket ownership. */ - if (frag->sk == NULL && skb->sk) - goto slow_path; - /* Partially cloned skb? */ if (skb_shared(frag)) goto slow_path; @@ -1113,12 +1109,10 @@ int ip_push_pending_frames(struct sock * tail_skb = &(tmp_skb->next); skb->len += tmp_skb->len; skb->data_len += tmp_skb->len; -#if 0 /* Logically correct, but useless work, ip_fragment() will have to undo */ skb->truesize += tmp_skb->truesize; __sock_put(tmp_skb->sk); tmp_skb->destructor = NULL; tmp_skb->sk = NULL; -#endif } /* Unless user demanded real pmtu discovery (IP_PMTUDISC_DO), we allow --- linux-2.6.8-rc1/net/ipv4/ipvs/ip_vs_sync.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/ipv4/ipvs/ip_vs_sync.c 2004-07-13 17:09:13.000000000 -0700 @@ -593,7 +593,7 @@ ip_vs_receive(struct socket *sock, char /* Receive a packet */ iov.iov_base = buffer; iov.iov_len = (size_t)buflen; - msg.msg_name = 0; + msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; --- linux-2.6.8-rc1/net/ipv4/ipvs/ip_vs_xmit.c 2004-03-10 20:41:31.000000000 -0800 +++ 25/net/ipv4/ipvs/ip_vs_xmit.c 2004-07-13 17:09:13.000000000 -0700 @@ -51,7 +51,7 @@ __ip_vs_dst_check(struct ip_vs_dest *des return NULL; if ((dst->obsolete || rtos != dest->dst_rtos) && dst->ops->check(dst, cookie) == NULL) { - dest->dst_cache = 0; + dest->dst_cache = NULL; return NULL; } dst_hold(dst); --- linux-2.6.8-rc1/net/ipv4/Kconfig 2004-04-03 20:39:14.000000000 -0800 +++ 25/net/ipv4/Kconfig 2004-07-13 17:09:13.000000000 -0700 @@ -196,8 +196,7 @@ config NET_IPIP can be useful if you want to make your (or some other) machine appear on a different network than it physically is, or to use mobile-IP facilities (allowing laptops to seamlessly move between - networks without changing their IP addresses; check out - ). + networks without changing their IP addresses). Saying Y to this option will produce two modules ( = code which can be inserted in and removed from the running kernel whenever you --- linux-2.6.8-rc1/net/ipv4/Makefile 2003-08-22 19:23:42.000000000 -0700 +++ 25/net/ipv4/Makefile 2004-07-13 17:09:13.680193168 -0700 @@ -23,4 +23,5 @@ obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_IP_VS) += ipvs/ -obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o xfrm4_tunnel.o +obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ + xfrm4_tunnel.o xfrm4_output.o --- linux-2.6.8-rc1/net/ipv4/netfilter/ip_nat_snmp_basic.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/net/ipv4/netfilter/ip_nat_snmp_basic.c 2004-07-13 17:09:13.000000000 -0700 @@ -252,7 +252,7 @@ static unsigned char asn1_header_decode( if (def) *eoc = ctx->pointer + len; else - *eoc = 0; + *eoc = NULL; return 1; } --- linux-2.6.8-rc1/net/ipv4/netfilter/ipt_LOG.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/ipv4/netfilter/ipt_LOG.c 2004-07-13 17:09:13.000000000 -0700 @@ -76,7 +76,7 @@ static void dump_packet(const struct ipt printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET); if ((info->logflags & IPT_LOG_IPOPT) - && iph.ihl * 4 != sizeof(struct iphdr)) { + && iph.ihl * 4 > sizeof(struct iphdr)) { unsigned char opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; @@ -143,7 +143,7 @@ static void dump_packet(const struct ipt printk("URGP=%u ", ntohs(tcph.urg_ptr)); if ((info->logflags & IPT_LOG_TCPOPT) - && tcph.doff * 4 != sizeof(struct tcphdr)) { + && tcph.doff * 4 > sizeof(struct tcphdr)) { unsigned char opt[4 * 15 - sizeof(struct tcphdr)]; unsigned int i, optsize; --- linux-2.6.8-rc1/net/ipv4/netfilter/ipt_ULOG.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/ipv4/netfilter/ipt_ULOG.c 2004-07-13 17:09:13.000000000 -0700 @@ -217,6 +217,10 @@ static void ipt_ulog_packet(unsigned int pm = NLMSG_DATA(nlh); + /* We might not have a timestamp, get one */ + if (skb->stamp.tv_sec == 0) + do_gettimeofday((struct timeval *)&skb->stamp); + /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; pm->timestamp_sec = skb->stamp.tv_sec; --- linux-2.6.8-rc1/net/ipv4/route.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/route.c 2004-07-13 17:09:13.690191648 -0700 @@ -432,7 +432,7 @@ static struct file_operations rt_cpu_seq .open = rt_cpu_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; #endif /* CONFIG_PROC_FS */ --- linux-2.6.8-rc1/net/ipv4/tcp_output.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/tcp_output.c 2004-07-13 17:09:13.691191496 -0700 @@ -682,17 +682,32 @@ u32 __tcp_select_window(struct sock *sk) if (free_space > tp->rcv_ssthresh) free_space = tp->rcv_ssthresh; - /* Get the largest window that is a nice multiple of mss. - * Window clamp already applied above. - * If our current window offering is within 1 mss of the - * free space we just keep it. This prevents the divide - * and multiply from happening most of the time. - * We also don't do any window rounding when the free space - * is too small. + /* Don't do rounding if we are using window scaling, since the + * scaled window will not line up with the MSS boundary anyway. */ window = tp->rcv_wnd; - if (window <= free_space - mss || window > free_space) - window = (free_space/mss)*mss; + if (tp->rcv_wscale) { + window = free_space; + + /* Advertise enough space so that it won't get scaled away. + * Import case: prevent zero window announcement if + * 1< mss. + */ + if (((window >> tp->rcv_wscale) << tp->rcv_wscale) != window) + window = (((window >> tp->rcv_wscale) + 1) + << tp->rcv_wscale); + } else { + /* Get the largest window that is a nice multiple of mss. + * Window clamp already applied above. + * If our current window offering is within 1 mss of the + * free space we just keep it. This prevents the divide + * and multiply from happening most of the time. + * We also don't do any window rounding when the free space + * is too small. + */ + if (window <= free_space - mss || window > free_space) + window = (free_space/mss)*mss; + } return window; } --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/net/ipv4/xfrm4_output.c 2004-07-13 17:09:13.692191344 -0700 @@ -0,0 +1,120 @@ +/* + * xfrm4_output.c - Common IPsec encapsulation code for IPv4. + * Copyright (c) 2004 Herbert Xu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +/* Add encapsulation header. + * + * In transport mode, the IP header will be moved forward to make space + * for the encapsulation header. + * + * In tunnel mode, the top IP header will be constructed per RFC 2401. + * The following fields in it shall be filled in by x->type->output: + * tot_len + * check + * + * On exit, skb->h will be set to the start of the payload to be processed + * by x->type->output and skb->nh will be set to the top IP header. + */ +static void xfrm4_encap(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + + iph = skb->nh.iph; + skb->h.ipiph = iph; + + skb->nh.raw = skb_push(skb, x->props.header_len); + top_iph = skb->nh.iph; + + if (!x->props.mode) { + skb->h.raw += iph->ihl*4; + memmove(top_iph, iph, iph->ihl*4); + return; + } + + top_iph->ihl = 5; + top_iph->version = 4; + + /* DS disclosed */ + top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); + if (x->props.flags & XFRM_STATE_NOECN) + IP_ECN_clear(top_iph); + + top_iph->frag_off = iph->frag_off & htons(IP_DF); + if (!top_iph->frag_off) + __ip_select_ident(top_iph, dst, 0); + + /* TTL disclosed */ + top_iph->ttl = iph->ttl; + + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + top_iph->protocol = IPPROTO_IPIP; + + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); +} + +int xfrm4_output(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + int err; + + if (skb->ip_summed == CHECKSUM_HW) { + err = skb_checksum_help(pskb, 0); + skb = *pskb; + if (err) + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err = xfrm_state_check(x, skb); + if (err) + goto error; + + if (x->props.mode) { + err = xfrm4_tunnel_check_size(skb); + if (err) + goto error; + } + + xfrm4_encap(skb); + + err = x->type->output(pskb); + skb = *pskb; + if (err) + goto error; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + + spin_unlock_bh(&x->lock); + + if (!(skb->dst = dst_pop(dst))) { + err = -EHOSTUNREACH; + goto error_nolock; + } + err = NET_XMIT_BYPASS; + +out_exit: + return err; +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + goto out_exit; +} --- linux-2.6.8-rc1/net/ipv4/xfrm4_policy.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/ipv4/xfrm4_policy.c 2004-07-13 17:09:13.693191192 -0700 @@ -139,7 +139,7 @@ __xfrm4_bundle_create(struct xfrm_policy /* Copy neighbout for reachability confirmation */ dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); dst_prev->input = rt->u.dst.input; - dst_prev->output = dst_prev->xfrm->type->output; + dst_prev->output = xfrm4_output; if (rt->peer) atomic_inc(&rt->peer->refcnt); x->u.rt.peer = rt->peer; --- linux-2.6.8-rc1/net/ipv4/xfrm4_tunnel.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv4/xfrm4_tunnel.c 2004-07-13 17:09:13.693191192 -0700 @@ -36,52 +36,13 @@ out: static int ipip_output(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - int tos, err; - - if ((err = xfrm4_tunnel_check_size(skb)) != 0) - goto error_nolock; - + struct iphdr *iph; + iph = skb->nh.iph; + iph->tot_len = htons(skb->len); + ip_send_check(iph); - spin_lock_bh(&x->lock); - - tos = iph->tos; - - top_iph = (struct iphdr *) skb_push(skb, x->props.header_len); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = INET_ECN_encapsulate(tos, iph->tos); - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = iph->frag_off & ~htons(IP_MF|IP_OFFSET); - if (!(iph->frag_off & htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; - top_iph->protocol = IPPROTO_IPIP; - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock_bh(&x->lock); - - if ((skb->dst = dst_pop(dst)) == NULL) { - kfree_skb(skb); - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error_nolock: - kfree_skb(skb); - return err; + return 0; } static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) --- linux-2.6.8-rc1/net/ipv6/addrconf.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/ipv6/addrconf.c 2004-07-13 17:09:13.000000000 -0700 @@ -696,7 +696,7 @@ retry: ift = !max_addresses || ipv6_count_addresses(idev) < max_addresses ? ipv6_add_addr(idev, &addr, tmp_plen, - ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : 0; + ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; if (!ift || IS_ERR(ift)) { in6_dev_put(idev); in6_ifa_put(ifp); --- linux-2.6.8-rc1/net/ipv6/af_inet6.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv6/af_inet6.c 2004-07-13 17:09:13.000000000 -0700 @@ -719,13 +719,13 @@ static int __init inet6_init(void) /* allocate our sock slab caches */ tcp6_sk_cachep = kmem_cache_create("tcp6_sock", sizeof(struct tcp6_sock), 0, - SLAB_HWCACHE_ALIGN, 0, 0); + SLAB_HWCACHE_ALIGN, NULL, NULL); udp6_sk_cachep = kmem_cache_create("udp6_sock", sizeof(struct udp6_sock), 0, - SLAB_HWCACHE_ALIGN, 0, 0); + SLAB_HWCACHE_ALIGN, NULL, NULL); raw6_sk_cachep = kmem_cache_create("raw6_sock", sizeof(struct raw6_sock), 0, - SLAB_HWCACHE_ALIGN, 0, 0); + SLAB_HWCACHE_ALIGN, NULL, NULL); if (!tcp6_sk_cachep || !udp6_sk_cachep || !raw6_sk_cachep) printk(KERN_CRIT "%s: Can't create protocol sock SLAB " "caches!\n", __FUNCTION__); --- linux-2.6.8-rc1/net/ipv6/anycast.c 2004-02-17 20:48:46.000000000 -0800 +++ 25/net/ipv6/anycast.c 2004-07-13 17:09:13.000000000 -0700 @@ -202,7 +202,7 @@ int ipv6_sock_ac_drop(struct sock *sk, i struct ipv6_ac_socklist *pac, *prev_pac; write_lock_bh(&ipv6_sk_ac_lock); - prev_pac = 0; + prev_pac = NULL; for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { if ((ifindex == 0 || pac->acl_ifindex == ifindex) && ipv6_addr_cmp(&pac->acl_addr, addr) == 0) @@ -232,13 +232,13 @@ int ipv6_sock_ac_drop(struct sock *sk, i void ipv6_sock_ac_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); - struct net_device *dev = 0; + struct net_device *dev = NULL; struct ipv6_ac_socklist *pac; int prev_index; write_lock_bh(&ipv6_sk_ac_lock); pac = np->ipv6_ac_list; - np->ipv6_ac_list = 0; + np->ipv6_ac_list = NULL; write_unlock_bh(&ipv6_sk_ac_lock); prev_index = 0; @@ -373,7 +373,7 @@ int ipv6_dev_ac_dec(struct net_device *d return -ENODEV; write_lock_bh(&idev->lock); - prev_aca = 0; + prev_aca = NULL; for (aca = idev->ac_list; aca; aca = aca->aca_next) { if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0) break; --- linux-2.6.8-rc1/net/ipv6/ip6_fib.c 2004-03-10 20:41:31.000000000 -0800 +++ 25/net/ipv6/ip6_fib.c 2004-07-13 17:09:54.000000000 -0700 @@ -94,7 +94,7 @@ static __u32 rt_sernum; static struct timer_list ip6_fib_timer = TIMER_INITIALIZER(fib6_run_gc, 0, 0); -static struct fib6_walker_t fib6_walker_list = { +struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, .next = &fib6_walker_list, }; --- linux-2.6.8-rc1/net/ipv6/ip6_output.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv6/ip6_output.c 2004-07-13 17:09:13.000000000 -0700 @@ -561,7 +561,7 @@ static int ip6_fragment(struct sk_buff * err = 0; offset = 0; frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = 0; + skb_shinfo(skb)->frag_list = NULL; /* BUILD HEADER */ tmp_hdr = kmalloc(hlen, GFP_ATOMIC); --- linux-2.6.8-rc1/net/ipv6/ipcomp6.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv6/ipcomp6.c 2004-07-13 17:09:13.000000000 -0700 @@ -123,7 +123,7 @@ static int ipcomp6_output(struct sk_buff int err; struct dst_entry *dst = (*pskb)->dst; struct xfrm_state *x = dst->xfrm; - struct ipv6hdr *tmp_iph = NULL, *iph, *top_iph; + struct ipv6hdr *iph, *top_iph; int hdr_len = 0; struct ipv6_comp_hdr *ipch; struct ipcomp_data *ipcd = x->data; @@ -193,19 +193,11 @@ static int ipcomp6_output(struct sk_buff if ((dlen + sizeof(struct ipv6_comp_hdr)) >= plen) { goto out_ok; } - memcpy(start, scratch, dlen); - pskb_trim(*pskb, hdr_len+dlen); + memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen); + pskb_trim(*pskb, hdr_len + dlen + sizeof(struct ip_comp_hdr)); /* insert ipcomp header and replace datagram */ - tmp_iph = kmalloc(hdr_len, GFP_ATOMIC); - if (!tmp_iph) { - err = -ENOMEM; - goto error; - } - memcpy(tmp_iph, (*pskb)->nh.raw, hdr_len); - top_iph = (struct ipv6hdr*)skb_push(*pskb, sizeof(struct ipv6_comp_hdr)); - memcpy(top_iph, tmp_iph, hdr_len); - kfree(tmp_iph); + top_iph = (*pskb)->nh.ipv6h; if (x->props.mode && (x->props.flags & XFRM_STATE_NOECN)) IP6_ECN_clear(top_iph); @@ -358,7 +350,7 @@ static int ipcomp6_init_state(struct xfr goto error; memset(ipcd, 0, sizeof(*ipcd)); - x->props.header_len = sizeof(struct ipv6_comp_hdr); + x->props.header_len = 0; if (x->props.mode) x->props.header_len += sizeof(struct ipv6hdr); --- linux-2.6.8-rc1/net/ipv6/mcast.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/ipv6/mcast.c 2004-07-13 17:09:13.000000000 -0700 @@ -210,7 +210,7 @@ int ipv6_sock_mc_join(struct sock *sk, i mc_lst->ifindex = dev->ifindex; mc_lst->sfmode = MCAST_EXCLUDE; - mc_lst->sflist = 0; + mc_lst->sflist = NULL; /* * now add/increase the group membership on the device @@ -272,8 +272,8 @@ int ipv6_sock_mc_drop(struct sock *sk, i struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) { - struct net_device *dev = 0; - struct inet6_dev *idev = 0; + struct net_device *dev = NULL; + struct inet6_dev *idev = NULL; if (ifindex == 0) { struct rt6_info *rt; @@ -288,18 +288,18 @@ struct inet6_dev *ip6_mc_find_dev(struct dev = dev_get_by_index(ifindex); if (!dev) - return 0; + return NULL; idev = in6_dev_get(dev); if (!idev) { dev_put(dev); - return 0; + return NULL; } read_lock_bh(&idev->lock); if (idev->dead) { read_unlock_bh(&idev->lock); in6_dev_put(idev); dev_put(dev); - return 0; + return NULL; } return idev; } @@ -378,8 +378,8 @@ int ip6_mc_source(int add, int omode, st goto done; } else if (pmc->sfmode != omode) { /* allow mode switches for empty-set filters */ - ip6_mc_add_src(idev, group, omode, 0, 0, 0); - ip6_mc_del_src(idev, group, pmc->sfmode, 0, 0, 0); + ip6_mc_add_src(idev, group, omode, 0, NULL, 0); + ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); pmc->sfmode = omode; } @@ -509,14 +509,14 @@ int ip6_mc_msfilter(struct sock *sk, str goto done; } } else - newpsl = 0; + newpsl = NULL; psl = pmc->sflist; if (psl) { (void) ip6_mc_del_src(idev, group, pmc->sfmode, psl->sl_count, psl->sl_addr, 0); sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); } else - (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, 0, 0); + (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); pmc->sflist = newpsl; pmc->sfmode = gsf->gf_fmode; done: @@ -718,7 +718,7 @@ static void mld_add_delrec(struct inet6_ pmc->mca_tomb = im->mca_tomb; pmc->mca_sources = im->mca_sources; - im->mca_tomb = im->mca_sources = 0; + im->mca_tomb = im->mca_sources = NULL; for (psf=pmc->mca_sources; psf; psf=psf->sf_next) psf->sf_crcount = pmc->mca_crcount; } @@ -736,7 +736,7 @@ static void mld_del_delrec(struct inet6_ struct ip6_sf_list *psf, *psf_next; write_lock_bh(&idev->mc_lock); - pmc_prev = 0; + pmc_prev = NULL; for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { if (ipv6_addr_cmp(&pmc->mca_addr, pmca) == 0) break; @@ -765,7 +765,7 @@ static void mld_clear_delrec(struct inet write_lock_bh(&idev->mc_lock); pmc = idev->mc_tomb; - idev->mc_tomb = 0; + idev->mc_tomb = NULL; write_unlock_bh(&idev->mc_lock); for (; pmc; pmc = nextpmc) { @@ -782,7 +782,7 @@ static void mld_clear_delrec(struct inet spin_lock_bh(&pmc->mca_lock); psf = pmc->mca_tomb; - pmc->mca_tomb = 0; + pmc->mca_tomb = NULL; spin_unlock_bh(&pmc->mca_lock); for (; psf; psf=psf_next) { psf_next = psf->sf_next; @@ -818,7 +818,7 @@ int ipv6_dev_mc_inc(struct net_device *d mc->mca_users++; write_unlock_bh(&idev->lock); ip6_mc_add_src(idev, &mc->mca_addr, MCAST_EXCLUDE, 0, - 0, 0); + NULL, 0); in6_dev_put(idev); return 0; } @@ -1274,7 +1274,7 @@ static struct sk_buff *mld_newpack(struc skb = sock_alloc_send_skb(sk, size + LL_RESERVED_SPACE(dev), 1, &err); if (skb == 0) - return 0; + return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); if (dev->hard_header) { @@ -1283,7 +1283,7 @@ static struct sk_buff *mld_newpack(struc ndisc_mc_map(&mld2_all_mcr, ha, dev, 1); if (dev->hard_header(skb, dev, ETH_P_IPV6,ha,NULL,size) < 0) { kfree_skb(skb); - return 0; + return NULL; } } @@ -1352,7 +1352,7 @@ static struct sk_buff *add_grhead(struct if (!skb) skb = mld_newpack(dev, dev->mtu); if (!skb) - return 0; + return NULL; pgr = (struct mld2_grec *)skb_put(skb, sizeof(struct mld2_grec)); pgr->grec_type = type; pgr->grec_auxwords = 0; @@ -1372,7 +1372,7 @@ static struct sk_buff *add_grec(struct s { struct net_device *dev = pmc->idev->dev; struct mld2_report *pmr; - struct mld2_grec *pgr = 0; + struct mld2_grec *pgr = NULL; struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list; int scount, first, isquery, truncate; @@ -1397,13 +1397,13 @@ static struct sk_buff *add_grec(struct s if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+ sizeof(struct in6_addr)) { mld_sendpack(skb); - skb = 0; /* add_grhead will get a new one */ + skb = NULL; /* add_grhead will get a new one */ } skb = add_grhead(skb, pmc, type, &pgr); } return skb; } - pmr = skb ? (struct mld2_report *)skb->h.raw : 0; + pmr = skb ? (struct mld2_report *)skb->h.raw : NULL; /* EX and TO_EX get a fresh packet, if needed */ if (truncate) { @@ -1416,7 +1416,7 @@ static struct sk_buff *add_grec(struct s } first = 1; scount = 0; - psf_prev = 0; + psf_prev = NULL; for (psf=*psf_list; psf; psf=psf_next) { struct in6_addr *psrc; @@ -1474,7 +1474,7 @@ static struct sk_buff *add_grec(struct s static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) { - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; int type; if (!pmc) { @@ -1511,7 +1511,7 @@ static void mld_clear_zeros(struct ip6_s { struct ip6_sf_list *psf_prev, *psf_next, *psf; - psf_prev = 0; + psf_prev = NULL; for (psf=*ppsf; psf; psf = psf_next) { psf_next = psf->sf_next; if (psf->sf_crcount == 0) { @@ -1528,14 +1528,14 @@ static void mld_clear_zeros(struct ip6_s static void mld_send_cr(struct inet6_dev *idev) { struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next; - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; int type, dtype; read_lock_bh(&idev->lock); write_lock_bh(&idev->mc_lock); /* deleted MCA's */ - pmc_prev = 0; + pmc_prev = NULL; for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) { pmc_next = pmc->next; if (pmc->mca_sfmode == MCAST_INCLUDE) { @@ -1691,7 +1691,7 @@ static int ip6_mc_del1_src(struct ifmcad struct ip6_sf_list *psf, *psf_prev; int rv = 0; - psf_prev = 0; + psf_prev = NULL; for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { if (ipv6_addr_cmp(&psf->sf_addr, psfsrc) == 0) break; @@ -1786,7 +1786,7 @@ static int ip6_mc_add1_src(struct ifmcad { struct ip6_sf_list *psf, *psf_prev; - psf_prev = 0; + psf_prev = NULL; for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { if (ipv6_addr_cmp(&psf->sf_addr, psfsrc) == 0) break; @@ -1914,12 +1914,12 @@ static void ip6_mc_clear_src(struct ifmc nextpsf = psf->sf_next; kfree(psf); } - pmc->mca_tomb = 0; + pmc->mca_tomb = NULL; for (psf=pmc->mca_sources; psf; psf=nextpsf) { nextpsf = psf->sf_next; kfree(psf); } - pmc->mca_sources = 0; + pmc->mca_sources = NULL; pmc->mca_sfmode = MCAST_EXCLUDE; pmc->mca_sfcount[MCAST_EXCLUDE] = 0; pmc->mca_sfcount[MCAST_EXCLUDE] = 1; @@ -1956,12 +1956,12 @@ int ip6_mc_leave_src(struct sock *sk, st if (iml->sflist == 0) { /* any-source empty exclude case */ - return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, 0, 0); + return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0); } err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, iml->sflist->sl_count, iml->sflist->sl_addr, 0); sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max)); - iml->sflist = 0; + iml->sflist = NULL; return err; } @@ -1982,7 +1982,7 @@ static void mld_gq_timer_expire(unsigned struct inet6_dev *idev = (struct inet6_dev *)data; idev->mc_gq_running = 0; - mld_send_report(idev, 0); + mld_send_report(idev, NULL); __in6_dev_put(idev); } @@ -2074,7 +2074,7 @@ void ipv6_mc_init_dev(struct inet6_dev * init_timer(&idev->mc_gq_timer); idev->mc_gq_timer.data = (unsigned long) idev; idev->mc_gq_timer.function = &mld_gq_timer_expire; - idev->mc_tomb = 0; + idev->mc_tomb = NULL; idev->mc_ifc_count = 0; init_timer(&idev->mc_ifc_timer); idev->mc_ifc_timer.data = (unsigned long) idev; --- linux-2.6.8-rc1/net/ipv6/xfrm6_state.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/ipv6/xfrm6_state.c 2004-07-13 17:09:55.000000000 -0700 @@ -16,7 +16,7 @@ #include #include -extern struct xfrm_state_afinfo xfrm6_state_afinfo; +static struct xfrm_state_afinfo xfrm6_state_afinfo; static void __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, --- linux-2.6.8-rc1/net/irda/discovery.c 2003-11-23 19:03:03.000000000 -0800 +++ 25/net/irda/discovery.c 2004-07-13 17:09:13.000000000 -0700 @@ -449,6 +449,6 @@ struct file_operations discovery_seq_fop .open = discovery_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; #endif --- linux-2.6.8-rc1/net/irda/ircomm/ircomm_core.c 2003-11-23 19:03:03.000000000 -0800 +++ 25/net/irda/ircomm/ircomm_core.c 2004-07-13 17:09:13.000000000 -0700 @@ -62,7 +62,7 @@ static struct file_operations ircomm_pro .open = ircomm_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; #endif /* CONFIG_PROC_FS */ --- linux-2.6.8-rc1/net/irda/ircomm/ircomm_tty.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/irda/ircomm/ircomm_tty.c 2004-07-13 17:09:13.000000000 -0700 @@ -561,7 +561,7 @@ static void ircomm_tty_close(struct tty_ tty->ldisc.flush_buffer(tty); tty->closing = 0; - self->tty = 0; + self->tty = NULL; if (self->blocked_open) { if (self->close_delay) { @@ -1045,7 +1045,7 @@ static void ircomm_tty_hangup(struct tty /* I guess we need to lock here - Jean II */ spin_lock_irqsave(&self->spinlock, flags); self->flags &= ~ASYNC_NORMAL_ACTIVE; - self->tty = 0; + self->tty = NULL; self->open_count = 0; spin_unlock_irqrestore(&self->spinlock, flags); --- linux-2.6.8-rc1/net/irda/iriap.c 2004-03-10 20:41:31.000000000 -0800 +++ 25/net/irda/iriap.c 2004-07-13 17:09:13.000000000 -0700 @@ -1093,7 +1093,7 @@ struct file_operations irias_seq_fops = .open = irias_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; #endif /* PROC_FS */ --- linux-2.6.8-rc1/net/irda/irlan/irlan_client.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/irda/irlan/irlan_client.c 2004-07-13 17:09:49.000000000 -0700 @@ -234,7 +234,7 @@ static void irlan_client_ctrl_disconnect ASSERT(tsap == self->client.tsap_ctrl, return;); /* Remove frames queued on the control channel */ - while ((skb = skb_dequeue(&self->client.txq))) { + while ((skb = skb_dequeue(&self->client.txq)) != NULL) { dev_kfree_skb(skb); } self->client.tx_busy = FALSE; --- linux-2.6.8-rc1/net/irda/irlmp.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/irda/irlmp.c 2004-07-13 17:09:13.000000000 -0700 @@ -1491,7 +1491,7 @@ void *irlmp_register_service(__u16 hints service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) { IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); - return 0; + return NULL; } service->hints.word = hints; hashbin_insert(irlmp->services, (irda_queue_t *) service, @@ -1561,13 +1561,13 @@ void *irlmp_register_client(__u16 hint_m irlmp_client_t *client; IRDA_DEBUG(1, "%s()\n", __FUNCTION__); - ASSERT(irlmp != NULL, return 0;); + ASSERT(irlmp != NULL, return NULL;); /* Make a new registration */ client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); if (!client) { IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__); - return 0; + return NULL; } /* Register the details */ --- linux-2.6.8-rc1/net/irda/irqueue.c 2004-03-10 20:41:31.000000000 -0800 +++ 25/net/irda/irqueue.c 2004-07-13 17:09:43.000000000 -0700 @@ -663,8 +663,10 @@ void* hashbin_remove_this( hashbin_t* ha } /* Default is no-lock */ /* Check if valid and not already removed... */ - if((entry->q_next == NULL) || (entry->q_prev == NULL)) - return NULL; + if((entry->q_next == NULL) || (entry->q_prev == NULL)) { + entry = NULL; + goto out; + } /* * Locate hashbin @@ -687,7 +689,7 @@ void* hashbin_remove_this( hashbin_t* ha */ if ( entry == hashbin->hb_current) hashbin->hb_current = NULL; - +out: /* Release lock */ if ( hashbin->hb_type & HB_LOCK ) { spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); --- linux-2.6.8-rc1/net/Kconfig 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/Kconfig 2004-07-13 17:09:26.000000000 -0700 @@ -650,18 +650,17 @@ endmenu endmenu +config KGDBOE + def_bool (X86 || IA64) && KGDB + config NETPOLL - def_bool NETCONSOLE + def_bool NETCONSOLE || KGDBOE config NETPOLL_RX - bool "Netpoll support for trapping incoming packets" - default n - depends on NETPOLL + def_bool KGDBOE config NETPOLL_TRAP - bool "Netpoll traffic trapping" - default n - depends on NETPOLL + def_bool KGDBOE config NET_POLL_CONTROLLER def_bool NETPOLL --- linux-2.6.8-rc1/net/rxrpc/call.c 2004-02-03 20:42:39.000000000 -0800 +++ 25/net/rxrpc/call.c 2004-07-13 17:09:13.000000000 -0700 @@ -471,7 +471,7 @@ static inline int __rxrpc_call_gen_norma rxrpc_seq_t seq) { struct rxrpc_message *msg; - struct iovec diov[3]; + struct kvec diov[3]; unsigned aux[4]; int delta, ret; @@ -717,7 +717,7 @@ static int rxrpc_call_generate_ACK(struc /* send a special ACK if one is required */ if (special_ACK) { struct rxrpc_ackpacket ack; - struct iovec diov[2]; + struct kvec diov[2]; uint8_t acks[1] = { RXRPC_ACK_TYPE_ACK }; /* fill out the appropriate form */ @@ -838,7 +838,7 @@ static int __rxrpc_call_abort(struct rxr { struct rxrpc_connection *conn = call->conn; struct rxrpc_message *msg; - struct iovec diov[1]; + struct kvec diov[1]; int ret; u32 _error; @@ -1919,14 +1919,14 @@ int rxrpc_call_read_data(struct rxrpc_ca */ int rxrpc_call_write_data(struct rxrpc_call *call, size_t sioc, - struct iovec siov[], + struct kvec *siov, u8 rxhdr_flags, int alloc_flags, int dup_data, size_t *size_sent) { struct rxrpc_message *msg; - struct iovec *sptr; + struct kvec *sptr; size_t space, size, chunk, tmp; char *buf; int ret; --- linux-2.6.8-rc1/net/rxrpc/connection.c 2004-03-10 20:41:32.000000000 -0800 +++ 25/net/rxrpc/connection.c 2004-07-13 17:09:13.000000000 -0700 @@ -518,7 +518,7 @@ int rxrpc_conn_newmsg(struct rxrpc_conne struct rxrpc_call *call, uint8_t type, int dcount, - struct iovec diov[], + struct kvec diov[], int alloc_flags, struct rxrpc_message **_msg) { @@ -634,7 +634,11 @@ int rxrpc_conn_sendmsg(struct rxrpc_conn /* set up the message to be transmitted */ msghdr.msg_name = &conn->addr; msghdr.msg_namelen = sizeof(conn->addr); - msghdr.msg_iov = msg->data; + /* + * the following is safe, since for compiler definitions of kvec and + * iovec are identical, yielding the same in-core layout and alignment + */ + msghdr.msg_iov = (struct iovec *)msg->data; msghdr.msg_iovlen = msg->dcount; msghdr.msg_control = NULL; msghdr.msg_controllen = 0; --- linux-2.6.8-rc1/net/rxrpc/transport.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/rxrpc/transport.c 2004-07-13 17:09:13.000000000 -0700 @@ -611,7 +611,7 @@ int rxrpc_trans_immediate_abort(struct r struct rxrpc_header ahdr; struct sockaddr_in sin; struct msghdr msghdr; - struct iovec iov[2]; + struct kvec iov[2]; mm_segment_t oldfs; uint32_t _error; int len, ret; @@ -649,7 +649,11 @@ int rxrpc_trans_immediate_abort(struct r msghdr.msg_name = &sin; msghdr.msg_namelen = sizeof(sin); - msghdr.msg_iov = iov; + /* + * the following is safe, since for compiler definitions of kvec and + * iovec are identical, yielding the same in-core layout and alignment + */ + msghdr.msg_iov = (struct iovec *)iov; msghdr.msg_iovlen = 2; msghdr.msg_control = NULL; msghdr.msg_controllen = 0; --- linux-2.6.8-rc1/net/sched/Kconfig 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/sched/Kconfig 2004-07-13 17:09:13.000000000 -0700 @@ -49,21 +49,6 @@ config NET_SCH_HFSC To compile this code as a module, choose M here: the module will be called sch_hfsc. -config NET_SCH_CSZ - tristate "CSZ packet scheduler" - depends on NET_SCHED - ---help--- - Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet - scheduling algorithm for some of your network devices. At the - moment, this is the only algorithm that can guarantee service for - real-time applications (see the top of - for details and references about the algorithm). - - Note: this scheduler is currently broken. - - To compile this code as a module, choose M here: the - module will be called sch_csz. - #tristate ' H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ config NET_SCH_ATM tristate "ATM pseudo-scheduler" --- linux-2.6.8-rc1/net/sched/Makefile 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/sched/Makefile 2004-07-13 17:09:13.710188608 -0700 @@ -12,7 +12,6 @@ obj-$(CONFIG_NET_ACT_POLICE) += polic obj-$(CONFIG_NET_CLS_POLICE) += police.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o -obj-$(CONFIG_NET_SCH_CSZ) += sch_csz.o obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o obj-$(CONFIG_NET_SCH_RED) += sch_red.o --- linux-2.6.8-rc1/net/sched/sch_csz.c 2004-07-11 14:13:30.000000000 -0700 +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,1055 +0,0 @@ -/* - * net/sched/sch_csz.c Clark-Shenker-Zhang scheduler. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Clark-Shenker-Zhang algorithm. - ======================================= - - SOURCE. - - David D. Clark, Scott Shenker and Lixia Zhang - "Supporting Real-Time Applications in an Integrated Services Packet - Network: Architecture and Mechanism". - - CBQ presents a flexible universal algorithm for packet scheduling, - but it has pretty poor delay characteristics. - Round-robin scheduling and link-sharing goals - apparently contradict minimization of network delay and jitter. - Moreover, correct handling of predictive flows seems to be - impossible in CBQ. - - CSZ presents a more precise but less flexible and less efficient - approach. As I understand it, the main idea is to create - WFQ flows for each guaranteed service and to allocate - the rest of bandwidth to dummy flow-0. Flow-0 comprises - the predictive services and the best effort traffic; - it is handled by a priority scheduler with the highest - priority band allocated for predictive services, and the rest --- - to the best effort packets. - - Note that in CSZ flows are NOT limited to their bandwidth. It - is supposed that the flow passed admission control at the edge - of the QoS network and it doesn't need further shaping. Any - attempt to improve the flow or to shape it to a token bucket - at intermediate hops will introduce undesired delays and raise - jitter. - - At the moment CSZ is the only scheduler that provides - true guaranteed service. Another schemes (including CBQ) - do not provide guaranteed delay and randomize jitter. - There is a proof (Sally Floyd), that delay - can be estimated by a IntServ compliant formula. - This result is true formally, but it is wrong in principle. - It takes into account only round-robin delays, - ignoring delays introduced by link sharing i.e. overlimiting. - Note that temporary overlimits are inevitable because - real links are not ideal, and the real algorithm must take this - into account. - - ALGORITHM. - - --- Notations. - - $B$ is link bandwidth (bits/sec). - - $I$ is set of all flows, including flow $0$. - Every flow $a \in I$ has associated bandwidth slice $r_a < 1$ and - $\sum_{a \in I} r_a = 1$. - - --- Flow model. - - Let $m_a$ is the number of backlogged bits in flow $a$. - The flow is {\em active}, if $m_a > 0$. - This number is a discontinuous function of time; - when a packet $i$ arrives: - \[ - m_a(t_i+0) - m_a(t_i-0) = L^i, - \] - where $L^i$ is the length of the arrived packet. - The flow queue is drained continuously until $m_a == 0$: - \[ - {d m_a \over dt} = - { B r_a \over \sum_{b \in A} r_b}. - \] - I.e. flow rates are their allocated rates proportionally - scaled to take all available link bandwidth. Apparently, - it is not the only possible policy. F.e. CBQ classes - without borrowing would be modelled by: - \[ - {d m_a \over dt} = - B r_a . - \] - More complicated hierarchical bandwidth allocation - policies are possible, but unfortunately, the basic - flow equations have a simple solution only for proportional - scaling. - - --- Departure times. - - We calculate the time until the last bit of packet is sent: - \[ - E_a^i(t) = { m_a(t_i) - \delta_a(t) \over r_a }, - \] - where $\delta_a(t)$ is number of bits drained since $t_i$. - We have to evaluate $E_a^i$ for all queued packets, - then find the packet with minimal $E_a^i$ and send it. - - This sounds good, but direct implementation of the algorithm - is absolutely infeasible. Luckily, if flow rates - are scaled proportionally, the equations have a simple solution. - - The differential equation for $E_a^i$ is - \[ - {d E_a^i (t) \over dt } = - { d \delta_a(t) \over dt} { 1 \over r_a} = - { B \over \sum_{b \in A} r_b} - \] - with initial condition - \[ - E_a^i (t_i) = { m_a(t_i) \over r_a } . - \] - - Let's introduce an auxiliary function $R(t)$: - - --- Round number. - - Consider the following model: we rotate over active flows, - sending $r_a B$ bits from every flow, so that we send - $B \sum_{a \in A} r_a$ bits per round, that takes - $\sum_{a \in A} r_a$ seconds. - - Hence, $R(t)$ (round number) is a monotonically increasing - linear function of time when $A$ is not changed - \[ - { d R(t) \over dt } = { 1 \over \sum_{a \in A} r_a } - \] - and it is continuous when $A$ changes. - - The central observation is that the quantity - $F_a^i = R(t) + E_a^i(t)/B$ does not depend on time at all! - $R(t)$ does not depend on flow, so that $F_a^i$ can be - calculated only once on packet arrival, and we need not - recalculate $E$ numbers and resorting queues. - The number $F_a^i$ is called finish number of the packet. - It is just the value of $R(t)$ when the last bit of packet - is sent out. - - Maximal finish number on flow is called finish number of flow - and minimal one is "start number of flow". - Apparently, flow is active if and only if $F_a \leq R$. - - When a packet of length $L_i$ bit arrives to flow $a$ at time $t_i$, - we calculate $F_a^i$ as: - - If flow was inactive ($F_a < R$): - $F_a^i = R(t) + {L_i \over B r_a}$ - otherwise - $F_a^i = F_a + {L_i \over B r_a}$ - - These equations complete the algorithm specification. - - It looks pretty hairy, but there is a simple - procedure for solving these equations. - See procedure csz_update(), that is a generalization of - the algorithm from S. Keshav's thesis Chapter 3 - "Efficient Implementation of Fair Queuing". - - NOTES. - - * We implement only the simplest variant of CSZ, - when flow-0 is a explicit 4band priority fifo. - This is bad, but we need a "peek" operation in addition - to "dequeue" to implement complete CSZ. - I do not want to do that, unless it is absolutely - necessary. - - * A primitive support for token bucket filtering - presents itself too. It directly contradicts CSZ, but - even though the Internet is on the globe ... :-) - "the edges of the network" really exist. - - BUGS. - - * Fixed point arithmetic is overcomplicated, suboptimal and even - wrong. Check it later. */ - - -/* This number is arbitrary */ - -#define CSZ_GUARANTEED 16 -#define CSZ_FLOWS (CSZ_GUARANTEED+4) - -struct csz_head -{ - struct csz_head *snext; - struct csz_head *sprev; - struct csz_head *fnext; - struct csz_head *fprev; -}; - -struct csz_flow -{ - struct csz_head *snext; - struct csz_head *sprev; - struct csz_head *fnext; - struct csz_head *fprev; - -/* Parameters */ - struct tc_ratespec rate; - struct tc_ratespec slice; - u32 *L_tab; /* Lookup table for L/(B*r_a) values */ - unsigned long limit; /* Maximal length of queue */ -#ifdef CSZ_PLUS_TBF - struct tc_ratespec peakrate; - __u32 buffer; /* Depth of token bucket, normalized - as L/(B*r_a) */ - __u32 mtu; -#endif - -/* Variables */ -#ifdef CSZ_PLUS_TBF - unsigned long tokens; /* Tokens number: usecs */ - psched_time_t t_tbf; - unsigned long R_tbf; - int throttled; -#endif - unsigned peeked; - unsigned long start; /* Finish number of the first skb */ - unsigned long finish; /* Finish number of the flow */ - - struct sk_buff_head q; /* FIFO queue */ -}; - -#define L2R(f,L) ((f)->L_tab[(L)>>(f)->slice.cell_log]) - -struct csz_sched_data -{ -/* Parameters */ - unsigned char rate_log; /* fixed point position for rate; - * really we need not it */ - unsigned char R_log; /* fixed point position for round number */ - unsigned char delta_log; /* 1< 2.1sec is MAXIMAL value */ - -/* Variables */ - struct tcf_proto *filter_list; - u8 prio2band[TC_PRIO_MAX+1]; -#ifdef CSZ_PLUS_TBF - struct timer_list wd_timer; - long wd_expires; -#endif - psched_time_t t_c; /* Time check-point */ - unsigned long R_c; /* R-number check-point */ - unsigned long rate; /* Current sum of rates of active flows */ - struct csz_head s; /* Flows sorted by "start" */ - struct csz_head f; /* Flows sorted by "finish" */ - - struct sk_buff_head other[4];/* Predicted (0) and the best efforts - classes (1,2,3) */ - struct csz_flow flow[CSZ_GUARANTEED]; /* Array of flows */ -}; - -/* These routines (csz_insert_finish and csz_insert_start) are - the most time consuming part of all the algorithm. - - We insert to sorted list, so that time - is linear with respect to number of active flows in the worst case. - Note that we have not very large number of guaranteed flows, - so that logarithmic algorithms (heap etc.) are useless, - they are slower than linear one when length of list <= 32. - - Heap would take sence if we used WFQ for best efforts - flows, but SFQ is better choice in this case. - */ - - -/* Insert flow "this" to the list "b" before - flow with greater finish number. - */ - -#if 0 -/* Scan forward */ -static inline void csz_insert_finish(struct csz_head *b, - struct csz_flow *this) -{ - struct csz_head *f = b->fnext; - unsigned long finish = this->finish; - - while (f != b) { - if (((struct csz_flow*)f)->finish - finish > 0) - break; - f = f->fnext; - } - this->fnext = f; - this->fprev = f->fprev; - this->fnext->fprev = this->fprev->fnext = (struct csz_head*)this; -} -#else -/* Scan backward */ -static inline void csz_insert_finish(struct csz_head *b, - struct csz_flow *this) -{ - struct csz_head *f = b->fprev; - unsigned long finish = this->finish; - - while (f != b) { - if (((struct csz_flow*)f)->finish - finish <= 0) - break; - f = f->fprev; - } - this->fnext = f->fnext; - this->fprev = f; - this->fnext->fprev = this->fprev->fnext = (struct csz_head*)this; -} -#endif - -/* Insert flow "this" to the list "b" before - flow with greater start number. - */ - -static inline void csz_insert_start(struct csz_head *b, - struct csz_flow *this) -{ - struct csz_head *f = b->snext; - unsigned long start = this->start; - - while (f != b) { - if (((struct csz_flow*)f)->start - start > 0) - break; - f = f->snext; - } - this->snext = f; - this->sprev = f->sprev; - this->snext->sprev = this->sprev->snext = (struct csz_head*)this; -} - - -/* Calculate and return current round number. - It is another time consuming part, but - it is impossible to avoid it. - - It costs O(N) that make all the algorithm useful only - to play with closest to ideal fluid model. - - There exist less academic, but more practical modifications, - which might have even better characteristics (WF2Q+, HPFQ, HFSC) - */ - -static unsigned long csz_update(struct Qdisc *sch) -{ - struct csz_sched_data *q = (struct csz_sched_data*)sch->data; - struct csz_flow *a; - unsigned long F; - unsigned long tmp; - psched_time_t now; - unsigned long delay; - unsigned long R_c; - - PSCHED_GET_TIME(now); - delay = PSCHED_TDIFF(now, q->t_c); - if (delay>>q->delta_log) { - /* Delta is too large. - It is possible if MTU/BW > 1<delta_log - (i.e. configuration error) or because of hardware - fault. We have no choice... - */ - qdisc_reset(sch); - return 0; - } - - q->t_c = now; - - for (;;) { - a = (struct csz_flow*)q->f.fnext; - - /* No more active flows. Reset R and exit. */ - if (a == (struct csz_flow*)&q->f) { -#ifdef CSZ_DEBUG - if (q->rate) { - printk("csz_update: rate!=0 on inactive csz\n"); - q->rate = 0; - } -#endif - q->R_c = 0; - return 0; - } - - F = a->finish; - -#ifdef CSZ_DEBUG - if (q->rate == 0) { - printk("csz_update: rate=0 on active csz\n"); - goto do_reset; - } -#endif - - /* - * tmp = (t - q->t_c)/q->rate; - */ - - tmp = ((delay<<(31-q->delta_log))/q->rate)>>(31-q->delta_log+q->R_log); - - tmp += q->R_c; - - /* OK, this flow (and all flows with greater - finish numbers) is still active */ - if (F - tmp > 0) - break; - - /* It is more not active */ - - a->fprev->fnext = a->fnext; - a->fnext->fprev = a->fprev; - - /* - * q->t_c += (F - q->R_c)*q->rate - */ - - tmp = ((F-q->R_c)*q->rate)<R_log; - R_c = F; - q->rate -= a->slice.rate; - - if ((long)(delay - tmp) >= 0) { - delay -= tmp; - continue; - } - delay = 0; - } - - q->R_c = tmp; - return tmp; -} - -unsigned csz_classify(struct sk_buff *skb, struct csz_sched_data *q) -{ - return CSZ_GUARANTEED; -} - -static int -csz_enqueue(struct sk_buff *skb, struct Qdisc* sch) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - unsigned flow_id = csz_classify(skb, q); - unsigned long R; - int prio = 0; - struct csz_flow *this; - - if (flow_id >= CSZ_GUARANTEED) { - prio = flow_id - CSZ_GUARANTEED; - flow_id = 0; - } - - this = &q->flow[flow_id]; - if (this->q.qlen >= this->limit || this->L_tab == NULL) { - sch->stats.drops++; - kfree_skb(skb); - return NET_XMIT_DROP; - } - - R = csz_update(sch); - - if ((long)(this->finish - R) >= 0) { - /* It was active */ - this->finish += L2R(this,skb->len); - } else { - /* It is inactive; activate it */ - this->finish = R + L2R(this,skb->len); - q->rate += this->slice.rate; - csz_insert_finish(&q->f, this); - } - - /* If this flow was empty, remember start number - and insert it into start queue */ - if (this->q.qlen == 0) { - this->start = this->finish; - csz_insert_start(&q->s, this); - } - if (flow_id) - skb_queue_tail(&this->q, skb); - else - skb_queue_tail(&q->other[prio], skb); - sch->q.qlen++; - sch->stats.bytes += skb->len; - sch->stats.packets++; - return 0; -} - -static __inline__ struct sk_buff * -skb_dequeue_best(struct csz_sched_data * q) -{ - int i; - struct sk_buff *skb; - - for (i=0; i<4; i++) { - skb = skb_dequeue(&q->other[i]); - if (skb) { - q->flow[0].q.qlen--; - return skb; - } - } - return NULL; -} - -static __inline__ struct sk_buff * -skb_peek_best(struct csz_sched_data * q) -{ - int i; - struct sk_buff *skb; - - for (i=0; i<4; i++) { - skb = skb_peek(&q->other[i]); - if (skb) - return skb; - } - return NULL; -} - -#ifdef CSZ_PLUS_TBF - -static void csz_watchdog(unsigned long arg) -{ - struct Qdisc *sch = (struct Qdisc*)arg; - - qdisc_wakeup(sch->dev); -} - -static __inline__ void -csz_move_queue(struct csz_flow *this, long delta) -{ - this->fprev->fnext = this->fnext; - this->fnext->fprev = this->fprev; - - this->start += delta; - this->finish += delta; - - csz_insert_finish(this); -} - -static __inline__ int csz_enough_tokens(struct csz_sched_data *q, - struct csz_flow *this, - struct sk_buff *skb) -{ - long toks; - long shift; - psched_time_t now; - - PSCHED_GET_TIME(now); - - toks = PSCHED_TDIFF(now, t_tbf) + this->tokens - L2R(q,this,skb->len); - - shift = 0; - if (this->throttled) { - /* Remember aposteriory delay */ - - unsigned long R = csz_update(q); - shift = R - this->R_tbf; - this->R_tbf = R; - } - - if (toks >= 0) { - /* Now we have enough tokens to proceed */ - - this->tokens = toks <= this->depth ? toks : this->depth; - this->t_tbf = now; - - if (!this->throttled) - return 1; - - /* Flow was throttled. Update its start&finish numbers - with delay calculated aposteriori. - */ - - this->throttled = 0; - if (shift > 0) - csz_move_queue(this, shift); - return 1; - } - - if (!this->throttled) { - /* Flow has just been throttled; remember - current round number to calculate aposteriori delay - */ - this->throttled = 1; - this->R_tbf = csz_update(q); - } - - /* Move all the queue to the time when it will be allowed to send. - We should translate time to round number, but it is impossible, - so that we made the most conservative estimate i.e. we suppose - that only this flow is active and, hence, R = t. - Really toks <= R <= toks/r_a. - - This apriory shift in R will be adjusted later to reflect - real delay. We cannot avoid it because of: - - throttled flow continues to be active from the viewpoint - of CSZ, so that it would acquire the highest priority, - if you not adjusted start numbers. - - Eventually, finish number would become less than round - number and flow were declared inactive. - */ - - toks = -toks; - - /* Remember, that we should start watchdog */ - if (toks < q->wd_expires) - q->wd_expires = toks; - - toks >>= q->R_log; - shift += toks; - if (shift > 0) { - this->R_tbf += toks; - csz_move_queue(this, shift); - } - csz_insert_start(this); - return 0; -} -#endif - - -static struct sk_buff * -csz_dequeue(struct Qdisc* sch) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - struct sk_buff *skb; - struct csz_flow *this; - -#ifdef CSZ_PLUS_TBF - q->wd_expires = 0; -#endif - this = (struct csz_flow*)q->s.snext; - - while (this != (struct csz_flow*)&q->s) { - - /* First of all: unlink from start list */ - this->sprev->snext = this->snext; - this->snext->sprev = this->sprev; - - if (this != &q->flow[0]) { /* Guaranteed flow */ - skb = __skb_dequeue(&this->q); - if (skb) { -#ifdef CSZ_PLUS_TBF - if (this->depth) { - if (!csz_enough_tokens(q, this, skb)) - continue; - } -#endif - if (this->q.qlen) { - struct sk_buff *nskb = skb_peek(&this->q); - this->start += L2R(this,nskb->len); - csz_insert_start(&q->s, this); - } - sch->q.qlen--; - return skb; - } - } else { /* Predicted or best effort flow */ - skb = skb_dequeue_best(q); - if (skb) { - unsigned peeked = this->peeked; - this->peeked = 0; - - if (--this->q.qlen) { - struct sk_buff *nskb; - unsigned dequeued = L2R(this,skb->len); - - /* We got not the same thing that - peeked earlier; adjust start number - */ - if (peeked != dequeued && peeked) - this->start += dequeued - peeked; - - nskb = skb_peek_best(q); - peeked = L2R(this,nskb->len); - this->start += peeked; - this->peeked = peeked; - csz_insert_start(&q->s, this); - } - sch->q.qlen--; - return skb; - } - } - } -#ifdef CSZ_PLUS_TBF - /* We are about to return no skb. - Schedule watchdog timer, if it occurred because of shaping. - */ - if (q->wd_expires) { - unsigned long delay = PSCHED_US2JIFFIE(q->wd_expires); - if (delay == 0) - delay = 1; - mod_timer(&q->wd_timer, jiffies + delay); - sch->stats.overlimits++; - } -#endif - return NULL; -} - -static void -csz_reset(struct Qdisc* sch) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - int i; - - for (i=0; i<4; i++) - skb_queue_purge(&q->other[i]); - - for (i=0; iflow + i; - skb_queue_purge(&this->q); - this->snext = this->sprev = - this->fnext = this->fprev = (struct csz_head*)this; - this->start = this->finish = 0; - } - q->s.snext = q->s.sprev = &q->s; - q->f.fnext = q->f.fprev = &q->f; - q->R_c = 0; -#ifdef CSZ_PLUS_TBF - PSCHED_GET_TIME(&q->t_tbf); - q->tokens = q->depth; - del_timer(&q->wd_timer); -#endif - sch->q.qlen = 0; -} - -static void -csz_destroy(struct Qdisc* sch) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - struct tcf_proto *tp; - - while ((tp = q->filter_list) != NULL) { - q->filter_list = tp->next; - tcf_destroy(tp); - } -} - -static int csz_init(struct Qdisc *sch, struct rtattr *opt) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - struct rtattr *tb[TCA_CSZ_PTAB]; - struct tc_csz_qopt *qopt; - int i; - - rtattr_parse(tb, TCA_CSZ_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)); - if (tb[TCA_CSZ_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_CSZ_PARMS-1]) < sizeof(*qopt)) - return -EINVAL; - qopt = RTA_DATA(tb[TCA_CSZ_PARMS-1]); - - q->R_log = qopt->R_log; - q->delta_log = qopt->delta_log; - for (i=0; i<=TC_PRIO_MAX; i++) { - if (qopt->priomap[i] >= CSZ_FLOWS) - return -EINVAL; - q->prio2band[i] = qopt->priomap[i]; - } - - for (i=0; i<4; i++) - skb_queue_head_init(&q->other[i]); - - for (i=0; iflow + i; - skb_queue_head_init(&this->q); - this->snext = this->sprev = - this->fnext = this->fprev = (struct csz_head*)this; - this->start = this->finish = 0; - } - q->s.snext = q->s.sprev = &q->s; - q->f.fnext = q->f.fprev = &q->f; - q->R_c = 0; -#ifdef CSZ_PLUS_TBF - init_timer(&q->wd_timer); - q->wd_timer.data = (unsigned long)sch; - q->wd_timer.function = csz_watchdog; -#endif - return 0; -} - -static int csz_dump(struct Qdisc *sch, struct sk_buff *skb) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - unsigned char *b = skb->tail; - struct rtattr *rta; - struct tc_csz_qopt opt; - - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - - opt.flows = CSZ_FLOWS; - memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1); - RTA_PUT(skb, TCA_CSZ_PARMS, sizeof(opt), &opt); - rta->rta_len = skb->tail - b; - - return skb->len; - -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; -} - -static int csz_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, - struct Qdisc **old) -{ - return -EINVAL; -} - -static struct Qdisc * csz_leaf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - - -static unsigned long csz_get(struct Qdisc *sch, u32 classid) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - unsigned long band = TC_H_MIN(classid) - 1; - - if (band >= CSZ_FLOWS) - return 0; - - if (band < CSZ_GUARANTEED && q->flow[band].L_tab == NULL) - return 0; - - return band+1; -} - -static unsigned long csz_bind(struct Qdisc *sch, unsigned long parent, u32 classid) -{ - return csz_get(sch, classid); -} - - -static void csz_put(struct Qdisc *sch, unsigned long cl) -{ - return; -} - -static int csz_change(struct Qdisc *sch, u32 handle, u32 parent, struct rtattr **tca, unsigned long *arg) -{ - unsigned long cl = *arg; - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - struct rtattr *opt = tca[TCA_OPTIONS-1]; - struct rtattr *tb[TCA_CSZ_PTAB]; - struct tc_csz_copt *copt; - - rtattr_parse(tb, TCA_CSZ_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)); - if (tb[TCA_CSZ_PARMS-1] == NULL || - RTA_PAYLOAD(tb[TCA_CSZ_PARMS-1]) < sizeof(*copt)) - return -EINVAL; - copt = RTA_DATA(tb[TCA_CSZ_PARMS-1]); - - if (tb[TCA_CSZ_RTAB-1] && - RTA_PAYLOAD(tb[TCA_CSZ_RTAB-1]) < 1024) - return -EINVAL; - - if (cl) { - struct csz_flow *a; - cl--; - if (cl >= CSZ_FLOWS) - return -ENOENT; - if (cl >= CSZ_GUARANTEED || q->flow[cl].L_tab == NULL) - return -EINVAL; - - a = &q->flow[cl]; - - spin_lock_bh(&sch->dev->queue_lock); -#if 0 - a->rate_log = copt->rate_log; -#endif -#ifdef CSZ_PLUS_TBF - a->limit = copt->limit; - a->rate = copt->rate; - a->buffer = copt->buffer; - a->mtu = copt->mtu; -#endif - - if (tb[TCA_CSZ_RTAB-1]) - memcpy(a->L_tab, RTA_DATA(tb[TCA_CSZ_RTAB-1]), 1024); - - spin_unlock_bh(&sch->dev->queue_lock); - return 0; - } - /* NI */ - return 0; -} - -static int csz_delete(struct Qdisc *sch, unsigned long cl) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - struct csz_flow *a; - - cl--; - - if (cl >= CSZ_FLOWS) - return -ENOENT; - if (cl >= CSZ_GUARANTEED || q->flow[cl].L_tab == NULL) - return -EINVAL; - - a = &q->flow[cl]; - - spin_lock_bh(&sch->dev->queue_lock); - a->fprev->fnext = a->fnext; - a->fnext->fprev = a->fprev; - a->sprev->snext = a->snext; - a->snext->sprev = a->sprev; - a->start = a->finish = 0; - kfree(xchg(&q->flow[cl].L_tab, NULL)); - spin_unlock_bh(&sch->dev->queue_lock); - - return 0; -} - -static int csz_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - unsigned char *b = skb->tail; - struct rtattr *rta; - struct tc_csz_copt opt; - - tcm->tcm_handle = sch->handle|cl; - - cl--; - - if (cl > CSZ_FLOWS) - goto rtattr_failure; - - if (cl < CSZ_GUARANTEED) { - struct csz_flow *f = &q->flow[cl]; - - if (f->L_tab == NULL) - goto rtattr_failure; - - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - - opt.limit = f->limit; - opt.rate = f->rate; - opt.slice = f->slice; - memset(&opt.peakrate, 0, sizeof(opt.peakrate)); -#ifdef CSZ_PLUS_TBF - opt.buffer = f->buffer; - opt.mtu = f->mtu; -#else - opt.buffer = 0; - opt.mtu = 0; -#endif - - RTA_PUT(skb, TCA_CSZ_PARMS, sizeof(opt), &opt); - rta->rta_len = skb->tail - b; - } - - return skb->len; - -rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; -} - -static void csz_walk(struct Qdisc *sch, struct qdisc_walker *arg) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - int prio = 0; - - if (arg->stop) - return; - - for (prio = 0; prio < CSZ_FLOWS; prio++) { - if (arg->count < arg->skip) { - arg->count++; - continue; - } - if (prio < CSZ_GUARANTEED && q->flow[prio].L_tab == NULL) { - arg->count++; - continue; - } - if (arg->fn(sch, prio+1, arg) < 0) { - arg->stop = 1; - break; - } - arg->count++; - } -} - -static struct tcf_proto ** csz_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - struct csz_sched_data *q = (struct csz_sched_data *)sch->data; - - if (cl) - return NULL; - - return &q->filter_list; -} - -struct Qdisc_class_ops csz_class_ops = { - .graft = csz_graft, - .leaf = csz_leaf, - .get = csz_get, - .put = csz_put, - .change = csz_change, - .delete = csz_delete, - .walk = csz_walk, - .tcf_chain = csz_find_tcf, - .bind_tcf = csz_bind, - .unbind_tcf = csz_put, - .dump = csz_dump_class, -}; - -static struct Qdisc_ops csz_qdisc_ops = { - .next = NULL, - .cl_ops = &csz_class_ops, - .id = "csz", - .priv_size = sizeof(struct csz_sched_data), - .enqueue = csz_enqueue, - .dequeue = csz_dequeue, - .requeue = NULL, - .drop = NULL, - .init = csz_init, - .reset = csz_reset, - .destroy = csz_destroy, - .change = NULL, - .dump = csz_dump, - .owner = THIS_MODULE, -}; - -static int __init csz_module_init(void) -{ - return register_qdisc(&csz_qdisc_ops); -} -static void __exit csz_module_exit(void) -{ - unregister_qdisc(&csz_qdisc_ops); -} -module_init(csz_module_init) -module_exit(csz_module_exit) -MODULE_LICENSE("GPL"); --- linux-2.6.8-rc1/net/sched/sch_netem.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/sched/sch_netem.c 2004-07-13 17:09:13.000000000 -0700 @@ -29,14 +29,16 @@ */ struct netem_sched_data { - struct sk_buff_head qnormal; - struct sk_buff_head qdelay; + struct Qdisc *qdisc; + struct sk_buff_head delayed; struct timer_list timer; u32 latency; u32 loss; + u32 limit; u32 counter; u32 gap; + u32 jitter; }; /* Time stamp put into socket buffer control block */ @@ -44,6 +46,558 @@ struct netem_skb_cb { psched_time_t time_to_send; }; +/* This is the distribution table for the normal distribution produced + * with NISTnet tools. + * The entries represent a scaled inverse of the cumulative distribution + * function. + */ +#define TABLESIZE 2048 +#define TABLEFACTOR 8192 + +static const short disttable[TABLESIZE] = { + -31473, -26739, -25226, -24269, + -23560, -22993, -22518, -22109, + -21749, -21426, -21133, -20865, + -20618, -20389, -20174, -19972, + -19782, -19601, -19430, -19267, + -19112, -18962, -18819, -18681, + -18549, -18421, -18298, -18178, + -18062, -17950, -17841, -17735, + -17632, -17532, -17434, -17339, + -17245, -17155, -17066, -16979, + -16894, -16811, -16729, -16649, + -16571, -16494, -16419, -16345, + -16272, -16201, -16130, -16061, + -15993, -15926, -15861, -15796, + -15732, -15669, -15607, -15546, + -15486, -15426, -15368, -15310, + -15253, -15196, -15140, -15086, + -15031, -14977, -14925, -14872, + -14821, -14769, -14719, -14669, + -14619, -14570, -14522, -14473, + -14426, -14379, -14332, -14286, + -14241, -14196, -14150, -14106, + -14062, -14019, -13976, -13933, + -13890, -13848, -13807, -13765, + -13724, -13684, -13643, -13604, + -13564, -13525, -13486, -13447, + -13408, -13370, -13332, -13295, + -13258, -13221, -13184, -13147, + -13111, -13075, -13040, -13004, + -12969, -12934, -12899, -12865, + -12830, -12796, -12762, -12729, + -12695, -12662, -12629, -12596, + -12564, -12531, -12499, -12467, + -12435, -12404, -12372, -12341, + -12310, -12279, -12248, -12218, + -12187, -12157, -12127, -12097, + -12067, -12038, -12008, -11979, + -11950, -11921, -11892, -11863, + -11835, -11806, -11778, -11750, + -11722, -11694, -11666, -11639, + -11611, -11584, -11557, -11530, + -11503, -11476, -11450, -11423, + -11396, -11370, -11344, -11318, + -11292, -11266, -11240, -11214, + -11189, -11164, -11138, -11113, + -11088, -11063, -11038, -11013, + -10988, -10964, -10939, -10915, + -10891, -10866, -10843, -10818, + -10794, -10770, -10747, -10723, + -10700, -10676, -10652, -10630, + -10606, -10583, -10560, -10537, + -10514, -10491, -10469, -10446, + -10424, -10401, -10378, -10356, + -10334, -10312, -10290, -10267, + -10246, -10224, -10202, -10180, + -10158, -10137, -10115, -10094, + -10072, -10051, -10030, -10009, + -9988, -9967, -9945, -9925, + -9904, -9883, -9862, -9842, + -9821, -9800, -9780, -9760, + -9739, -9719, -9699, -9678, + -9658, -9638, -9618, -9599, + -9578, -9559, -9539, -9519, + -9499, -9480, -9461, -9441, + -9422, -9402, -9383, -9363, + -9344, -9325, -9306, -9287, + -9268, -9249, -9230, -9211, + -9192, -9173, -9155, -9136, + -9117, -9098, -9080, -9062, + -9043, -9025, -9006, -8988, + -8970, -8951, -8933, -8915, + -8897, -8879, -8861, -8843, + -8825, -8807, -8789, -8772, + -8754, -8736, -8718, -8701, + -8683, -8665, -8648, -8630, + -8613, -8595, -8578, -8561, + -8543, -8526, -8509, -8492, + -8475, -8458, -8441, -8423, + -8407, -8390, -8373, -8356, + -8339, -8322, -8305, -8289, + -8272, -8255, -8239, -8222, + -8206, -8189, -8172, -8156, + -8140, -8123, -8107, -8090, + -8074, -8058, -8042, -8025, + -8009, -7993, -7977, -7961, + -7945, -7929, -7913, -7897, + -7881, -7865, -7849, -7833, + -7817, -7802, -7786, -7770, + -7754, -7739, -7723, -7707, + -7692, -7676, -7661, -7645, + -7630, -7614, -7599, -7583, + -7568, -7553, -7537, -7522, + -7507, -7492, -7476, -7461, + -7446, -7431, -7416, -7401, + -7385, -7370, -7356, -7340, + -7325, -7311, -7296, -7281, + -7266, -7251, -7236, -7221, + -7207, -7192, -7177, -7162, + -7148, -7133, -7118, -7104, + -7089, -7075, -7060, -7046, + -7031, -7016, -7002, -6988, + -6973, -6959, -6944, -6930, + -6916, -6901, -6887, -6873, + -6859, -6844, -6830, -6816, + -6802, -6788, -6774, -6760, + -6746, -6731, -6717, -6704, + -6690, -6675, -6661, -6647, + -6633, -6620, -6606, -6592, + -6578, -6564, -6550, -6537, + -6523, -6509, -6495, -6482, + -6468, -6454, -6441, -6427, + -6413, -6400, -6386, -6373, + -6359, -6346, -6332, -6318, + -6305, -6291, -6278, -6264, + -6251, -6238, -6224, -6211, + -6198, -6184, -6171, -6158, + -6144, -6131, -6118, -6105, + -6091, -6078, -6065, -6052, + -6039, -6025, -6012, -5999, + -5986, -5973, -5960, -5947, + -5934, -5921, -5908, -5895, + -5882, -5869, -5856, -5843, + -5830, -5817, -5804, -5791, + -5779, -5766, -5753, -5740, + -5727, -5714, -5702, -5689, + -5676, -5663, -5650, -5638, + -5625, -5612, -5600, -5587, + -5575, -5562, -5549, -5537, + -5524, -5512, -5499, -5486, + -5474, -5461, -5449, -5436, + -5424, -5411, -5399, -5386, + -5374, -5362, -5349, -5337, + -5324, -5312, -5299, -5287, + -5275, -5263, -5250, -5238, + -5226, -5213, -5201, -5189, + -5177, -5164, -5152, -5140, + -5128, -5115, -5103, -5091, + -5079, -5067, -5055, -5043, + -5030, -5018, -5006, -4994, + -4982, -4970, -4958, -4946, + -4934, -4922, -4910, -4898, + -4886, -4874, -4862, -4850, + -4838, -4826, -4814, -4803, + -4791, -4778, -4767, -4755, + -4743, -4731, -4719, -4708, + -4696, -4684, -4672, -4660, + -4649, -4637, -4625, -4613, + -4601, -4590, -4578, -4566, + -4554, -4543, -4531, -4520, + -4508, -4496, -4484, -4473, + -4461, -4449, -4438, -4427, + -4415, -4403, -4392, -4380, + -4368, -4357, -4345, -4334, + -4322, -4311, -4299, -4288, + -4276, -4265, -4253, -4242, + -4230, -4219, -4207, -4196, + -4184, -4173, -4162, -4150, + -4139, -4128, -4116, -4105, + -4094, -4082, -4071, -4060, + -4048, -4037, -4026, -4014, + -4003, -3992, -3980, -3969, + -3958, -3946, -3935, -3924, + -3913, -3901, -3890, -3879, + -3868, -3857, -3845, -3834, + -3823, -3812, -3801, -3790, + -3779, -3767, -3756, -3745, + -3734, -3723, -3712, -3700, + -3689, -3678, -3667, -3656, + -3645, -3634, -3623, -3612, + -3601, -3590, -3579, -3568, + -3557, -3545, -3535, -3524, + -3513, -3502, -3491, -3480, + -3469, -3458, -3447, -3436, + -3425, -3414, -3403, -3392, + -3381, -3370, -3360, -3348, + -3337, -3327, -3316, -3305, + -3294, -3283, -3272, -3262, + -3251, -3240, -3229, -3218, + -3207, -3197, -3185, -3175, + -3164, -3153, -3142, -3132, + -3121, -3110, -3099, -3088, + -3078, -3067, -3056, -3045, + -3035, -3024, -3013, -3003, + -2992, -2981, -2970, -2960, + -2949, -2938, -2928, -2917, + -2906, -2895, -2885, -2874, + -2864, -2853, -2842, -2832, + -2821, -2810, -2800, -2789, + -2778, -2768, -2757, -2747, + -2736, -2725, -2715, -2704, + -2694, -2683, -2673, -2662, + -2651, -2641, -2630, -2620, + -2609, -2599, -2588, -2578, + -2567, -2556, -2546, -2535, + -2525, -2515, -2504, -2493, + -2483, -2472, -2462, -2451, + -2441, -2431, -2420, -2410, + -2399, -2389, -2378, -2367, + -2357, -2347, -2336, -2326, + -2315, -2305, -2295, -2284, + -2274, -2263, -2253, -2243, + -2232, -2222, -2211, -2201, + -2191, -2180, -2170, -2159, + -2149, -2139, -2128, -2118, + -2107, -2097, -2087, -2076, + -2066, -2056, -2046, -2035, + -2025, -2014, -2004, -1994, + -1983, -1973, -1963, -1953, + -1942, -1932, -1921, -1911, + -1901, -1891, -1880, -1870, + -1860, -1849, -1839, -1829, + -1819, -1808, -1798, -1788, + -1778, -1767, -1757, -1747, + -1736, -1726, -1716, -1706, + -1695, -1685, -1675, -1665, + -1654, -1644, -1634, -1624, + -1613, -1603, -1593, -1583, + -1573, -1563, -1552, -1542, + -1532, -1522, -1511, -1501, + -1491, -1481, -1471, -1461, + -1450, -1440, -1430, -1420, + -1409, -1400, -1389, -1379, + -1369, -1359, -1348, -1339, + -1328, -1318, -1308, -1298, + -1288, -1278, -1267, -1257, + -1247, -1237, -1227, -1217, + -1207, -1196, -1186, -1176, + -1166, -1156, -1146, -1135, + -1126, -1115, -1105, -1095, + -1085, -1075, -1065, -1055, + -1044, -1034, -1024, -1014, + -1004, -994, -984, -974, + -964, -954, -944, -933, + -923, -913, -903, -893, + -883, -873, -863, -853, + -843, -833, -822, -812, + -802, -792, -782, -772, + -762, -752, -742, -732, + -722, -712, -702, -691, + -682, -671, -662, -651, + -641, -631, -621, -611, + -601, -591, -581, -571, + -561, -551, -541, -531, + -521, -511, -501, -491, + -480, -471, -460, -451, + -440, -430, -420, -410, + -400, -390, -380, -370, + -360, -350, -340, -330, + -320, -310, -300, -290, + -280, -270, -260, -250, + -240, -230, -220, -210, + -199, -190, -179, -170, + -159, -150, -139, -129, + -119, -109, -99, -89, + -79, -69, -59, -49, + -39, -29, -19, -9, + 1, 11, 21, 31, + 41, 51, 61, 71, + 81, 91, 101, 111, + 121, 131, 141, 152, + 161, 172, 181, 192, + 202, 212, 222, 232, + 242, 252, 262, 272, + 282, 292, 302, 312, + 322, 332, 342, 352, + 362, 372, 382, 392, + 402, 412, 422, 433, + 442, 453, 462, 473, + 483, 493, 503, 513, + 523, 533, 543, 553, + 563, 573, 583, 593, + 603, 613, 623, 633, + 643, 653, 664, 673, + 684, 694, 704, 714, + 724, 734, 744, 754, + 764, 774, 784, 794, + 804, 815, 825, 835, + 845, 855, 865, 875, + 885, 895, 905, 915, + 925, 936, 946, 956, + 966, 976, 986, 996, + 1006, 1016, 1026, 1037, + 1047, 1057, 1067, 1077, + 1087, 1097, 1107, 1117, + 1128, 1138, 1148, 1158, + 1168, 1178, 1188, 1198, + 1209, 1219, 1229, 1239, + 1249, 1259, 1269, 1280, + 1290, 1300, 1310, 1320, + 1330, 1341, 1351, 1361, + 1371, 1381, 1391, 1402, + 1412, 1422, 1432, 1442, + 1452, 1463, 1473, 1483, + 1493, 1503, 1513, 1524, + 1534, 1544, 1554, 1565, + 1575, 1585, 1595, 1606, + 1616, 1626, 1636, 1647, + 1656, 1667, 1677, 1687, + 1697, 1708, 1718, 1729, + 1739, 1749, 1759, 1769, + 1780, 1790, 1800, 1810, + 1821, 1831, 1841, 1851, + 1862, 1872, 1883, 1893, + 1903, 1913, 1923, 1934, + 1944, 1955, 1965, 1975, + 1985, 1996, 2006, 2016, + 2027, 2037, 2048, 2058, + 2068, 2079, 2089, 2099, + 2110, 2120, 2130, 2141, + 2151, 2161, 2172, 2182, + 2193, 2203, 2213, 2224, + 2234, 2245, 2255, 2265, + 2276, 2286, 2297, 2307, + 2318, 2328, 2338, 2349, + 2359, 2370, 2380, 2391, + 2401, 2412, 2422, 2433, + 2443, 2454, 2464, 2475, + 2485, 2496, 2506, 2517, + 2527, 2537, 2548, 2559, + 2569, 2580, 2590, 2601, + 2612, 2622, 2632, 2643, + 2654, 2664, 2675, 2685, + 2696, 2707, 2717, 2728, + 2738, 2749, 2759, 2770, + 2781, 2791, 2802, 2813, + 2823, 2834, 2845, 2855, + 2866, 2877, 2887, 2898, + 2909, 2919, 2930, 2941, + 2951, 2962, 2973, 2984, + 2994, 3005, 3015, 3027, + 3037, 3048, 3058, 3069, + 3080, 3091, 3101, 3113, + 3123, 3134, 3145, 3156, + 3166, 3177, 3188, 3199, + 3210, 3220, 3231, 3242, + 3253, 3264, 3275, 3285, + 3296, 3307, 3318, 3329, + 3340, 3351, 3362, 3373, + 3384, 3394, 3405, 3416, + 3427, 3438, 3449, 3460, + 3471, 3482, 3493, 3504, + 3515, 3526, 3537, 3548, + 3559, 3570, 3581, 3592, + 3603, 3614, 3625, 3636, + 3647, 3659, 3670, 3681, + 3692, 3703, 3714, 3725, + 3736, 3747, 3758, 3770, + 3781, 3792, 3803, 3814, + 3825, 3837, 3848, 3859, + 3870, 3881, 3893, 3904, + 3915, 3926, 3937, 3949, + 3960, 3971, 3983, 3994, + 4005, 4017, 4028, 4039, + 4051, 4062, 4073, 4085, + 4096, 4107, 4119, 4130, + 4141, 4153, 4164, 4175, + 4187, 4198, 4210, 4221, + 4233, 4244, 4256, 4267, + 4279, 4290, 4302, 4313, + 4325, 4336, 4348, 4359, + 4371, 4382, 4394, 4406, + 4417, 4429, 4440, 4452, + 4464, 4475, 4487, 4499, + 4510, 4522, 4533, 4545, + 4557, 4569, 4581, 4592, + 4604, 4616, 4627, 4639, + 4651, 4663, 4674, 4686, + 4698, 4710, 4722, 4734, + 4746, 4758, 4769, 4781, + 4793, 4805, 4817, 4829, + 4841, 4853, 4865, 4877, + 4889, 4900, 4913, 4925, + 4936, 4949, 4961, 4973, + 4985, 4997, 5009, 5021, + 5033, 5045, 5057, 5070, + 5081, 5094, 5106, 5118, + 5130, 5143, 5155, 5167, + 5179, 5191, 5204, 5216, + 5228, 5240, 5253, 5265, + 5278, 5290, 5302, 5315, + 5327, 5340, 5352, 5364, + 5377, 5389, 5401, 5414, + 5426, 5439, 5451, 5464, + 5476, 5489, 5502, 5514, + 5527, 5539, 5552, 5564, + 5577, 5590, 5603, 5615, + 5628, 5641, 5653, 5666, + 5679, 5691, 5704, 5717, + 5730, 5743, 5756, 5768, + 5781, 5794, 5807, 5820, + 5833, 5846, 5859, 5872, + 5885, 5897, 5911, 5924, + 5937, 5950, 5963, 5976, + 5989, 6002, 6015, 6028, + 6042, 6055, 6068, 6081, + 6094, 6108, 6121, 6134, + 6147, 6160, 6174, 6187, + 6201, 6214, 6227, 6241, + 6254, 6267, 6281, 6294, + 6308, 6321, 6335, 6348, + 6362, 6375, 6389, 6403, + 6416, 6430, 6443, 6457, + 6471, 6485, 6498, 6512, + 6526, 6540, 6554, 6567, + 6581, 6595, 6609, 6623, + 6637, 6651, 6665, 6679, + 6692, 6706, 6721, 6735, + 6749, 6763, 6777, 6791, + 6805, 6819, 6833, 6848, + 6862, 6876, 6890, 6905, + 6919, 6933, 6948, 6962, + 6976, 6991, 7005, 7020, + 7034, 7049, 7064, 7078, + 7093, 7107, 7122, 7136, + 7151, 7166, 7180, 7195, + 7210, 7225, 7240, 7254, + 7269, 7284, 7299, 7314, + 7329, 7344, 7359, 7374, + 7389, 7404, 7419, 7434, + 7449, 7465, 7480, 7495, + 7510, 7526, 7541, 7556, + 7571, 7587, 7602, 7618, + 7633, 7648, 7664, 7680, + 7695, 7711, 7726, 7742, + 7758, 7773, 7789, 7805, + 7821, 7836, 7852, 7868, + 7884, 7900, 7916, 7932, + 7948, 7964, 7981, 7997, + 8013, 8029, 8045, 8061, + 8078, 8094, 8110, 8127, + 8143, 8160, 8176, 8193, + 8209, 8226, 8242, 8259, + 8276, 8292, 8309, 8326, + 8343, 8360, 8377, 8394, + 8410, 8428, 8444, 8462, + 8479, 8496, 8513, 8530, + 8548, 8565, 8582, 8600, + 8617, 8634, 8652, 8670, + 8687, 8704, 8722, 8740, + 8758, 8775, 8793, 8811, + 8829, 8847, 8865, 8883, + 8901, 8919, 8937, 8955, + 8974, 8992, 9010, 9029, + 9047, 9066, 9084, 9103, + 9121, 9140, 9159, 9177, + 9196, 9215, 9234, 9253, + 9272, 9291, 9310, 9329, + 9349, 9368, 9387, 9406, + 9426, 9445, 9465, 9484, + 9504, 9524, 9544, 9563, + 9583, 9603, 9623, 9643, + 9663, 9683, 9703, 9723, + 9744, 9764, 9785, 9805, + 9826, 9846, 9867, 9888, + 9909, 9930, 9950, 9971, + 9993, 10013, 10035, 10056, + 10077, 10099, 10120, 10142, + 10163, 10185, 10207, 10229, + 10251, 10273, 10294, 10317, + 10339, 10361, 10384, 10406, + 10428, 10451, 10474, 10496, + 10519, 10542, 10565, 10588, + 10612, 10635, 10658, 10682, + 10705, 10729, 10752, 10776, + 10800, 10824, 10848, 10872, + 10896, 10921, 10945, 10969, + 10994, 11019, 11044, 11069, + 11094, 11119, 11144, 11169, + 11195, 11221, 11246, 11272, + 11298, 11324, 11350, 11376, + 11402, 11429, 11456, 11482, + 11509, 11536, 11563, 11590, + 11618, 11645, 11673, 11701, + 11728, 11756, 11785, 11813, + 11842, 11870, 11899, 11928, + 11957, 11986, 12015, 12045, + 12074, 12104, 12134, 12164, + 12194, 12225, 12255, 12286, + 12317, 12348, 12380, 12411, + 12443, 12475, 12507, 12539, + 12571, 12604, 12637, 12670, + 12703, 12737, 12771, 12804, + 12839, 12873, 12907, 12942, + 12977, 13013, 13048, 13084, + 13120, 13156, 13192, 13229, + 13267, 13304, 13341, 13379, + 13418, 13456, 13495, 13534, + 13573, 13613, 13653, 13693, + 13734, 13775, 13817, 13858, + 13901, 13943, 13986, 14029, + 14073, 14117, 14162, 14206, + 14252, 14297, 14343, 14390, + 14437, 14485, 14533, 14582, + 14631, 14680, 14731, 14782, + 14833, 14885, 14937, 14991, + 15044, 15099, 15154, 15210, + 15266, 15324, 15382, 15441, + 15500, 15561, 15622, 15684, + 15747, 15811, 15877, 15943, + 16010, 16078, 16148, 16218, + 16290, 16363, 16437, 16513, + 16590, 16669, 16749, 16831, + 16915, 17000, 17088, 17177, + 17268, 17362, 17458, 17556, + 17657, 17761, 17868, 17977, + 18090, 18207, 18328, 18452, + 18581, 18715, 18854, 18998, + 19149, 19307, 19472, 19645, + 19828, 20021, 20226, 20444, + 20678, 20930, 21204, 21503, + 21835, 22206, 22630, 23124, + 23721, 24478, 25529, 27316, +}; + +/* tabledist - return a pseudo-randomly distributed value with mean mu and + * std deviation sigma. Uses table lookup to approximate the desired + * distribution, and a uniformly-distributed pseudo-random source. + */ +static inline int tabledist(int mu, int sigma) +{ + int x; + int index; + int sigmamod, sigmadiv; + + if (sigma == 0) + return mu; + + index = (net_random() & (TABLESIZE-1)); + sigmamod = sigma%TABLEFACTOR; + sigmadiv = sigma/TABLEFACTOR; + x = sigmamod*disttable[index]; + + if (x >= 0) + x += TABLEFACTOR/2; + else + x -= TABLEFACTOR/2; + + x /= TABLEFACTOR; + x += sigmadiv*disttable[index]; + x += mu; + return x; +} + /* Enqueue packets with underlying discipline (fifo) * but mark them with current time first. */ @@ -51,6 +605,8 @@ static int netem_enqueue(struct sk_buff { struct netem_sched_data *q = (struct netem_sched_data *)sch->data; struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; + psched_time_t now; + long delay; pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); @@ -60,101 +616,105 @@ static int netem_enqueue(struct sk_buff return 0; /* lie about loss so TCP doesn't know */ } - if (q->qnormal.qlen < sch->dev->tx_queue_len) { - PSCHED_GET_TIME(cb->time_to_send); - PSCHED_TADD(cb->time_to_send, q->latency); - __skb_queue_tail(&q->qnormal, skb); - sch->q.qlen++; - sch->stats.bytes += skb->len; - sch->stats.packets++; - return 0; + /* If doing simple delay then gap == 0 so all packets + * go into the delayed holding queue + * otherwise if doing out of order only "1 out of gap" + * packets will be delayed. + */ + if (q->counter < q->gap) { + int ret; + + ++q->counter; + ret = q->qdisc->enqueue(skb, q->qdisc); + if (ret) + sch->stats.drops++; + return ret; } - - sch->stats.drops++; - kfree_skb(skb); - return NET_XMIT_DROP; + + q->counter = 0; + + PSCHED_GET_TIME(now); + if (q->jitter) + delay = tabledist(q->latency, q->jitter); + else + delay = q->latency; + + PSCHED_TADD2(now, delay, cb->time_to_send); + + /* Always queue at tail to keep packets in order */ + __skb_queue_tail(&q->delayed, skb); + sch->q.qlen++; + sch->stats.bytes += skb->len; + sch->stats.packets++; + return 0; } /* Requeue packets but don't change time stamp */ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch) { struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + int ret; - __skb_queue_head(&q->qnormal, skb); - sch->q.qlen++; - return 0; + if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) + sch->q.qlen++; + + return ret; } -/* - * Check the look aside buffer list, and see if any freshly baked buffers. - * If head of queue is not baked, set timer. - */ -static struct sk_buff *netem_get_delayed(struct netem_sched_data *q) +static unsigned int netem_drop(struct Qdisc* sch) { - struct sk_buff *skb; - psched_time_t now; - long delay; - - skb = skb_peek(&q->qdelay); - if (skb) { - const struct netem_skb_cb *cb - = (const struct netem_skb_cb *)skb->cb; - - PSCHED_GET_TIME(now); - delay = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); - pr_debug("netem_dequeue: delay queue %p@%lu %ld\n", - skb, jiffies, delay); - - /* it's baked enough */ - if (delay <= 0) { - __skb_unlink(skb, &q->qdelay); - del_timer(&q->timer); - return skb; - } + struct netem_sched_data *q = (struct netem_sched_data *)sch->data; + unsigned int len; - if (!timer_pending(&q->timer)) { - q->timer.expires = jiffies + delay; - add_timer(&q->timer); - } + if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { + sch->q.qlen--; + sch->stats.drops++; } - return NULL; + return len; } /* Dequeue packet. - * If packet needs to be held up, then put in the delay - * queue and set timer to wakeup later. + * Move all packets that are ready to send from the delay holding + * list to the underlying qdisc, then just call dequeue */ static struct sk_buff *netem_dequeue(struct Qdisc *sch) { struct netem_sched_data *q = (struct netem_sched_data *)sch->data; struct sk_buff *skb; + psched_time_t now; + + PSCHED_GET_TIME(now); + while ((skb = skb_peek(&q->delayed)) != NULL) { + const struct netem_skb_cb *cb + = (const struct netem_skb_cb *)skb->cb; + long delay + = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); + pr_debug("netem_dequeue: delay queue %p@%lu %ld\n", + skb, jiffies, delay); - skb = netem_get_delayed(q); - if (!skb && (skb = __skb_dequeue(&q->qnormal))) { - /* are we doing out of order packet skip? */ - if (q->counter < q->gap) { - pr_debug("netem_dequeue: send %p normally\n", skb); - q->counter++; - } else { - /* don't send now hold for later */ - pr_debug("netem_dequeue: hold [%p]@%lu\n", skb, jiffies); - __skb_queue_tail(&q->qdelay, skb); - q->counter = 0; - skb = netem_get_delayed(q); + /* if more time remaining? */ + if (delay > 0) { + mod_timer(&q->timer, jiffies + delay); + break; } + __skb_unlink(skb, &q->delayed); + + if (q->qdisc->enqueue(skb, q->qdisc)) + sch->stats.drops++; } - if (skb) + skb = q->qdisc->dequeue(q->qdisc); + if (skb) sch->q.qlen--; return skb; } -static void netem_timer(unsigned long arg) +static void netem_watchdog(unsigned long arg) { struct Qdisc *sch = (struct Qdisc *)arg; - pr_debug("netem_timer: fired @%lu\n", jiffies); + pr_debug("netem_watchdog: fired @%lu\n", jiffies); netif_schedule(sch->dev); } @@ -162,24 +722,63 @@ static void netem_reset(struct Qdisc *sc { struct netem_sched_data *q = (struct netem_sched_data *)sch->data; - skb_queue_purge(&q->qnormal); - skb_queue_purge(&q->qdelay); + qdisc_reset(q->qdisc); + skb_queue_purge(&q->delayed); sch->q.qlen = 0; del_timer_sync(&q->timer); } +static int set_fifo_limit(struct Qdisc *q, int limit) +{ + struct rtattr *rta; + int ret = -ENOMEM; + + rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); + if (rta) { + rta->rta_type = RTM_NEWQDISC; + rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + + ret = q->ops->change(q, rta); + kfree(rta); + } + return ret; +} + static int netem_change(struct Qdisc *sch, struct rtattr *opt) { struct netem_sched_data *q = (struct netem_sched_data *)sch->data; struct tc_netem_qopt *qopt = RTA_DATA(opt); + struct Qdisc *child; + int ret; - if (qopt->limit) - sch->dev->tx_queue_len = qopt->limit; + if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) + return -EINVAL; - q->gap = qopt->gap; - q->loss = qopt->loss; - q->latency = qopt->latency; + child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (!child) + return -EINVAL; + + ret = set_fifo_limit(child, qopt->limit); + if (ret) { + qdisc_destroy(child); + return ret; + } + + sch_tree_lock(sch); + if (child) { + child = xchg(&q->qdisc, child); + if (child != &noop_qdisc) + qdisc_destroy(child); + + q->latency = qopt->latency; + q->jitter = qopt->jitter; + q->limit = qopt->limit; + q->gap = qopt->gap; + q->loss = qopt->loss; + } + sch_tree_unlock(sch); return 0; } @@ -191,10 +790,11 @@ static int netem_init(struct Qdisc *sch, if (!opt) return -EINVAL; - skb_queue_head_init(&q->qnormal); - skb_queue_head_init(&q->qdelay); + skb_queue_head_init(&q->delayed); + q->qdisc = &noop_qdisc; + init_timer(&q->timer); - q->timer.function = netem_timer; + q->timer.function = netem_watchdog; q->timer.data = (unsigned long) sch; q->counter = 0; @@ -215,6 +815,7 @@ static int netem_dump(struct Qdisc *sch, struct tc_netem_qopt qopt; qopt.latency = q->latency; + qopt.jitter = q->jitter; qopt.limit = sch->dev->tx_queue_len; qopt.loss = q->loss; qopt.gap = q->gap; @@ -234,6 +835,7 @@ static struct Qdisc_ops netem_qdisc_ops .enqueue = netem_enqueue, .dequeue = netem_dequeue, .requeue = netem_requeue, + .drop = netem_drop, .init = netem_init, .reset = netem_reset, .destroy = netem_destroy, --- linux-2.6.8-rc1/net/sctp/inqueue.c 2003-06-14 12:18:25.000000000 -0700 +++ 25/net/sctp/inqueue.c 2004-07-13 17:09:13.000000000 -0700 @@ -78,7 +78,7 @@ void sctp_inq_free(struct sctp_inq *queu struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL) sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, --- linux-2.6.8-rc1/net/sctp/output.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/sctp/output.c 2004-07-13 17:09:13.000000000 -0700 @@ -133,7 +133,7 @@ void sctp_packet_free(struct sctp_packet SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) sctp_chunk_free(chunk); if (packet->malloced) @@ -370,7 +370,7 @@ int sctp_packet_transmit(struct sctp_pac * [This whole comment explains WORD_ROUND() below.] */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (sctp_chunk_is_data(chunk)) { if (!chunk->has_tsn) { @@ -511,7 +511,7 @@ err: * will get resent or dropped later. */ - while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { if (!sctp_chunk_is_data(chunk)) sctp_chunk_free(chunk); } --- linux-2.6.8-rc1/net/sctp/outqueue.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/sctp/outqueue.c 2004-07-13 17:09:13.000000000 -0700 @@ -245,7 +245,7 @@ void sctp_outq_teardown(struct sctp_outq /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { + while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); /* Mark as part of a failed message. */ @@ -282,7 +282,7 @@ void sctp_outq_teardown(struct sctp_outq } /* Throw away any leftover data chunks. */ - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* Mark as send failure. */ sctp_chunk_fail(chunk, q->error); @@ -292,7 +292,7 @@ void sctp_outq_teardown(struct sctp_outq q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL) sctp_chunk_free(chunk); } @@ -681,7 +681,7 @@ int sctp_outq_flush(struct sctp_outq *q, */ queue = &q->control; - while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) { /* Pick the right transport to use. */ new_transport = chunk->transport; @@ -812,7 +812,7 @@ int sctp_outq_flush(struct sctp_outq *q, start_timer = 0; queue = &q->out; - while ((chunk = sctp_outq_dequeue_data(q))) { + while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid * stream identifier. */ @@ -866,7 +866,7 @@ int sctp_outq_flush(struct sctp_outq *q, SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head " "%p skb->users %d.\n", ntohl(chunk->subh.data_hdr->tsn), - chunk->skb ?chunk->skb->head : 0, + chunk->skb ?chunk->skb->head : NULL, chunk->skb ? atomic_read(&chunk->skb->users) : -1); --- linux-2.6.8-rc1/net/sctp/protocol.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/sctp/protocol.c 2004-07-13 17:09:13.000000000 -0700 @@ -101,7 +101,7 @@ __init int sctp_proc_init(void) { if (!proc_net_sctp) { struct proc_dir_entry *ent; - ent = proc_mkdir("net/sctp", 0); + ent = proc_mkdir("net/sctp", NULL); if (ent) { ent->owner = THIS_MODULE; proc_net_sctp = ent; @@ -134,7 +134,7 @@ void sctp_proc_exit(void) if (proc_net_sctp) { proc_net_sctp = NULL; - remove_proc_entry("net/sctp", 0); + remove_proc_entry("net/sctp", NULL); } } --- linux-2.6.8-rc1/net/sctp/sm_statefuns.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/net/sctp/sm_statefuns.c 2004-07-13 17:09:13.000000000 -0700 @@ -995,7 +995,7 @@ static int sctp_sf_check_restart_addrs(c /* Search through all current addresses and make sure * we aren't adding any new ones. */ - new_addr = 0; + new_addr = NULL; found = 0; list_for_each(pos, &new_asoc->peer.transport_addr_list) { --- linux-2.6.8-rc1/net/sctp/socket.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/sctp/socket.c 2004-07-13 17:09:13.000000000 -0700 @@ -86,8 +86,6 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); -static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, size_t msg_len); @@ -95,7 +93,8 @@ static int sctp_wait_for_packet(struct s static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); static void sctp_wait_for_close(struct sock *sk, long timeo); -static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); +static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, + union sctp_addr *addr, int len); static int sctp_bindx_add(struct sock *, struct sockaddr *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); @@ -111,6 +110,64 @@ static char *sctp_hmac_alg = SCTP_COOKIE extern kmem_cache_t *sctp_bucket_cachep; extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc); +/* Get the sndbuf space available at the time on the association. */ +static inline int sctp_wspace(struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (amt < 0) + amt = 0; + return amt; +} + +/* Increment the used sndbuf space count of the corresponding association by + * the size of the outgoing data chunk. + * Also, set the skb destructor for sndbuf accounting later. + * + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * destructor in the data chunk skb for the purpose of the sndbuf space + * tracking. + */ +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) +{ + struct sctp_association *asoc = chunk->asoc; + struct sock *sk = asoc->base.sk; + + /* The sndbuf space is tracked per association. */ + sctp_association_hold(asoc); + + chunk->skb->destructor = sctp_wfree; + /* Save the chunk pointer in skb for sctp_wfree to use later. */ + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); +} + +/* Verify that this is a valid address. */ +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, + int len) +{ + struct sctp_af *af; + + /* Verify basic sockaddr. */ + af = sctp_sockaddr_af(sctp_sk(sk), addr, len); + if (!af) + return -EINVAL; + + /* Is this a valid SCTP address? */ + if (!af->addr_valid(addr, sctp_sk(sk))) + return -EINVAL; + + if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) + return -EINVAL; + + return 0; +} + /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ @@ -1008,7 +1065,7 @@ SCTP_STATIC int sctp_sendmsg(struct kioc struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = NULL; - sctp_cmsgs_t cmsgs = { 0 }; + sctp_cmsgs_t cmsgs = { NULL }; int err; sctp_scope_t scope; long timeo; @@ -4144,64 +4201,6 @@ no_packet: return NULL; } -/* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, - int len) -{ - struct sctp_af *af; - - /* Verify basic sockaddr. */ - af = sctp_sockaddr_af(sctp_sk(sk), addr, len); - if (!af) - return -EINVAL; - - /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr, sctp_sk(sk))) - return -EINVAL; - - if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) - return -EINVAL; - - return 0; -} - -/* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(struct sctp_association *asoc) -{ - struct sock *sk = asoc->base.sk; - int amt = 0; - - amt = sk->sk_sndbuf - asoc->sndbuf_used; - if (amt < 0) - amt = 0; - return amt; -} - -/* Increment the used sndbuf space count of the corresponding association by - * the size of the outgoing data chunk. - * Also, set the skb destructor for sndbuf accounting later. - * - * Since it is always 1-1 between chunk and skb, and also a new skb is always - * allocated for chunk bundling in sctp_packet_transmit(), we can use the - * destructor in the data chunk skb for the purpose of the sndbuf space - * tracking. - */ -static inline void sctp_set_owner_w(struct sctp_chunk *chunk) -{ - struct sctp_association *asoc = chunk->asoc; - struct sock *sk = asoc->base.sk; - - /* The sndbuf space is tracked per association. */ - sctp_association_hold(asoc); - - chunk->skb->destructor = sctp_wfree; - /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); -} - /* If sndbuf has changed, wake up per association sndbuf waiters. */ static void __sctp_write_space(struct sctp_association *asoc) { --- linux-2.6.8-rc1/net/sctp/ulpevent.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/sctp/ulpevent.c 2004-07-13 17:09:13.000000000 -0700 @@ -48,13 +48,23 @@ #include #include -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc); -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, struct sctp_association *asoc); static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); +/* Stub skb destructor. */ +static void sctp_stub_rfree(struct sk_buff *skb) +{ +/* WARNING: This function is just a warning not to use the + * skb destructor. If the skb is shared, we may get the destructor + * callback on some processor that does not own the sock_lock. This + * was occuring with PACKET socket applications that were monitoring + * our skbs. We can't take the sock_lock, because we can't risk + * recursing if we do really own the sock lock. Instead, do all + * of our rwnd manipulation while we own the sock_lock outright. + */ +} + /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) { @@ -87,6 +97,30 @@ int sctp_ulpevent_is_notification(const return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION); } +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) +{ + struct sk_buff *skb; + + /* Cast away the const, as we are just wanting to + * bump the reference count. + */ + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); + skb->sk = asoc->base.sk; + event->asoc = (struct sctp_association *)asoc; + skb->destructor = sctp_stub_rfree; +} + +/* A simple destructor to give up the reference to the association. */ +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) +{ + sctp_association_put(event->asoc); +} + /* Create and initialize an SCTP_ASSOC_CHANGE event. * * 5.3.1.1 SCTP_ASSOC_CHANGE @@ -789,43 +823,6 @@ void sctp_ulpevent_read_sndrcvinfo(const sizeof(struct sctp_sndrcvinfo), (void *)&sinfo); } -/* Stub skb destructor. */ -static void sctp_stub_rfree(struct sk_buff *skb) -{ -/* WARNING: This function is just a warning not to use the - * skb destructor. If the skb is shared, we may get the destructor - * callback on some processor that does not own the sock_lock. This - * was occuring with PACKET socket applications that were monitoring - * our skbs. We can't take the sock_lock, because we can't risk - * recursing if we do really own the sock lock. Instead, do all - * of our rwnd manipulation while we own the sock_lock outright. - */ -} - -/* Hold the association in case the msg_name needs read out of - * the association. - */ -static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, - const struct sctp_association *asoc) -{ - struct sk_buff *skb; - - /* Cast away the const, as we are just wanting to - * bump the reference count. - */ - sctp_association_hold((struct sctp_association *)asoc); - skb = sctp_event2skb(event); - skb->sk = asoc->base.sk; - event->asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_stub_rfree; -} - -/* A simple destructor to give up the reference to the association. */ -static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) -{ - sctp_association_put(event->asoc); -} - /* Do accounting for bytes received and hold a reference to the association * for each skb. */ --- linux-2.6.8-rc1/net/sctp/ulpqueue.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/net/sctp/ulpqueue.c 2004-07-13 17:09:13.000000000 -0700 @@ -49,10 +49,10 @@ #include /* Forward declarations for internal helpers. */ -static inline struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *); -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, - struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *); +static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *, + struct sctp_ulpevent *); /* 1st Level Abstractions */ @@ -97,12 +97,12 @@ void sctp_ulpq_flush(struct sctp_ulpq *u struct sk_buff *skb; struct sctp_ulpevent *event; - while ((skb = __skb_dequeue(&ulpq->lobby))) { + while ((skb = __skb_dequeue(&ulpq->lobby)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } - while ((skb = __skb_dequeue(&ulpq->reasm))) { + while ((skb = __skb_dequeue(&ulpq->reasm)) != NULL) { event = sctp_skb2event(skb); sctp_ulpevent_free(event); } @@ -466,8 +466,8 @@ done: /* Helper function to reassemble chunks. Hold chunks on the reasm queue that * need reassembling. */ -static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { struct sctp_ulpevent *retval = NULL; @@ -645,8 +645,8 @@ static inline void sctp_ulpq_store_order } -static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, - struct sctp_ulpevent *event) +static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, + struct sctp_ulpevent *event) { __u16 sid, ssn; struct sctp_stream *in; @@ -756,7 +756,7 @@ static __u16 sctp_ulpq_renege_order(stru tsnmap = &ulpq->asoc->peer.tsn_map; - while ((skb = __skb_dequeue_tail(&ulpq->lobby))) { + while ((skb = __skb_dequeue_tail(&ulpq->lobby)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn; @@ -782,7 +782,7 @@ static __u16 sctp_ulpq_renege_frags(stru tsnmap = &ulpq->asoc->peer.tsn_map; /* Walk backwards through the list, reneges the newest tsns. */ - while ((skb = __skb_dequeue_tail(&ulpq->reasm))) { + while ((skb = __skb_dequeue_tail(&ulpq->reasm)) != NULL) { freed += skb_headlen(skb); event = sctp_skb2event(skb); tsn = event->tsn; --- linux-2.6.8-rc1/net/xfrm/xfrm_user.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/net/xfrm/xfrm_user.c 2004-07-13 17:09:13.000000000 -0700 @@ -814,6 +814,20 @@ static int xfrm_get_policy(struct sk_buf return err; } +static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) +{ + struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); + + xfrm_state_flush(p->proto); + return 0; +} + +static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) +{ + xfrm_policy_flush(); + return 0; +} + static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = { NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* NEW SA */ NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* DEL SA */ @@ -826,6 +840,9 @@ static const int xfrm_msg_min[(XFRM_MSG_ NLMSG_LENGTH(sizeof(struct xfrm_user_expire)), /* EXPIRE */ NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */ NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* UPD SA */ + NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */ + NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)), /* FLUSH SA */ + NLMSG_LENGTH(0), /* FLUSH POLICY */ }; static struct xfrm_link { @@ -849,6 +866,9 @@ static struct xfrm_link { {}, { .doit = xfrm_add_policy }, { .doit = xfrm_add_sa, }, + {}, + { .doit = xfrm_flush_sa }, + { .doit = xfrm_flush_policy }, }; static int xfrm_done(struct netlink_callback *cb) --- linux-2.6.8-rc1/scripts/basic/fixdep.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/scripts/basic/fixdep.c 2004-07-13 17:09:46.000000000 -0700 @@ -93,6 +93,14 @@ * (Note: it'd be easy to port over the complete mkdep state machine, * but I don't think the added complexity is worth it) */ +/* + * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto + * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not + * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as + * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, + * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that + * those files will have correct dependencies. + */ #include #include @@ -310,6 +318,7 @@ void parse_dep_file(void *map, size_t le } memcpy(s, m, p-m); s[p-m] = 0; if (strrcmp(s, "include/linux/autoconf.h") && + strrcmp(s, "arch/um/include/uml-config.h") && strrcmp(s, ".ver")) { printf(" %s \\\n", s); do_config_file(s); --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/scripts/mkmakefile 2004-07-13 17:09:16.000000000 -0700 @@ -0,0 +1,31 @@ +#!/bin/sh +# Generates a small Makefile used in the root of the output +# directory, to allow make to be started from there. +# The Makefile also allow for more convinient build of external modules + +# Usage +# $1 - Kernel src directory +# $2 - Output directory +# $3 - version +# $4 - patchlevel + + +cat << EOF +# Automatically generated by $0: don't edit + +VERSION = $3 +PATCHLEVEL = $4 + +KERNELSRC := $1 +KERNELOUTPUT := $2 + +MAKEFLAGS += --no-print-directory + +all: + \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT) + +%:: + \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT) \$@ + +EOF + --- linux-2.6.8-rc1/sound/arm/sa11xx-uda1341.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/arm/sa11xx-uda1341.c 2004-07-13 17:09:19.000000000 -0700 @@ -21,7 +21,7 @@ * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.15 2004/05/03 17:36:50 tiwai Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.17 2004/07/01 08:33:41 tiwai Exp $ */ /*************************************************************************************************** * @@ -108,16 +108,13 @@ MODULE_AUTHOR("Tomas Kasparek "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{UDA1341,iPAQ H3600 UDA1341TS}}"); +MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}"); static char *id = NULL; /* ID for this card */ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard."); -#define chip_t sa11xx_uda1341_t - typedef struct audio_stream { char *id; /* identification string */ int stream_id; /* numeric identification */ @@ -869,7 +866,7 @@ static int __init snd_card_sa11xx_uda134 static int snd_sa11xx_uda1341_suspend(snd_card_t *card, unsigned int state) { - sa11xx_uda1341_t *chip = snd_magic_cast(sa11x_uda1341_t, card->pm_private_data, return -EINVAL); + sa11xx_uda1341_t *chip = card->pm_private_data; snd_pcm_suspend_all(chip->pcm); #ifdef HH_VERSION @@ -886,7 +883,7 @@ static int snd_sa11xx_uda1341_suspend(sn static int snd_sa11xx_uda1341_resume(snd_card_t *card, unsigned int state) { - sa11xx_uda1341_t *chip = snd_magic_cast(sa11x_uda1341_t, card->pm_private_data, return -EINVAL); + sa11xx_uda1341_t *chip = card->pm_private_data; sa11xx_uda1341_audio_init(chip); l3_command(chip->uda1341, CMD_RESUME, NULL); @@ -903,7 +900,7 @@ static int snd_sa11xx_uda1341_resume(snd void snd_sa11xx_uda1341_free(snd_card_t *card) { - sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->private_data, return); + sa11xx_uda1341_t *chip = card->private_data; audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]); audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]); @@ -925,7 +922,7 @@ static int __init sa11xx_uda1341_init(vo if (card == NULL) return -ENOMEM; - sa11xx_uda1341 = snd_magic_kcalloc(sa11xx_uda1341_t, 0, GFP_KERNEL); + sa11xx_uda1341 = kcalloc(1, sizeof(*sa11xx_uda1341), GFP_KERNEL); if (sa11xx_uda1341 == NULL) return -ENOMEM; spin_lock_init(&chip->s[0].dma_lock); --- linux-2.6.8-rc1/sound/core/control.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/control.c 2004-07-13 17:09:19.000000000 -0700 @@ -62,7 +62,7 @@ static int snd_ctl_open(struct inode *in err = -EFAULT; goto __error2; } - ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL); + ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) { err = -ENOMEM; goto __error; @@ -108,7 +108,7 @@ static int snd_ctl_release(struct inode snd_kcontrol_t *control; unsigned int idx; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + ctl = file->private_data; fasync_helper(-1, file, 0, &ctl->fasync); file->private_data = NULL; card = ctl->card; @@ -124,7 +124,7 @@ static int snd_ctl_release(struct inode } up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); - snd_magic_kfree(ctl); + kfree(ctl); module_put(card->module); snd_card_file_remove(card, file); return 0; @@ -155,7 +155,7 @@ void snd_ctl_notify(snd_card_t *card, un goto _found; } } - ev = snd_kcalloc(sizeof(*ev), GFP_ATOMIC); + ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC); if (ev) { ev->id = *id; ev->mask = mask; @@ -188,9 +188,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol snd_runtime_check(control != NULL, return NULL); snd_runtime_check(control->count > 0, return NULL); - kctl = (snd_kcontrol_t *)snd_magic_kcalloc(snd_kcontrol_t, - sizeof(snd_kcontrol_volatile_t) * control->count, - GFP_KERNEL); + kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL); if (kctl == NULL) return NULL; *kctl = *control; @@ -249,7 +247,7 @@ void snd_ctl_free_one(snd_kcontrol_t * k if (kcontrol) { if (kcontrol->private_free) kcontrol->private_free(kcontrol); - snd_magic_kfree(kcontrol); + kfree(kcontrol); } } @@ -927,7 +925,7 @@ static int snd_ctl_elem_add(snd_ctl_file if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++) dimen_size += sizeof(unsigned short); - ue = snd_kcalloc(sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL); + ue = kcalloc(1, sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL); if (ue == NULL) return -ENOMEM; ue->type = info.type; @@ -1033,7 +1031,7 @@ static int snd_ctl_ioctl(struct inode *i int __user *ip = argp; int err; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + ctl = file->private_data; card = ctl->card; snd_assert(card != NULL, return -ENXIO); switch (cmd) { @@ -1102,7 +1100,7 @@ static ssize_t snd_ctl_read(struct file int err = 0; ssize_t result = 0; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + ctl = file->private_data; snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO); if (!ctl->subscribed) return -EBADFD; @@ -1155,7 +1153,7 @@ static unsigned int snd_ctl_poll(struct unsigned int mask; snd_ctl_file_t *ctl; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return 0); + ctl = file->private_data; if (!ctl->subscribed) return 0; poll_wait(file, &ctl->change_sleep, wait); @@ -1175,8 +1173,7 @@ int snd_ctl_register_ioctl(snd_kctl_ioct { snd_kctl_ioctl_t *pn; - pn = (snd_kctl_ioctl_t *) - snd_kcalloc(sizeof(snd_kctl_ioctl_t), GFP_KERNEL); + pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL); if (pn == NULL) return -ENOMEM; pn->fioctl = fcn; @@ -1214,7 +1211,7 @@ static int snd_ctl_fasync(int fd, struct { snd_ctl_file_t *ctl; int err; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + ctl = file->private_data; err = fasync_helper(fd, file, on, &ctl->fasync); if (err < 0) return err; --- linux-2.6.8-rc1/sound/core/device.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/sound/core/device.c 2004-07-13 17:09:19.000000000 -0700 @@ -47,7 +47,7 @@ int snd_device_new(snd_card_t *card, snd snd_device_t *dev; snd_assert(card != NULL && device_data != NULL && ops != NULL, return -ENXIO); - dev = (snd_device_t *) snd_magic_kcalloc(snd_device_t, 0, GFP_KERNEL); + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; dev->card = card; @@ -94,7 +94,7 @@ int snd_device_free(snd_card_t *card, vo snd_printk(KERN_ERR "device free failure\n"); } } - snd_magic_kfree(dev); + kfree(dev); return 0; } snd_printd("device free %p (from %p), not found\n", device_data, __builtin_return_address(0)); --- linux-2.6.8-rc1/sound/core/hwdep.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/hwdep.c 2004-07-13 17:09:19.000000000 -0700 @@ -49,7 +49,7 @@ static int snd_hwdep_dev_unregister(snd_ static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; if (hw->ops.llseek) return hw->ops.llseek(hw, file, offset, orig); return -ENXIO; @@ -57,7 +57,7 @@ static loff_t snd_hwdep_llseek(struct fi static ssize_t snd_hwdep_read(struct file * file, char __user *buf, size_t count, loff_t *offset) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; if (hw->ops.read) return hw->ops.read(hw, buf, count, offset); return -ENXIO; @@ -65,7 +65,7 @@ static ssize_t snd_hwdep_read(struct fil static ssize_t snd_hwdep_write(struct file * file, const char __user *buf, size_t count, loff_t *offset) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; if (hw->ops.write) return hw->ops.write(hw, buf, count, offset); return -ENXIO; @@ -157,7 +157,7 @@ static int snd_hwdep_open(struct inode * static int snd_hwdep_release(struct inode *inode, struct file * file) { int err = -ENXIO; - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; down(&hw->open_mutex); if (hw->ops.release) { err = hw->ops.release(hw, file); @@ -173,7 +173,7 @@ static int snd_hwdep_release(struct inod static unsigned int snd_hwdep_poll(struct file * file, poll_table * wait) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return 0); + snd_hwdep_t *hw = file->private_data; if (hw->ops.poll) return hw->ops.poll(hw, file, wait); return 0; @@ -234,7 +234,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_ static int snd_hwdep_ioctl(struct inode *inode, struct file * file, unsigned int cmd, unsigned long arg) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; void __user *argp = (void __user *)arg; switch (cmd) { case SNDRV_HWDEP_IOCTL_PVERSION: @@ -253,7 +253,7 @@ static int snd_hwdep_ioctl(struct inode static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma) { - snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); + snd_hwdep_t *hw = file->private_data; if (hw->ops.mmap) return hw->ops.mmap(hw, file, vma); return -ENXIO; @@ -352,7 +352,7 @@ int snd_hwdep_new(snd_card_t * card, cha snd_assert(rhwdep != NULL, return -EINVAL); *rhwdep = NULL; snd_assert(card != NULL, return -ENXIO); - hwdep = snd_magic_kcalloc(snd_hwdep_t, 0, GFP_KERNEL); + hwdep = kcalloc(1, sizeof(*hwdep), GFP_KERNEL); if (hwdep == NULL) return -ENOMEM; hwdep->card = card; @@ -378,19 +378,19 @@ static int snd_hwdep_free(snd_hwdep_t *h snd_assert(hwdep != NULL, return -ENXIO); if (hwdep->private_free) hwdep->private_free(hwdep); - snd_magic_kfree(hwdep); + kfree(hwdep); return 0; } static int snd_hwdep_dev_free(snd_device_t *device) { - snd_hwdep_t *hwdep = snd_magic_cast(snd_hwdep_t, device->device_data, return -ENXIO); + snd_hwdep_t *hwdep = device->device_data; return snd_hwdep_free(hwdep); } static int snd_hwdep_dev_register(snd_device_t *device) { - snd_hwdep_t *hwdep = snd_magic_cast(snd_hwdep_t, device->device_data, return -ENXIO); + snd_hwdep_t *hwdep = device->device_data; int idx, err; char name[32]; @@ -433,7 +433,7 @@ static int snd_hwdep_dev_register(snd_de static int snd_hwdep_dev_unregister(snd_device_t *device) { - snd_hwdep_t *hwdep = snd_magic_cast(snd_hwdep_t, device->device_data, return -ENXIO); + snd_hwdep_t *hwdep = device->device_data; int idx; snd_assert(hwdep != NULL, return -ENXIO); --- linux-2.6.8-rc1/sound/core/info.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/info.c 2004-07-13 17:09:19.000000000 -0700 @@ -139,7 +139,7 @@ static loff_t snd_info_entry_llseek(stru struct snd_info_entry *entry; loff_t ret; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; entry = data->entry; lock_kernel(); switch (entry->content) { @@ -182,7 +182,7 @@ static ssize_t snd_info_entry_read(struc snd_info_buffer_t *buf; size_t size = 0; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; snd_assert(data != NULL, return -ENXIO); entry = data->entry; switch (entry->content) { @@ -216,7 +216,7 @@ static ssize_t snd_info_entry_write(stru snd_info_buffer_t *buf; size_t size = 0; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; snd_assert(data != NULL, return -ENXIO); entry = data->entry; switch (entry->content) { @@ -284,7 +284,7 @@ static int snd_info_entry_open(struct in goto __error; } } - data = snd_magic_kcalloc(snd_info_private_data_t, 0, GFP_KERNEL); + data = kcalloc(1, sizeof(*data), GFP_KERNEL); if (data == NULL) { err = -ENOMEM; goto __error; @@ -293,10 +293,9 @@ static int snd_info_entry_open(struct in switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: if (mode == O_RDONLY || mode == O_RDWR) { - buffer = (snd_info_buffer_t *) - snd_kcalloc(sizeof(snd_info_buffer_t), GFP_KERNEL); + buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { - snd_magic_kfree(data); + kfree(data); err = -ENOMEM; goto __error; } @@ -305,7 +304,7 @@ static int snd_info_entry_open(struct in buffer->buffer = vmalloc(buffer->len); if (buffer->buffer == NULL) { kfree(buffer); - snd_magic_kfree(data); + kfree(data); err = -ENOMEM; goto __error; } @@ -313,14 +312,13 @@ static int snd_info_entry_open(struct in data->rbuffer = buffer; } if (mode == O_WRONLY || mode == O_RDWR) { - buffer = (snd_info_buffer_t *) - snd_kcalloc(sizeof(snd_info_buffer_t), GFP_KERNEL); + buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { if (mode == O_RDWR) { vfree(data->rbuffer->buffer); kfree(data->rbuffer); } - snd_magic_kfree(data); + kfree(data); err = -ENOMEM; goto __error; } @@ -333,7 +331,7 @@ static int snd_info_entry_open(struct in kfree(data->rbuffer); } kfree(buffer); - snd_magic_kfree(data); + kfree(data); err = -ENOMEM; goto __error; } @@ -345,7 +343,7 @@ static int snd_info_entry_open(struct in if (entry->c.ops->open) { if ((err = entry->c.ops->open(entry, mode, &data->file_private_data)) < 0) { - snd_magic_kfree(data); + kfree(data); goto __error; } } @@ -377,7 +375,7 @@ static int snd_info_entry_release(struct int mode; mode = file->f_flags & O_ACCMODE; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; entry = data->entry; switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: @@ -405,7 +403,7 @@ static int snd_info_entry_release(struct break; } module_put(entry->module); - snd_magic_kfree(data); + kfree(data); return 0; } @@ -415,7 +413,7 @@ static unsigned int snd_info_entry_poll( struct snd_info_entry *entry; unsigned int mask; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; if (data == NULL) return 0; entry = data->entry; @@ -441,7 +439,7 @@ static int snd_info_entry_ioctl(struct i snd_info_private_data_t *data; struct snd_info_entry *entry; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; if (data == NULL) return 0; entry = data->entry; @@ -462,7 +460,7 @@ static int snd_info_entry_mmap(struct fi snd_info_private_data_t *data; struct snd_info_entry *entry; - data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); + data = file->private_data; if (data == NULL) return 0; entry = data->entry; @@ -732,12 +730,12 @@ char *snd_info_get_str(char *dest, char static snd_info_entry_t *snd_info_create_entry(const char *name) { snd_info_entry_t *entry; - entry = snd_magic_kcalloc(snd_info_entry_t, 0, GFP_KERNEL); + entry = kcalloc(1, sizeof(*entry), GFP_KERNEL); if (entry == NULL) return NULL; entry->name = snd_kmalloc_strdup(name, GFP_KERNEL); if (entry->name == NULL) { - snd_magic_kfree(entry); + kfree(entry); return NULL; } entry->mode = S_IFREG | S_IRUGO; @@ -793,27 +791,27 @@ snd_info_entry_t *snd_info_create_card_e static int snd_info_dev_free_entry(snd_device_t *device) { - snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); + snd_info_entry_t *entry = device->device_data; snd_info_free_entry(entry); return 0; } static int snd_info_dev_register_entry(snd_device_t *device) { - snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); + snd_info_entry_t *entry = device->device_data; return snd_info_register(entry); } static int snd_info_dev_disconnect_entry(snd_device_t *device) { - snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); + snd_info_entry_t *entry = device->device_data; entry->disconnected = 1; return 0; } static int snd_info_dev_unregister_entry(snd_device_t *device) { - snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); + snd_info_entry_t *entry = device->device_data; return snd_info_unregister(entry); } @@ -875,7 +873,7 @@ void snd_info_free_entry(snd_info_entry_ kfree((char *)entry->name); if (entry->private_free) entry->private_free(entry); - snd_magic_kfree(entry); + kfree(entry); } /** --- linux-2.6.8-rc1/sound/core/init.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/init.c 2004-07-13 17:09:19.000000000 -0700 @@ -73,7 +73,7 @@ snd_card_t *snd_card_new(int idx, const if (extra_size < 0) extra_size = 0; - card = (snd_card_t *) snd_kcalloc(sizeof(snd_card_t) + extra_size, GFP_KERNEL); + card = kcalloc(1, sizeof(*card) + extra_size, GFP_KERNEL); if (card == NULL) return NULL; if (xid) { --- linux-2.6.8-rc1/sound/core/ioctl32/ioctl32.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/ioctl32/ioctl32.c 2004-07-13 17:09:19.000000000 -0700 @@ -257,7 +257,7 @@ static int get_ctl_type(struct file *fil snd_ctl_elem_info_t info; int err; - ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + ctl = file->private_data; down_read(&ctl->card->controls_rwsem); kctl = snd_ctl_find_id(ctl->card, id); --- linux-2.6.8-rc1/sound/core/ioctl32/pcm32.c 2003-09-27 18:57:47.000000000 -0700 +++ 25/sound/core/ioctl32/pcm32.c 2004-07-13 17:09:19.000000000 -0700 @@ -234,7 +234,7 @@ static int _snd_ioctl32_xfern(unsigned i /* FIXME: need to check whether fop->ioctl is sane */ - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL && substream->runtime, return -ENXIO); @@ -349,8 +349,8 @@ static int _snd_ioctl32_pcm_hw_params_ol mm_segment_t oldseg; int err; - data32 = snd_kcalloc(sizeof(*data32), GFP_KERNEL); - data = snd_kcalloc(sizeof(*data), GFP_KERNEL); + data32 = kcalloc(1, sizeof(*data32), GFP_KERNEL); + data = kcalloc(1, sizeof(*data), GFP_KERNEL); if (data32 == NULL || data == NULL) { err = -ENOMEM; goto __end; --- linux-2.6.8-rc1/sound/core/memalloc.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/memalloc.c 2004-07-13 17:09:19.000000000 -0700 @@ -45,10 +45,14 @@ MODULE_LICENSE("GPL"); #ifndef SNDRV_CARDS #define SNDRV_CARDS 8 #endif + +/* FIXME: so far only some PCI devices have the preallocation table */ +#ifdef CONFIG_PCI static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; static int boot_devs; module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); +#endif /* */ --- linux-2.6.8-rc1/sound/core/memory.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/memory.c 2004-07-13 17:09:19.000000000 -0700 @@ -118,6 +118,17 @@ void *snd_hidden_kmalloc(size_t size, in return _snd_kmalloc(size, flags); } +void *snd_hidden_kcalloc(size_t n, size_t size, int flags) +{ + void *ret = NULL; + if (n != 0 && size > INT_MAX / n) + return ret; + ret = _snd_kmalloc(n * size, flags); + if (ret) + memset(ret, 0, n * size); + return ret; +} + void snd_hidden_kfree(const void *obj) { unsigned long flags; @@ -140,46 +151,6 @@ void snd_hidden_kfree(const void *obj) snd_wrapper_kfree(obj); } -void *_snd_magic_kcalloc(unsigned long magic, size_t size, int flags) -{ - unsigned long *ptr; - ptr = _snd_kmalloc(size + sizeof(unsigned long), flags); - if (ptr) { - *ptr++ = magic; - memset(ptr, 0, size); - } - return ptr; -} - -void *_snd_magic_kmalloc(unsigned long magic, size_t size, int flags) -{ - unsigned long *ptr; - ptr = _snd_kmalloc(size + sizeof(unsigned long), flags); - if (ptr) - *ptr++ = magic; - return ptr; -} - -void snd_magic_kfree(void *_ptr) -{ - unsigned long *ptr = _ptr; - if (ptr == NULL) { - snd_printk(KERN_WARNING "null snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); - return; - } - *--ptr = 0; - { - struct snd_alloc_track *t; - t = snd_alloc_track_entry(ptr); - if (t->magic != KMALLOC_MAGIC) { - snd_printk(KERN_ERR "bad snd_magic_kfree (called from %p)\n", __builtin_return_address(0)); - return; - } - } - snd_hidden_kfree(ptr); - return; -} - void *snd_hidden_vmalloc(unsigned long size) { void *ptr; @@ -256,25 +227,6 @@ int __exit snd_memory_info_done(void) #endif /* CONFIG_SND_DEBUG_MEMORY */ /** - * snd_kcalloc - memory allocation and zero-clear - * @size: the size to allocate in bytes - * @flags: allocation conditions, GFP_XXX - * - * Allocates a memory chunk via kmalloc() and initializes it to zero. - * - * Returns the pointer, or NULL if no enoguh memory. - */ -void *snd_kcalloc(size_t size, int flags) -{ - void *ptr; - - ptr = _snd_kmalloc(size, flags); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -/** * snd_kmalloc_strdup - copy the string * @string: the original string * @flags: allocation conditions, GFP_XXX --- linux-2.6.8-rc1/sound/core/oss/mixer_oss.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/oss/mixer_oss.c 2004-07-13 17:09:19.000000000 -0700 @@ -51,7 +51,7 @@ static int snd_mixer_oss_open(struct ino err = snd_card_file_add(card, file); if (err < 0) return err; - fmixer = (snd_mixer_oss_file_t *)snd_kcalloc(sizeof(*fmixer), GFP_KERNEL); + fmixer = kcalloc(1, sizeof(*fmixer), GFP_KERNEL); if (fmixer == NULL) { snd_card_file_remove(card, file); return -ENOMEM; @@ -508,8 +508,8 @@ static void snd_mixer_oss_get_volume1_vo up_read(&card->controls_rwsem); return; } - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -544,8 +544,8 @@ static void snd_mixer_oss_get_volume1_sw up_read(&card->controls_rwsem); return; } - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -607,8 +607,8 @@ static void snd_mixer_oss_put_volume1_vo down_read(&card->controls_rwsem); if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) return; - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -646,8 +646,8 @@ static void snd_mixer_oss_put_volume1_sw up_read(&fmixer->card->controls_rwsem); return; } - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -767,8 +767,8 @@ static int snd_mixer_oss_get_recsrc2(snd snd_ctl_elem_value_t *uctl; int err, idx; - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; goto __unlock; @@ -814,8 +814,8 @@ static int snd_mixer_oss_put_recsrc2(snd int err; unsigned int idx; - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); - uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; goto __unlock; @@ -1060,7 +1060,7 @@ static char *oss_mixer_names[SNDRV_OSS_M static void snd_mixer_oss_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - snd_mixer_oss_t *mixer = snd_magic_cast(snd_mixer_oss_t, entry->private_data, return); + snd_mixer_oss_t *mixer = entry->private_data; int i; down(&mixer->reg_mutex); @@ -1084,7 +1084,7 @@ static void snd_mixer_oss_proc_read(snd_ static void snd_mixer_oss_proc_write(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - snd_mixer_oss_t *mixer = snd_magic_cast(snd_mixer_oss_t, entry->private_data, return); + snd_mixer_oss_t *mixer = entry->private_data; char line[128], str[32], idxstr[16], *cptr; int ch, idx; struct snd_mixer_oss_assign_table *tbl; @@ -1224,7 +1224,7 @@ static void snd_mixer_oss_build(snd_mixe static int snd_mixer_oss_free1(void *private) { - snd_mixer_oss_t *mixer = snd_magic_cast(snd_mixer_oss_t, private, return -ENXIO); + snd_mixer_oss_t *mixer = private; snd_card_t * card; int idx; @@ -1237,7 +1237,7 @@ static int snd_mixer_oss_free1(void *pri if (chn->private_free) chn->private_free(chn); } - snd_magic_kfree(mixer); + kfree(mixer); return 0; } @@ -1249,7 +1249,7 @@ static int snd_mixer_oss_notify_handler( char name[128]; int idx, err; - mixer = snd_magic_kcalloc(snd_mixer_oss_t, sizeof(snd_mixer_oss_t), GFP_KERNEL); + mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); if (mixer == NULL) return -ENOMEM; init_MUTEX(&mixer->reg_mutex); @@ -1259,7 +1259,7 @@ static int snd_mixer_oss_notify_handler( &snd_mixer_oss_reg, name)) < 0) { snd_printk("unable to register OSS mixer device %i:%i\n", card->number, 0); - snd_magic_kfree(mixer); + kfree(mixer); return err; } mixer->oss_dev_alloc = 1; --- linux-2.6.8-rc1/sound/core/oss/pcm_oss.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/oss/pcm_oss.c 2004-07-13 17:09:19.000000000 -0700 @@ -53,13 +53,10 @@ MODULE_DESCRIPTION("PCM OSS emulation fo MODULE_LICENSE("GPL"); module_param_array(dsp_map, int, boot_devs, 0444); MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device."); -MODULE_PARM_SYNTAX(dsp_map, "default:0,skill:advanced"); module_param_array(adsp_map, int, boot_devs, 0444); MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device."); -MODULE_PARM_SYNTAX(adsp_map, "default:1,skill:advanced"); module_param(nonblock_open, bool, 0644); MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices."); -MODULE_PARM_SYNTAX(nonblock_open, "default:0,skill:advanced"); MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM); MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1); @@ -1177,10 +1174,11 @@ static int snd_pcm_oss_get_formats(snd_p snd_pcm_substream_t *substream; int err; int direct; - snd_pcm_hw_params_t params; + snd_pcm_hw_params_t *params; unsigned int formats = 0; snd_mask_t format_mask; int fmt; + if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; if (atomic_read(&substream->runtime->mmap_count)) { @@ -1194,10 +1192,14 @@ static int snd_pcm_oss_get_formats(snd_p AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE; - _snd_pcm_hw_params_any(¶ms); - err = snd_pcm_hw_refine(substream, ¶ms); + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + _snd_pcm_hw_params_any(params); + err = snd_pcm_hw_refine(substream, params); + format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + kfree(params); snd_assert(err >= 0, return err); - format_mask = *hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT); for (fmt = 0; fmt < 32; ++fmt) { if (snd_mask_test(&format_mask, fmt)) { int f = snd_pcm_oss_format_to(fmt); @@ -1693,7 +1695,7 @@ static int snd_pcm_oss_release_file(snd_ snd_pcm_oss_release_substream(substream); snd_pcm_release_substream(substream); } - snd_magic_kfree(pcm_oss_file); + kfree(pcm_oss_file); return 0; } @@ -1712,7 +1714,7 @@ static int snd_pcm_oss_open_file(struct snd_assert(rpcm_oss_file != NULL, return -EINVAL); *rpcm_oss_file = NULL; - pcm_oss_file = snd_magic_kcalloc(snd_pcm_oss_file_t, 0, GFP_KERNEL); + pcm_oss_file = kcalloc(1, sizeof(*pcm_oss_file), GFP_KERNEL); if (pcm_oss_file == NULL) return -ENOMEM; @@ -1892,7 +1894,7 @@ static int snd_pcm_oss_release(struct in snd_pcm_substream_t *substream; snd_pcm_oss_file_t *pcm_oss_file; - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); + pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; @@ -1915,7 +1917,7 @@ static int snd_pcm_oss_ioctl(struct inod int __user *p = (int __user *)arg; int res; - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); + pcm_oss_file = file->private_data; if (cmd == OSS_GETVERSION) return put_user(SNDRV_OSS_VERSION, p); if (cmd == OSS_ALSAEMULVER) @@ -2073,7 +2075,7 @@ static ssize_t snd_pcm_oss_read(struct f snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *substream; - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); + pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream == NULL) return -ENXIO; @@ -2094,7 +2096,7 @@ static ssize_t snd_pcm_oss_write(struct snd_pcm_substream_t *substream; long result; - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); + pcm_oss_file = file->private_data; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -ENXIO; @@ -2131,7 +2133,7 @@ static unsigned int snd_pcm_oss_poll(str unsigned int mask; snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return 0); + pcm_oss_file = file->private_data; psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; @@ -2178,7 +2180,7 @@ static int snd_pcm_oss_mmap(struct file #ifdef OSS_DEBUG printk("pcm_oss: mmap begin\n"); #endif - pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); + pcm_oss_file = file->private_data; switch ((area->vm_flags & (VM_READ | VM_WRITE))) { case VM_READ | VM_WRITE: substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; @@ -2280,7 +2282,7 @@ static void snd_pcm_oss_proc_write(snd_i snd_info_buffer_t * buffer) { snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data; - char line[512], str[32], task_name[32], *ptr; + char line[256], str[32], task_name[32], *ptr; int idx1; snd_pcm_oss_setup_t *setup, *setup1, template; --- linux-2.6.8-rc1/sound/core/oss/pcm_plugin.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/oss/pcm_plugin.c 2004-07-13 17:09:19.000000000 -0700 @@ -172,7 +172,7 @@ int snd_pcm_plugin_build(snd_pcm_plug_t snd_assert(plug != NULL, return -ENXIO); snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO); - plugin = (snd_pcm_plugin_t *)snd_kcalloc(sizeof(*plugin) + extra, GFP_KERNEL); + plugin = kcalloc(1, sizeof(*plugin) + extra, GFP_KERNEL); if (plugin == NULL) return -ENOMEM; plugin->name = name; @@ -189,7 +189,7 @@ int snd_pcm_plugin_build(snd_pcm_plug_t channels = src_format->channels; else channels = dst_format->channels; - plugin->buf_channels = snd_kcalloc(channels * sizeof(*plugin->buf_channels), GFP_KERNEL); + plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL); if (plugin->buf_channels == NULL) { snd_pcm_plugin_free(plugin); return -ENOMEM; @@ -468,7 +468,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_ if (srcformat.channels > dstformat.channels) { int sv = srcformat.channels; int dv = dstformat.channels; - route_ttable_entry_t *ttable = snd_kcalloc(dv*sv*sizeof(*ttable), GFP_KERNEL); + route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL); if (ttable == NULL) return -ENOMEM; #if 1 @@ -531,7 +531,7 @@ int snd_pcm_plug_format_plugins(snd_pcm_ if (srcformat.channels < dstformat.channels) { int sv = srcformat.channels; int dv = dstformat.channels; - route_ttable_entry_t *ttable = snd_kcalloc(dv * sv * sizeof(*ttable), GFP_KERNEL); + route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL); if (ttable == NULL) return -ENOMEM; #if 0 @@ -846,41 +846,31 @@ int snd_pcm_area_silence(const snd_pcm_c size_t samples, int format) { /* FIXME: sub byte resolution and odd dst_offset */ - char *dst; + unsigned char *dst; unsigned int dst_step; int width; - u_int64_t silence; + const unsigned char *silence; if (!dst_area->addr) return 0; dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; width = snd_pcm_format_physical_width(format); + if (width <= 0) + return -EINVAL; + if (dst_area->step == (unsigned int) width && width >= 8) + return snd_pcm_format_set_silence(format, dst, samples); silence = snd_pcm_format_silence_64(format); - if (dst_area->step == (unsigned int) width) { - size_t dwords = samples * width / 64; - u_int64_t *dst64 = (u_int64_t *)dst; - - samples -= dwords * 64 / width; - while (dwords-- > 0) - *dst64++ = silence; - if (samples == 0) - return 0; - dst = (char *)dst64; - } + if (! silence) + return -EINVAL; dst_step = dst_area->step / 8; - switch (width) { - case 4: { - u_int8_t s0 = silence & 0xf0; - u_int8_t s1 = silence & 0x0f; + if (width == 4) { + /* Ima ADPCM */ int dstbit = dst_area->first % 8; int dstbit_step = dst_area->step % 8; while (samples-- > 0) { - if (dstbit) { + if (dstbit) *dst &= 0xf0; - *dst |= s1; - } else { + else *dst &= 0x0f; - *dst |= s0; - } dst += dst_step; dstbit += dstbit_step; if (dstbit == 8) { @@ -888,41 +878,12 @@ int snd_pcm_area_silence(const snd_pcm_c dstbit = 0; } } - break; - } - case 8: { - u_int8_t sil = silence; - while (samples-- > 0) { - *dst = sil; - dst += dst_step; - } - break; - } - case 16: { - u_int16_t sil = silence; - while (samples-- > 0) { - *(u_int16_t*)dst = sil; - dst += dst_step; - } - break; - } - case 32: { - u_int32_t sil = silence; - while (samples-- > 0) { - *(u_int32_t*)dst = sil; - dst += dst_step; - } - break; - } - case 64: { + } else { + width /= 8; while (samples-- > 0) { - *(u_int64_t*)dst = silence; + memcpy(dst, silence, width); dst += dst_step; } - break; - } - default: - snd_BUG(); } return 0; } @@ -942,18 +903,18 @@ int snd_pcm_area_copy(const snd_pcm_chan if (!dst_area->addr) return 0; width = snd_pcm_format_physical_width(format); + if (width <= 0) + return -EINVAL; if (src_area->step == (unsigned int) width && - dst_area->step == (unsigned int) width) { + dst_area->step == (unsigned int) width && width >= 8) { size_t bytes = samples * width / 8; - samples -= bytes * 8 / width; memcpy(dst, src, bytes); - if (samples == 0) - return 0; + return 0; } src_step = src_area->step / 8; dst_step = dst_area->step / 8; - switch (width) { - case 4: { + if (width == 4) { + /* Ima ADPCM */ int srcbit = src_area->first % 8; int srcbit_step = src_area->step % 8; int dstbit = dst_area->first % 8; @@ -963,12 +924,11 @@ int snd_pcm_area_copy(const snd_pcm_chan if (srcbit) srcval = *src & 0x0f; else - srcval = *src & 0xf0; + srcval = (*src & 0xf0) >> 4; if (dstbit) - *dst &= 0xf0; + *dst = (*dst & 0xf0) | srcval; else - *dst &= 0x0f; - *dst |= srcval; + *dst = (*dst & 0x0f) | (srcval << 4); src += src_step; srcbit += srcbit_step; if (srcbit == 8) { @@ -982,42 +942,13 @@ int snd_pcm_area_copy(const snd_pcm_chan dstbit = 0; } } - break; - } - case 8: { - while (samples-- > 0) { - *dst = *src; - src += src_step; - dst += dst_step; - } - break; - } - case 16: { - while (samples-- > 0) { - *(u_int16_t*)dst = *(u_int16_t*)src; - src += src_step; - dst += dst_step; - } - break; - } - case 32: { - while (samples-- > 0) { - *(u_int32_t*)dst = *(u_int32_t*)src; - src += src_step; - dst += dst_step; - } - break; - } - case 64: { + } else { + width /= 8; while (samples-- > 0) { - *(u_int64_t*)dst = *(u_int64_t*)src; + memcpy(dst, src, width); src += src_step; dst += dst_step; } - break; - } - default: - snd_BUG(); } return 0; } --- linux-2.6.8-rc1/sound/core/oss/pcm_plugin.h 2003-09-27 18:57:47.000000000 -0700 +++ 25/sound/core/oss/pcm_plugin.h 2004-07-13 17:09:19.000000000 -0700 @@ -35,7 +35,7 @@ static inline size_t bitset_size(int nbi static inline bitset_t *bitset_alloc(int nbits) { - return snd_kcalloc(bitset_size(nbits) * sizeof(bitset_t), GFP_KERNEL); + return kcalloc(bitset_size(nbits), sizeof(bitset_t), GFP_KERNEL); } static inline void bitset_set(bitset_t *bitmap, unsigned int pos) --- linux-2.6.8-rc1/sound/core/oss/route.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/oss/route.c 2004-07-13 17:09:19.000000000 -0700 @@ -458,7 +458,7 @@ static int route_load_ttable(snd_pcm_plu dptr->func = route_to_channel; if (nsrcs > 0) { int srcidx; - dptr->srcs = snd_kcalloc(nsrcs * sizeof(*srcs), GFP_KERNEL); + dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL); for(srcidx = 0; srcidx < nsrcs; srcidx++) dptr->srcs[srcidx] = srcs[srcidx]; } else --- linux-2.6.8-rc1/sound/core/pcm.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -585,7 +585,7 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, i } prev = NULL; for (idx = 0, prev = NULL; idx < substream_count; idx++) { - substream = snd_magic_kcalloc(snd_pcm_substream_t, 0, GFP_KERNEL); + substream = kcalloc(1, sizeof(*substream), GFP_KERNEL); if (substream == NULL) return -ENOMEM; substream->pcm = pcm; @@ -600,7 +600,7 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, i prev->next = substream; err = snd_pcm_substream_proc_init(substream); if (err < 0) { - snd_magic_kfree(substream); + kfree(substream); return err; } substream->group = &substream->self_group; @@ -645,7 +645,7 @@ int snd_pcm_new(snd_card_t * card, char snd_assert(rpcm != NULL, return -EINVAL); *rpcm = NULL; snd_assert(card != NULL, return -ENXIO); - pcm = snd_magic_kcalloc(snd_pcm_t, 0, GFP_KERNEL); + pcm = kcalloc(1, sizeof(*pcm), GFP_KERNEL); if (pcm == NULL) return -ENOMEM; pcm->card = card; @@ -681,7 +681,7 @@ static void snd_pcm_free_stream(snd_pcm_ while (substream) { substream_next = substream->next; snd_pcm_substream_proc_done(substream); - snd_magic_kfree(substream); + kfree(substream); substream = substream_next; } snd_pcm_stream_proc_done(pstr); @@ -702,13 +702,13 @@ static int snd_pcm_free(snd_pcm_t *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]); snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]); - snd_magic_kfree(pcm); + kfree(pcm); return 0; } static int snd_pcm_dev_free(snd_device_t *device) { - snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); + snd_pcm_t *pcm = device->device_data; return snd_pcm_free(pcm); } @@ -783,7 +783,7 @@ int snd_pcm_open_substream(snd_pcm_t *pc if (substream == NULL) return -EAGAIN; - runtime = snd_kcalloc(sizeof(snd_pcm_runtime_t), GFP_KERNEL); + runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL); if (runtime == NULL) return -ENOMEM; @@ -843,7 +843,7 @@ static int snd_pcm_dev_register(snd_devi snd_pcm_substream_t *substream; struct list_head *list; char str[16]; - snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); + snd_pcm_t *pcm = device->device_data; snd_assert(pcm != NULL && device != NULL, return -ENXIO); down(®ister_mutex); @@ -888,7 +888,7 @@ static int snd_pcm_dev_register(snd_devi static int snd_pcm_dev_disconnect(snd_device_t *device) { - snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); + snd_pcm_t *pcm = device->device_data; struct list_head *list; snd_pcm_substream_t *substream; int idx, cidx; @@ -914,7 +914,7 @@ static int snd_pcm_dev_unregister(snd_de int idx, cidx, devtype; snd_pcm_substream_t *substream; struct list_head *list; - snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); + snd_pcm_t *pcm = device->device_data; snd_assert(pcm != NULL, return -ENXIO); down(®ister_mutex); --- linux-2.6.8-rc1/sound/core/pcm_lib.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/pcm_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -894,7 +894,7 @@ int snd_pcm_hw_rule_add(snd_pcm_runtime_ old = constrs->rules; constrs->rules_all += 10; } - constrs->rules = snd_kcalloc(constrs->rules_all * sizeof(*c), + constrs->rules = kcalloc(constrs->rules_all, sizeof(*c), GFP_KERNEL); if (!constrs->rules) return -ENOMEM; --- linux-2.6.8-rc1/sound/core/pcm_memory.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/pcm_memory.c 2004-07-13 17:09:19.000000000 -0700 @@ -32,12 +32,10 @@ static int preallocate_dma = 1; module_param(preallocate_dma, int, 0444); MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized."); -MODULE_PARM_SYNTAX(preallocate_dma, SNDRV_BOOLEAN_TRUE_DESC); static int maximum_substreams = 4; module_param(maximum_substreams, int, 0444); MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory."); -MODULE_PARM_SYNTAX(maximum_substreams, SNDRV_BOOLEAN_TRUE_DESC); const static size_t snd_minimum_buffer = 16384; @@ -314,31 +312,35 @@ struct page *snd_pcm_sgbuf_ops_page(snd_ int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size) { snd_pcm_runtime_t *runtime; - struct snd_dma_buffer dmab; + struct snd_dma_buffer *dmab = NULL; snd_assert(substream->dma_device.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL); snd_assert(substream != NULL, return -EINVAL); runtime = substream->runtime; - snd_assert(runtime != NULL, return -EINVAL); + snd_assert(runtime != NULL, return -EINVAL); - if (runtime->dma_area != NULL) { + if (runtime->dma_buffer_p) { /* perphaps, we might free the large DMA memory region to save some space here, but the actual solution costs us less time */ - if (runtime->dma_bytes >= size) + if (runtime->dma_buffer_p->bytes >= size) { + runtime->dma_bytes = size; return 0; /* ok, do not change */ + } snd_pcm_lib_free_pages(substream); } if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { - dmab = substream->dma_buffer; /* use the pre-allocated buffer */ + dmab = &substream->dma_buffer; /* use the pre-allocated buffer */ } else { - memset(&dmab, 0, sizeof(dmab)); /* allocate a new buffer */ - if (snd_dma_alloc_pages(&substream->dma_device, size, &dmab) < 0) + dmab = kcalloc(1, sizeof(*dmab), GFP_KERNEL); + if (! dmab) + return -ENOMEM; + if (snd_dma_alloc_pages(&substream->dma_device, size, dmab) < 0) { + kfree(dmab); return -ENOMEM; + } } - runtime->dma_area = dmab.area; - runtime->dma_addr = dmab.addr; - runtime->dma_private = dmab.private_data; + snd_pcm_set_runtime_buffer(substream, dmab); runtime->dma_bytes = size; return 1; /* area was changed */ } @@ -360,34 +362,11 @@ int snd_pcm_lib_free_pages(snd_pcm_subst snd_assert(runtime != NULL, return -EINVAL); if (runtime->dma_area == NULL) return 0; - if (runtime->dma_area != substream->dma_buffer.area) { + if (runtime->dma_buffer_p != &substream->dma_buffer) { /* it's a newly allocated buffer. release it now. */ - struct snd_dma_buffer dmab; - memset(&dmab, 0, sizeof(dmab)); - dmab.area = runtime->dma_area; - dmab.addr = runtime->dma_addr; - dmab.bytes = runtime->dma_bytes; - dmab.private_data = runtime->dma_private; - snd_dma_free_pages(&substream->dma_device, &dmab); + snd_dma_free_pages(&substream->dma_device, runtime->dma_buffer_p); + kfree(runtime->dma_buffer_p); } - runtime->dma_area = NULL; - runtime->dma_addr = 0UL; - runtime->dma_bytes = 0; - runtime->dma_private = NULL; + snd_pcm_set_runtime_buffer(substream, NULL); return 0; } - -#ifndef MODULE - -/* format is: snd-pcm=preallocate_dma,maximum_substreams */ - -static int __init alsa_pcm_setup(char *str) -{ - (void)(get_option(&str,&preallocate_dma) == 2 && - get_option(&str,&maximum_substreams) == 2); - return 1; -} - -__setup("snd-pcm=", alsa_pcm_setup); - -#endif /* ifndef MODULE */ --- linux-2.6.8-rc1/sound/core/pcm_misc.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/pcm_misc.c 2004-07-13 17:09:19.000000000 -0700 @@ -23,12 +23,169 @@ #include #include #include -#define bswap_16 swab16 -#define bswap_32 swab32 -#define bswap_64 swab64 #define SND_PCM_FORMAT_UNKNOWN (-1) -#define snd_enum_to_int(v) (v) -#define snd_int_to_enum(v) (v) + +struct pcm_format_data { + char width; /* bit width */ + char phys; /* physical bit width */ + char le; /* 0 = big-endian, 1 = little-endian, -1 = others */ + char signd; /* 0 = unsigned, 1 = signed, -1 = others */ + unsigned char silence[8]; /* silence data to fill */ +}; + +static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { + [SNDRV_PCM_FORMAT_S8] = { + .width = 8, .phys = 8, .le = -1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U8] = { + .width = 8, .phys = 8, .le = -1, .signd = 0, + .silence = { 0x80 }, + }, + [SNDRV_PCM_FORMAT_S16_LE] = { + .width = 16, .phys = 16, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S16_BE] = { + .width = 16, .phys = 16, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U16_LE] = { + .width = 16, .phys = 16, .le = 1, .signd = 0, + .silence = { 0x00, 0x80 }, + }, + [SNDRV_PCM_FORMAT_U16_BE] = { + .width = 16, .phys = 16, .le = 0, .signd = 0, + .silence = { 0x80, 0x00 }, + }, + [SNDRV_PCM_FORMAT_S24_LE] = { + .width = 24, .phys = 32, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S24_BE] = { + .width = 24, .phys = 32, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U24_LE] = { + .width = 24, .phys = 32, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x80 }, + }, + [SNDRV_PCM_FORMAT_U24_BE] = { + .width = 24, .phys = 32, .le = 0, .signd = 0, + .silence = { 0x80, 0x00, 0x00 }, + }, + [SNDRV_PCM_FORMAT_S32_LE] = { + .width = 32, .phys = 32, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S32_BE] = { + .width = 32, .phys = 32, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U32_LE] = { + .width = 32, .phys = 32, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x00, 0x80 }, + }, + [SNDRV_PCM_FORMAT_U32_BE] = { + .width = 32, .phys = 32, .le = 0, .signd = 0, + .silence = { 0x80, 0x00, 0x00, 0x00 }, + }, + [SNDRV_PCM_FORMAT_FLOAT_LE] = { + .width = 32, .phys = 32, .le = 1, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_FLOAT_BE] = { + .width = 32, .phys = 32, .le = 0, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_FLOAT64_LE] = { + .width = 64, .phys = 64, .le = 1, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_FLOAT64_BE] = { + .width = 64, .phys = 64, .le = 0, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = { + .width = 32, .phys = 32, .le = 1, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = { + .width = 32, .phys = 32, .le = 0, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_MU_LAW] = { + .width = 8, .phys = 8, .le = -1, .signd = -1, + .silence = { 0x7f }, + }, + [SNDRV_PCM_FORMAT_A_LAW] = { + .width = 8, .phys = 8, .le = -1, .signd = -1, + .silence = { 0x55 }, + }, + [SNDRV_PCM_FORMAT_IMA_ADPCM] = { + .width = 4, .phys = 4, .le = -1, .signd = -1, + .silence = {}, + }, + /* FIXME: the following three formats are not defined properly yet */ + [SNDRV_PCM_FORMAT_MPEG] = { + .le = -1, .signd = -1, + }, + [SNDRV_PCM_FORMAT_GSM] = { + .le = -1, .signd = -1, + }, + [SNDRV_PCM_FORMAT_SPECIAL] = { + .le = -1, .signd = -1, + }, + [SNDRV_PCM_FORMAT_S24_3LE] = { + .width = 24, .phys = 24, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S24_3BE] = { + .width = 24, .phys = 24, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U24_3LE] = { + .width = 24, .phys = 24, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x80 }, + }, + [SNDRV_PCM_FORMAT_U24_3BE] = { + .width = 24, .phys = 24, .le = 0, .signd = 0, + .silence = { 0x80, 0x00, 0x00 }, + }, + [SNDRV_PCM_FORMAT_S20_3LE] = { + .width = 20, .phys = 24, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S20_3BE] = { + .width = 20, .phys = 24, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U20_3LE] = { + .width = 20, .phys = 24, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x08 }, + }, + [SNDRV_PCM_FORMAT_U20_3BE] = { + .width = 20, .phys = 24, .le = 0, .signd = 0, + .silence = { 0x08, 0x00, 0x00 }, + }, + [SNDRV_PCM_FORMAT_S18_3LE] = { + .width = 18, .phys = 24, .le = 1, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_S18_3BE] = { + .width = 18, .phys = 24, .le = 0, .signd = 1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_U18_3LE] = { + .width = 18, .phys = 24, .le = 1, .signd = 0, + .silence = { 0x00, 0x00, 0x02 }, + }, + [SNDRV_PCM_FORMAT_U18_3BE] = { + .width = 18, .phys = 24, .le = 0, .signd = 0, + .silence = { 0x02, 0x00, 0x00 }, + }, +}; + /** * snd_pcm_format_signed - Check the PCM format is signed linear @@ -39,38 +196,12 @@ */ int snd_pcm_format_signed(snd_pcm_format_t format) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S8: - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - return 1; - case SNDRV_PCM_FORMAT_U8: - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_U16_BE: - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_U24_BE: - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_U32_BE: - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_U24_3BE: - case SNDRV_PCM_FORMAT_U20_3LE: - case SNDRV_PCM_FORMAT_U20_3BE: - case SNDRV_PCM_FORMAT_U18_3LE: - case SNDRV_PCM_FORMAT_U18_3BE: - return 0; - default: + int val; + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) return -EINVAL; - } + if ((val = pcm_formats[format].signd) < 0) + return -EINVAL; + return val; } /** @@ -110,42 +241,12 @@ int snd_pcm_format_linear(snd_pcm_format */ int snd_pcm_format_little_endian(snd_pcm_format_t format) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_FLOAT_LE: - case SNDRV_PCM_FORMAT_FLOAT64_LE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_U20_3LE: - case SNDRV_PCM_FORMAT_U18_3LE: - return 1; - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_U16_BE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_U24_BE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_U32_BE: - case SNDRV_PCM_FORMAT_FLOAT_BE: - case SNDRV_PCM_FORMAT_FLOAT64_BE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_S18_3BE: - case SNDRV_PCM_FORMAT_U24_3BE: - case SNDRV_PCM_FORMAT_U20_3BE: - case SNDRV_PCM_FORMAT_U18_3BE: - return 0; - default: + int val; + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) return -EINVAL; - } + if ((val = pcm_formats[format].le) < 0) + return -EINVAL; + return val; } /** @@ -190,55 +291,12 @@ int snd_pcm_format_cpu_endian(snd_pcm_fo */ int snd_pcm_format_width(snd_pcm_format_t format) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S8: - case SNDRV_PCM_FORMAT_U8: - return 8; - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_U16_BE: - return 16; - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - case SNDRV_PCM_FORMAT_U18_3LE: - case SNDRV_PCM_FORMAT_U18_3BE: - return 18; - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_U20_3LE: - case SNDRV_PCM_FORMAT_U20_3BE: - return 20; - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_U24_BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_U24_3BE: - return 24; - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_U32_BE: - case SNDRV_PCM_FORMAT_FLOAT_LE: - case SNDRV_PCM_FORMAT_FLOAT_BE: - return 32; - case SNDRV_PCM_FORMAT_FLOAT64_LE: - case SNDRV_PCM_FORMAT_FLOAT64_BE: - return 64; - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: - return 32; - case SNDRV_PCM_FORMAT_MU_LAW: - case SNDRV_PCM_FORMAT_A_LAW: - return 8; - case SNDRV_PCM_FORMAT_IMA_ADPCM: - return 4; - default: + int val; + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) return -EINVAL; - } + if ((val = pcm_formats[format].width) == 0) + return -EINVAL; + return val; } /** @@ -250,52 +308,12 @@ int snd_pcm_format_width(snd_pcm_format_ */ int snd_pcm_format_physical_width(snd_pcm_format_t format) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S8: - case SNDRV_PCM_FORMAT_U8: - return 8; - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_U16_BE: - return 16; - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - case SNDRV_PCM_FORMAT_U18_3LE: - case SNDRV_PCM_FORMAT_U18_3BE: - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_U20_3LE: - case SNDRV_PCM_FORMAT_U20_3BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_U24_3BE: - return 24; - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_U24_BE: - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_U32_BE: - case SNDRV_PCM_FORMAT_FLOAT_LE: - case SNDRV_PCM_FORMAT_FLOAT_BE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: - return 32; - case SNDRV_PCM_FORMAT_FLOAT64_LE: - case SNDRV_PCM_FORMAT_FLOAT64_BE: - return 64; - case SNDRV_PCM_FORMAT_MU_LAW: - case SNDRV_PCM_FORMAT_A_LAW: - return 8; - case SNDRV_PCM_FORMAT_IMA_ADPCM: - return 4; - default: + int val; + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) return -EINVAL; - } + if ((val = pcm_formats[format].phys) == 0) + return -EINVAL; + return val; } /** @@ -307,216 +325,25 @@ int snd_pcm_format_physical_width(snd_pc */ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S8: - case SNDRV_PCM_FORMAT_U8: - return samples; - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_U16_LE: - case SNDRV_PCM_FORMAT_U16_BE: - return samples * 2; - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - case SNDRV_PCM_FORMAT_U18_3LE: - case SNDRV_PCM_FORMAT_U18_3BE: - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_U20_3LE: - case SNDRV_PCM_FORMAT_U20_3BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_U24_3LE: - case SNDRV_PCM_FORMAT_U24_3BE: - return samples * 3; - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_U24_LE: - case SNDRV_PCM_FORMAT_U24_BE: - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_U32_LE: - case SNDRV_PCM_FORMAT_U32_BE: - case SNDRV_PCM_FORMAT_FLOAT_LE: - case SNDRV_PCM_FORMAT_FLOAT_BE: - return samples * 4; - case SNDRV_PCM_FORMAT_FLOAT64_LE: - case SNDRV_PCM_FORMAT_FLOAT64_BE: - return samples * 8; - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: - return samples * 4; - case SNDRV_PCM_FORMAT_MU_LAW: - case SNDRV_PCM_FORMAT_A_LAW: - return samples; - case SNDRV_PCM_FORMAT_IMA_ADPCM: - if (samples & 1) - return -EINVAL; - return samples / 2; - default: + int phys_width = snd_pcm_format_physical_width(format); + if (phys_width < 0) return -EINVAL; - } + return samples * phys_width / 8; } /** - * snd_pcm_format_silence_64 - return the silent data in 64bit integer + * snd_pcm_format_silence_64 - return the silent data in 8 bytes array * @format: the format to check * - * Returns the silent data in 64bit integer for the given format. + * Returns the format pattern to fill or NULL if error. */ -u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) +const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) { - switch (snd_enum_to_int(format)) { - case SNDRV_PCM_FORMAT_S8: - case SNDRV_PCM_FORMAT_S16_LE: - case SNDRV_PCM_FORMAT_S16_BE: - case SNDRV_PCM_FORMAT_S24_LE: - case SNDRV_PCM_FORMAT_S24_BE: - case SNDRV_PCM_FORMAT_S32_LE: - case SNDRV_PCM_FORMAT_S32_BE: - case SNDRV_PCM_FORMAT_S24_3LE: - case SNDRV_PCM_FORMAT_S24_3BE: - case SNDRV_PCM_FORMAT_S20_3LE: - case SNDRV_PCM_FORMAT_S20_3BE: - case SNDRV_PCM_FORMAT_S18_3LE: - case SNDRV_PCM_FORMAT_S18_3BE: - return 0; - case SNDRV_PCM_FORMAT_U8: - return 0x8080808080808080ULL; -#ifdef SNDRV_LITTLE_ENDIAN - case SNDRV_PCM_FORMAT_U16_LE: - return 0x8000800080008000ULL; - case SNDRV_PCM_FORMAT_U24_LE: - return 0x0080000000800000ULL; - case SNDRV_PCM_FORMAT_U32_LE: - return 0x8000000080000000ULL; - case SNDRV_PCM_FORMAT_U16_BE: - return 0x0080008000800080ULL; - case SNDRV_PCM_FORMAT_U24_BE: - return 0x0000800000008000ULL; - case SNDRV_PCM_FORMAT_U32_BE: - return 0x0000008000000080ULL; - case SNDRV_PCM_FORMAT_U24_3LE: - return 0x0000800000800000ULL; - case SNDRV_PCM_FORMAT_U24_3BE: - return 0x0080000080000080ULL; - case SNDRV_PCM_FORMAT_U20_3LE: - return 0x0000080000080000ULL; - case SNDRV_PCM_FORMAT_U20_3BE: - return 0x0008000008000008ULL; - case SNDRV_PCM_FORMAT_U18_3LE: - return 0x0000020000020000ULL; - case SNDRV_PCM_FORMAT_U18_3BE: - return 0x0002000002000002ULL; -#else - case SNDRV_PCM_FORMAT_U16_LE: - return 0x0080008000800080ULL; - case SNDRV_PCM_FORMAT_U24_LE: - return 0x0000800000008000ULL; - case SNDRV_PCM_FORMAT_U32_LE: - return 0x0000008000000080ULL; - case SNDRV_PCM_FORMAT_U16_BE: - return 0x8000800080008000ULL; - case SNDRV_PCM_FORMAT_U24_BE: - return 0x0080000000800000ULL; - case SNDRV_PCM_FORMAT_U32_BE: - return 0x8000000080000000ULL; - case SNDRV_PCM_FORMAT_U24_3LE: - return 0x0080000080000080ULL; - case SNDRV_PCM_FORMAT_U24_3BE: - return 0x0000800000800000ULL; - case SNDRV_PCM_FORMAT_U20_3LE: - return 0x0008000008000008ULL; - case SNDRV_PCM_FORMAT_U20_3BE: - return 0x0000080000080000ULL; - case SNDRV_PCM_FORMAT_U18_3LE: - return 0x0002000002000002ULL; - case SNDRV_PCM_FORMAT_U18_3BE: - return 0x0000020000020000ULL; -#endif - case SNDRV_PCM_FORMAT_FLOAT_LE: - { - union { - float f; - u_int32_t i; - } u; - u.f = 0.0; -#ifdef SNDRV_LITTLE_ENDIAN - return u.i; -#else - return bswap_32(u.i); -#endif - } - case SNDRV_PCM_FORMAT_FLOAT64_LE: - { - union { - double f; - u_int64_t i; - } u; - u.f = 0.0; -#ifdef SNDRV_LITTLE_ENDIAN - return u.i; -#else - return bswap_64(u.i); -#endif - } - case SNDRV_PCM_FORMAT_FLOAT_BE: - { - union { - float f; - u_int32_t i; - } u; - u.f = 0.0; -#ifdef SNDRV_LITTLE_ENDIAN - return bswap_32(u.i); -#else - return u.i; -#endif - } - case SNDRV_PCM_FORMAT_FLOAT64_BE: - { - union { - double f; - u_int64_t i; - } u; - u.f = 0.0; -#ifdef SNDRV_LITTLE_ENDIAN - return bswap_64(u.i); -#else - return u.i; -#endif - } - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: - case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: - return 0; - case SNDRV_PCM_FORMAT_MU_LAW: - return 0x7f7f7f7f7f7f7f7fULL; - case SNDRV_PCM_FORMAT_A_LAW: - return 0x5555555555555555ULL; - case SNDRV_PCM_FORMAT_IMA_ADPCM: /* special case */ - case SNDRV_PCM_FORMAT_MPEG: - case SNDRV_PCM_FORMAT_GSM: - case SNDRV_PCM_FORMAT_SPECIAL: - return 0; - default: - return -EINVAL; - } - return 0; -} - -u_int32_t snd_pcm_format_silence_32(snd_pcm_format_t format) -{ - return (u_int32_t)snd_pcm_format_silence_64(format); -} - -u_int16_t snd_pcm_format_silence_16(snd_pcm_format_t format) -{ - return (u_int16_t)snd_pcm_format_silence_64(format); -} - -u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) -{ - return (u_int8_t)snd_pcm_format_silence_64(format); + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) + return NULL; + if (! pcm_formats[format].phys) + return NULL; + return pcm_formats[format].silence; } /** @@ -531,99 +358,73 @@ u_int8_t snd_pcm_format_silence(snd_pcm_ */ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) { + int width; + unsigned char *dst, *pat; + + if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) + return -EINVAL; if (samples == 0) return 0; - switch (snd_pcm_format_width(format)) { - case 4: { - u_int8_t silence = snd_pcm_format_silence_64(format); - unsigned int samples1; - if (samples % 2 != 0) - return -EINVAL; - samples1 = samples / 2; - memset(data, silence, samples1); - break; + width = pcm_formats[format].phys; /* physical width */ + pat = pcm_formats[format].silence; + if (! width) + return -EINVAL; + /* signed or 1 byte data */ + if (pcm_formats[format].signd == 1 || width <= 8) { + unsigned int bytes = samples * width / 8; + memset(data, *pat, bytes); + return 0; } - case 8: { - u_int8_t silence = snd_pcm_format_silence_64(format); - memset(data, silence, samples); - break; + /* non-zero samples, fill using a loop */ + width /= 8; + dst = data; +#if 0 + while (samples--) { + memcpy(dst, pat, width); + dst += width; } - case 16: { - u_int16_t silence = snd_pcm_format_silence_64(format); - if (! silence) - memset(data, 0, samples * 2); - else { - u_int16_t *data16 = data; - while (samples-- > 0) - *data16++ = silence; +#else + /* a bit optimization for constant width */ + switch (width) { + case 2: + while (samples--) { + memcpy(dst, pat, 2); + dst += 2; } break; - } - case 24: { - u_int32_t silence = snd_pcm_format_silence_64(format); - if (! silence) - memset(data, 0, samples * 3); - else { - while (samples-- > 0) { - u_int8_t *data8 = data; -#ifdef SNDRV_LITTLE_ENDIAN - *data8++ = silence >> 0; - *data8++ = silence >> 8; - *data8++ = silence >> 16; -#else - *data8++ = silence >> 16; - *data8++ = silence >> 8; - *data8++ = silence >> 0; -#endif - } + case 3: + while (samples--) { + memcpy(dst, pat, 3); + dst += 3; } break; - } - case 32: { - u_int32_t silence = snd_pcm_format_silence_64(format); - if (! silence) - memset(data, 0, samples * 4); - else { - u_int32_t *data32 = data; - while (samples-- > 0) - *data32++ = silence; + case 4: + while (samples--) { + memcpy(dst, pat, 4); + dst += 4; } break; - } - case 64: { - u_int64_t silence = snd_pcm_format_silence_64(format); - if (! silence) - memset(data, 0, samples * 8); - else { - u_int64_t *data64 = data; - while (samples-- > 0) - *data64++ = silence; + case 8: + while (samples--) { + memcpy(dst, pat, 8); + dst += 8; } break; } - default: - return -EINVAL; - } +#endif return 0; } -static int linear_formats[4*2*2] = { - SNDRV_PCM_FORMAT_S8, - SNDRV_PCM_FORMAT_S8, - SNDRV_PCM_FORMAT_U8, - SNDRV_PCM_FORMAT_U8, - SNDRV_PCM_FORMAT_S16_LE, - SNDRV_PCM_FORMAT_S16_BE, - SNDRV_PCM_FORMAT_U16_LE, - SNDRV_PCM_FORMAT_U16_BE, - SNDRV_PCM_FORMAT_S24_LE, - SNDRV_PCM_FORMAT_S24_BE, - SNDRV_PCM_FORMAT_U24_LE, - SNDRV_PCM_FORMAT_U24_BE, - SNDRV_PCM_FORMAT_S32_LE, - SNDRV_PCM_FORMAT_S32_BE, - SNDRV_PCM_FORMAT_U32_LE, - SNDRV_PCM_FORMAT_U32_BE +/* [width][unsigned][bigendian] */ +static int linear_formats[4][2][2] = { + {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, + { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}}, + {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE}, + {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}}, + {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE}, + {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}}, + {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE}, + {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}} }; /** @@ -636,23 +437,12 @@ static int linear_formats[4*2*2] = { */ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian) { - switch (width) { - case 8: - width = 0; - break; - case 16: - width = 1; - break; - case 24: - width = 2; - break; - case 32: - width = 3; - break; - default: + if (width & 7) return SND_PCM_FORMAT_UNKNOWN; - } - return snd_int_to_enum(((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian]); + width = (width / 8) - 1; + if (width < 0 || width >= 4) + return SND_PCM_FORMAT_UNKNOWN; + return linear_formats[width][!!unsignd][!!big_endian]; } /** --- linux-2.6.8-rc1/sound/core/pcm_native.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/pcm_native.c 2004-07-13 17:09:19.000000000 -0700 @@ -304,13 +304,25 @@ int snd_pcm_hw_refine(snd_pcm_substream_ static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) { - snd_pcm_hw_params_t params; + snd_pcm_hw_params_t *params; int err; - if (copy_from_user(¶ms, _params, sizeof(params))) - return -EFAULT; - err = snd_pcm_hw_refine(substream, ¶ms); - if (copy_to_user(_params, ¶ms, sizeof(params))) - return -EFAULT; + + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto out; + } + if (copy_from_user(params, _params, sizeof(*params))) { + err = -EFAULT; + goto out; + } + err = snd_pcm_hw_refine(substream, params); + if (copy_to_user(_params, params, sizeof(*params))) { + if (!err) + err = -EFAULT; + } +out: + kfree(params); return err; } @@ -408,13 +420,25 @@ static int snd_pcm_hw_params(snd_pcm_sub static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) { - snd_pcm_hw_params_t params; + snd_pcm_hw_params_t *params; int err; - if (copy_from_user(¶ms, _params, sizeof(params))) - return -EFAULT; - err = snd_pcm_hw_params(substream, ¶ms); - if (copy_to_user(_params, ¶ms, sizeof(params))) - return -EFAULT; + + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto out; + } + if (copy_from_user(params, _params, sizeof(*params))) { + err = -EFAULT; + goto out; + } + err = snd_pcm_hw_params(substream, params); + if (copy_to_user(_params, params, sizeof(*params))) { + if (!err) + err = -EFAULT; + } +out: + kfree(params); return err; } @@ -1503,7 +1527,7 @@ static int snd_pcm_link(snd_pcm_substrea file = snd_pcm_file_fd(fd); if (!file) return -EBADFD; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream1 = pcm_file->substream; write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state != substream1->runtime->status->state) { @@ -1923,7 +1947,7 @@ static int snd_pcm_release_file(snd_pcm_ substream->ffile = NULL; snd_pcm_remove_file(str, pcm_file); snd_pcm_release_substream(substream); - snd_magic_kfree(pcm_file); + kfree(pcm_file); return 0; } @@ -1940,13 +1964,13 @@ static int snd_pcm_open_file(struct file snd_assert(rpcm_file != NULL, return -EINVAL); *rpcm_file = NULL; - pcm_file = snd_magic_kcalloc(snd_pcm_file_t, 0, GFP_KERNEL); + pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL); if (pcm_file == NULL) { return -ENOMEM; } if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) { - snd_magic_kfree(pcm_file); + kfree(pcm_file); return err; } @@ -2050,7 +2074,7 @@ int snd_pcm_release(struct inode *inode, snd_pcm_substream_t *substream; snd_pcm_file_t *pcm_file; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); snd_assert(!atomic_read(&substream->runtime->mmap_count), ); @@ -2617,7 +2641,7 @@ static int snd_pcm_playback_ioctl(struct { snd_pcm_file_t *pcm_file; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; @@ -2630,7 +2654,7 @@ static int snd_pcm_capture_ioctl(struct { snd_pcm_file_t *pcm_file; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; @@ -2682,7 +2706,7 @@ static ssize_t snd_pcm_read(struct file snd_pcm_runtime_t *runtime; snd_pcm_sframes_t result; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); runtime = substream->runtime; @@ -2704,7 +2728,7 @@ static ssize_t snd_pcm_write(struct file snd_pcm_runtime_t *runtime; snd_pcm_sframes_t result; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, result = -ENXIO; goto end); runtime = substream->runtime; @@ -2736,7 +2760,7 @@ static ssize_t snd_pcm_readv(struct file void __user **bufs; snd_pcm_uframes_t frames; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); runtime = substream->runtime; @@ -2770,7 +2794,7 @@ static ssize_t snd_pcm_writev(struct fil void __user **bufs; snd_pcm_uframes_t frames; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, result = -ENXIO; goto end); runtime = substream->runtime; @@ -2805,7 +2829,7 @@ unsigned int snd_pcm_playback_poll(struc unsigned int mask; snd_pcm_uframes_t avail; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return 0); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); @@ -2843,7 +2867,7 @@ unsigned int snd_pcm_capture_poll(struct unsigned int mask; snd_pcm_uframes_t avail; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return 0); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); @@ -3009,6 +3033,12 @@ static struct vm_operations_struct snd_p .nopage = snd_pcm_mmap_data_nopage, }; +static struct vm_operations_struct snd_pcm_vm_ops_data_mmio = +{ + .open = snd_pcm_mmap_data_open, + .close = snd_pcm_mmap_data_close, +}; + int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file, struct vm_area_struct *area) { @@ -3044,6 +3074,14 @@ int snd_pcm_mmap_data(snd_pcm_substream_ area->vm_ops = &snd_pcm_vm_ops_data; area->vm_private_data = substream; area->vm_flags |= VM_RESERVED; + if (runtime->hw.info & SNDRV_PCM_INFO_MMAP_IOMEM) { + area->vm_ops = &snd_pcm_vm_ops_data_mmio; + area->vm_flags |= VM_IO; + if (io_remap_page_range(area, area->vm_start, + runtime->dma_addr + offset, + size, area->vm_page_prot)) + return -EAGAIN; + } atomic_inc(&runtime->mmap_count); return 0; } @@ -3054,7 +3092,7 @@ static int snd_pcm_mmap(struct file *fil snd_pcm_substream_t *substream; unsigned long offset; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); @@ -3077,7 +3115,7 @@ static int snd_pcm_fasync(int fd, struct snd_pcm_runtime_t *runtime; int err; - pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); + pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); runtime = substream->runtime; @@ -3133,31 +3171,68 @@ static void snd_pcm_hw_convert_to_old_pa static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) { - snd_pcm_hw_params_t params; - struct sndrv_pcm_hw_params_old oparams; + snd_pcm_hw_params_t *params; + struct sndrv_pcm_hw_params_old *oparams = NULL; int err; - if (copy_from_user(&oparams, _oparams, sizeof(oparams))) - return -EFAULT; - snd_pcm_hw_convert_from_old_params(¶ms, &oparams); - err = snd_pcm_hw_refine(substream, ¶ms); - snd_pcm_hw_convert_to_old_params(&oparams, ¶ms); - if (copy_to_user(_oparams, &oparams, sizeof(oparams))) - return -EFAULT; + + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto out; + } + oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); + if (!oparams) { + err = -ENOMEM; + goto out; + } + + if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { + err = -EFAULT; + goto out; + } + snd_pcm_hw_convert_from_old_params(params, oparams); + err = snd_pcm_hw_refine(substream, params); + snd_pcm_hw_convert_to_old_params(oparams, params); + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { + if (!err) + err = -EFAULT; + } +out: + kfree(params); + kfree(oparams); return err; } static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) { - snd_pcm_hw_params_t params; - struct sndrv_pcm_hw_params_old oparams; + snd_pcm_hw_params_t *params; + struct sndrv_pcm_hw_params_old *oparams = NULL; int err; - if (copy_from_user(&oparams, _oparams, sizeof(oparams))) - return -EFAULT; - snd_pcm_hw_convert_from_old_params(¶ms, &oparams); - err = snd_pcm_hw_params(substream, ¶ms); - snd_pcm_hw_convert_to_old_params(&oparams, ¶ms); - if (copy_to_user(_oparams, &oparams, sizeof(oparams))) - return -EFAULT; + + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + err = -ENOMEM; + goto out; + } + oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); + if (!oparams) { + err = -ENOMEM; + goto out; + } + if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { + err = -EFAULT; + goto out; + } + snd_pcm_hw_convert_from_old_params(params, oparams); + err = snd_pcm_hw_params(substream, params); + snd_pcm_hw_convert_to_old_params(oparams, params); + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { + if (!err) + err = -EFAULT; + } +out: + kfree(params); + kfree(oparams); return err; } --- linux-2.6.8-rc1/sound/core/pcm_timer.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/core/pcm_timer.c 2004-07-13 17:09:19.000000000 -0700 @@ -25,8 +25,6 @@ #include #include -#define chip_t snd_pcm_substream_t - /* * Timer functions */ @@ -49,7 +47,7 @@ static unsigned long gcd(unsigned long a void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream) { - unsigned long rate, mult, fsize, l; + unsigned long rate, mult, fsize, l, post; snd_pcm_runtime_t *runtime = substream->runtime; mult = 1000000000; @@ -63,23 +61,24 @@ void snd_pcm_timer_resolution_change(snd l = gcd(rate, fsize); rate /= l; fsize /= l; + post = 1; while ((mult * fsize) / fsize != mult) { mult /= 2; - rate /= 2; + post *= 2; } if (rate == 0) { snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size); runtime->timer_resolution = -1; return; } - runtime->timer_resolution = mult * fsize / rate; + runtime->timer_resolution = (mult * fsize / rate) * post; } static unsigned long snd_pcm_timer_resolution(snd_timer_t * timer) { snd_pcm_substream_t * substream; - substream = snd_magic_cast(snd_pcm_substream_t, timer->private_data, return -ENXIO); + substream = timer->private_data; return substream->runtime ? substream->runtime->timer_resolution : 0; } @@ -123,7 +122,7 @@ static struct _snd_timer_hardware snd_pc static void snd_pcm_timer_free(snd_timer_t *timer) { - snd_pcm_substream_t *substream = snd_magic_cast(snd_pcm_substream_t, timer->private_data, return); + snd_pcm_substream_t *substream = timer->private_data; substream->timer = NULL; } --- linux-2.6.8-rc1/sound/core/rawmidi.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/rawmidi.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,10 +44,8 @@ static int amidi_map[SNDRV_CARDS] = {[0 static int boot_devs; module_param_array(midi_map, int, boot_devs, 0444); MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device."); -MODULE_PARM_SYNTAX(midi_map, "default:0,skill:advanced"); module_param_array(amidi_map, int, boot_devs, 0444); MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device."); -MODULE_PARM_SYNTAX(amidi_map, "default:1,skill:advanced"); #endif /* CONFIG_SND_OSSEMUL */ static int snd_rawmidi_free(snd_rawmidi_t *rawmidi); @@ -269,7 +267,7 @@ int snd_rawmidi_kernel_open(int cardnum, list2 = list2->next; } if (mode & SNDRV_RAWMIDI_LFLG_INPUT) { - input = snd_kcalloc(sizeof(snd_rawmidi_runtime_t), GFP_KERNEL); + input = kcalloc(1, sizeof(*input), GFP_KERNEL); if (input == NULL) { err = -ENOMEM; goto __error; @@ -291,7 +289,7 @@ int snd_rawmidi_kernel_open(int cardnum, if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { if (soutput->opened) goto __skip_output; - output = snd_kcalloc(sizeof(snd_rawmidi_runtime_t), GFP_KERNEL); + output = kcalloc(1, sizeof(*output), GFP_KERNEL); if (output == NULL) { err = -ENOMEM; goto __error; @@ -398,7 +396,7 @@ static int snd_rawmidi_open(struct inode if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */ fflags |= SNDRV_RAWMIDI_LFLG_APPEND; fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; - rawmidi_file = snd_magic_kmalloc(snd_rawmidi_file_t, 0, GFP_KERNEL); + rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); if (rawmidi_file == NULL) { snd_card_file_remove(card, file); return -ENOMEM; @@ -447,7 +445,7 @@ static int snd_rawmidi_open(struct inode file->private_data = rawmidi_file; } else { snd_card_file_remove(card, file); - snd_magic_kfree(rawmidi_file); + kfree(rawmidi_file); } up(&rmidi->open_mutex); return err; @@ -512,11 +510,11 @@ static int snd_rawmidi_release(struct in snd_rawmidi_t *rmidi; int err; - rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); + rfile = file->private_data; err = snd_rawmidi_kernel_release(rfile); rmidi = rfile->rmidi; wake_up(&rmidi->open_wait); - snd_magic_kfree(rfile); + kfree(rfile); snd_card_file_remove(rmidi->card, file); return err; } @@ -681,7 +679,7 @@ static int snd_rawmidi_ioctl(struct inod snd_rawmidi_file_t *rfile; void __user *argp = (void __user *)arg; - rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); + rfile = file->private_data; if (((cmd >> 8) & 0xff) != 'W') return -ENOTTY; switch (cmd) { @@ -944,7 +942,7 @@ static ssize_t snd_rawmidi_read(struct f snd_rawmidi_substream_t *substream; snd_rawmidi_runtime_t *runtime; - rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); + rfile = file->private_data; substream = rfile->input; if (substream == NULL) return -EIO; @@ -1176,7 +1174,7 @@ static ssize_t snd_rawmidi_write(struct snd_rawmidi_runtime_t *runtime; snd_rawmidi_substream_t *substream; - rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO); + rfile = file->private_data; substream = rfile->output; runtime = substream->runtime; /* we cannot put an atomic message to our buffer */ @@ -1241,7 +1239,7 @@ static unsigned int snd_rawmidi_poll(str snd_rawmidi_runtime_t *runtime; unsigned int mask; - rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return 0); + rfile = file->private_data; if (rfile->input != NULL) { runtime = rfile->input->runtime; runtime->trigger = 1; @@ -1276,7 +1274,7 @@ static void snd_rawmidi_proc_info_read(s snd_rawmidi_runtime_t *runtime; struct list_head *list; - rmidi = snd_magic_cast(snd_rawmidi_t, entry->private_data, return); + rmidi = entry->private_data; snd_iprintf(buffer, "%s\n\n", rmidi->name); down(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { @@ -1353,7 +1351,7 @@ static int snd_rawmidi_alloc_substreams( INIT_LIST_HEAD(&stream->substreams); for (idx = 0; idx < count; idx++) { - substream = snd_kcalloc(sizeof(snd_rawmidi_substream_t), GFP_KERNEL); + substream = kcalloc(1, sizeof(*substream), GFP_KERNEL); if (substream == NULL) return -ENOMEM; substream->stream = direction; @@ -1396,7 +1394,7 @@ int snd_rawmidi_new(snd_card_t * card, c snd_assert(rrawmidi != NULL, return -EINVAL); *rrawmidi = NULL; snd_assert(card != NULL, return -ENXIO); - rmidi = snd_magic_kcalloc(snd_rawmidi_t, 0, GFP_KERNEL); + rmidi = kcalloc(1, sizeof(*rmidi), GFP_KERNEL); if (rmidi == NULL) return -ENOMEM; rmidi->card = card; @@ -1439,20 +1437,20 @@ static int snd_rawmidi_free(snd_rawmidi_ snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); if (rmidi->private_free) rmidi->private_free(rmidi); - snd_magic_kfree(rmidi); + kfree(rmidi); return 0; } static int snd_rawmidi_dev_free(snd_device_t *device) { - snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO); + snd_rawmidi_t *rmidi = device->device_data; return snd_rawmidi_free(rmidi); } #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) static void snd_rawmidi_dev_seq_free(snd_seq_device_t *device) { - snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->private_data, return); + snd_rawmidi_t *rmidi = device->private_data; rmidi->seq_dev = NULL; } #endif @@ -1462,7 +1460,7 @@ static int snd_rawmidi_dev_register(snd_ int idx, err; snd_info_entry_t *entry; char name[16]; - snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO); + snd_rawmidi_t *rmidi = device->device_data; if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; @@ -1539,7 +1537,7 @@ static int snd_rawmidi_dev_register(snd_ static int snd_rawmidi_dev_disconnect(snd_device_t *device) { - snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO); + snd_rawmidi_t *rmidi = device->device_data; int idx; down(®ister_mutex); @@ -1552,7 +1550,7 @@ static int snd_rawmidi_dev_disconnect(sn static int snd_rawmidi_dev_unregister(snd_device_t *device) { int idx; - snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO); + snd_rawmidi_t *rmidi = device->device_data; snd_assert(rmidi != NULL, return -ENXIO); down(®ister_mutex); --- linux-2.6.8-rc1/sound/core/seq/instr/ainstr_fm.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/instr/ainstr_fm.c 2004-07-13 17:09:19.000000000 -0700 @@ -29,8 +29,6 @@ MODULE_AUTHOR("Uros Bizjak "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); char *snd_seq_fm_id = SNDRV_SEQ_INSTR_ID_OPL2_3; --- linux-2.6.8-rc1/sound/core/seq/instr/ainstr_gf1.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/instr/ainstr_gf1.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); char *snd_seq_gf1_id = SNDRV_SEQ_INSTR_ID_GUS_PATCH; @@ -64,7 +62,7 @@ static int snd_seq_gf1_copy_wave_from_st return -EFAULT; *data += sizeof(xp); *len -= sizeof(xp); - wp = (gf1_wave_t *)snd_kcalloc(sizeof(*wp), gfp_mask); + wp = kcalloc(1, sizeof(*wp), gfp_mask); if (wp == NULL) return -ENOMEM; wp->share_id[0] = le32_to_cpu(xp.share_id[0]); --- linux-2.6.8-rc1/sound/core/seq/instr/ainstr_iw.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/instr/ainstr_iw.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); char *snd_seq_iwffff_id = SNDRV_SEQ_INSTR_ID_INTERWAVE; @@ -96,7 +94,7 @@ static int snd_seq_iwffff_copy_env_from_ points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16); if (points_size > *len) return -EINVAL; - rp = (iwffff_env_record_t *)snd_kcalloc(sizeof(*rp) + points_size, gfp_mask); + rp = kcalloc(1, sizeof(*rp) + points_size, gfp_mask); if (rp == NULL) return -ENOMEM; rp->nattack = le16_to_cpu(rx.nattack); @@ -142,7 +140,7 @@ static int snd_seq_iwffff_copy_wave_from return -EFAULT; *data += sizeof(xp); *len -= sizeof(xp); - wp = (iwffff_wave_t *)snd_kcalloc(sizeof(*wp), gfp_mask); + wp = kcalloc(1, sizeof(*wp), gfp_mask); if (wp == NULL) return -ENOMEM; wp->share_id[0] = le32_to_cpu(xp.share_id[0]); @@ -275,7 +273,7 @@ static int snd_seq_iwffff_put(void *priv snd_seq_iwffff_instr_free(ops, ip, atomic); return -EINVAL; } - lp = (iwffff_layer_t *)snd_kcalloc(sizeof(*lp), gfp_mask); + lp = kcalloc(1, sizeof(*lp), gfp_mask); if (lp == NULL) { snd_seq_iwffff_instr_free(ops, ip, atomic); return -ENOMEM; --- linux-2.6.8-rc1/sound/core/seq/instr/ainstr_simple.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/instr/ainstr_simple.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); char *snd_seq_simple_id = SNDRV_SEQ_INSTR_ID_SIMPLE; --- linux-2.6.8-rc1/sound/core/seq/instr/Makefile 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/seq/instr/Makefile 2004-07-13 17:09:19.000000000 -0700 @@ -17,35 +17,7 @@ snd-ainstr-iw-objs := ainstr_iw.o sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) # Toplevel Module Dependency -obj-$(call sequencer,$(CONFIG_SND_ALS100)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_DT019X)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_AD1816A)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_CS4232)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_CS4236)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_ES1688)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o -obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o -obj-$(call sequencer,$(CONFIG_SND_GUSEXTREME)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE_STB)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o -obj-$(call sequencer,$(CONFIG_SND_OPTI92X_AD1848)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_OPTI92X_CS4231)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_OPTI93X)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_SB8)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_SB16)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_WAVEFRONT)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_ALS4000)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_CMIPCI)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_CS4281)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_ES1938)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_FM801)) += snd-ainstr-fm.o -obj-$(call sequencer,$(CONFIG_SND_SONICVIBES)) += snd-ainstr-fm.o +obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o +obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o +obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o -obj-$(call sequencer,$(CONFIG_SND_YMFPCI)) += snd-ainstr-fm.o - -obj-m := $(sort $(obj-m)) --- linux-2.6.8-rc1/sound/core/seq/Makefile 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/core/seq/Makefile 2004-07-13 17:09:19.000000000 -0700 @@ -19,9 +19,6 @@ snd-seq-instr-objs := seq_instr.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o -RAWMIDI_OBJS = snd-seq-midi.o snd-seq-midi-event.o -OPL3_OBJS = snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o - # # this function returns: # "m" - CONFIG_SND_SEQUENCER is m @@ -38,53 +35,8 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-d # Toplevel Module Dependency obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(call sequencer,$(CONFIG_SND_SERIAL_U16550)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_MTPAV)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_MPU401)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ALS100)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_DT019X)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_AD1816A)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CS4231)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CS4232)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CS4236)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ES1688)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_GUSEXTREME)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE_STB)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_OPTI92X_AD1848)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_OPTI92X_CS4231)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_OPTI93X)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_SB8)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_SB16)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) snd-seq-virmidi.o -obj-$(call sequencer,$(CONFIG_SND_ES968)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_WAVEFRONT)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_SSCAPE)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ALS4000)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CMIPCI)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CS4281)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ENS1370)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ENS1371)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ES1938)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ES1968)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_FM801)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ICE1712)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ICE1724)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_INTEL8X0)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_SONICVIBES)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_VIA82XX)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_ALI5451)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_CS46XX)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += $(RAWMIDI_OBJS) snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += $(RAWMIDI_OBJS) snd-seq-midi-emul.o snd-seq-instr.o -obj-$(call sequencer,$(CONFIG_SND_YMFPCI)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) -obj-$(call sequencer,$(CONFIG_SND_USB_AUDIO)) += $(RAWMIDI_OBJS) -obj-$(call sequencer,$(CONFIG_SND_HDSP)) += $(RAWMIDI_OBJS) - -obj-m := $(sort $(obj-m)) +obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o +obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss.c 2004-07-13 17:09:19.000000000 -0700 @@ -35,7 +35,6 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("OSS-compatible sequencer module"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); /* Takashi says this is really only for sound-service-0-, but this is OK. */ MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER); MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC); --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_init.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss_init.c 2004-07-13 17:09:19.000000000 -0700 @@ -183,7 +183,7 @@ snd_seq_oss_open(struct file *file, int int i, rc; seq_oss_devinfo_t *dp; - if ((dp = snd_kcalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { + if ((dp = kcalloc(1, sizeof(*dp), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc device info\n"); return -ENOMEM; } @@ -211,7 +211,7 @@ snd_seq_oss_open(struct file *file, int snd_seq_oss_midi_setup(dp); if (dp->synth_opened == 0 && dp->max_mididev == 0) { - snd_printk(KERN_ERR "no device found\n"); + /* snd_printk(KERN_ERR "no device found\n"); */ rc = -ENODEV; goto _error; } --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_ioctl.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss_ioctl.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,16 +28,54 @@ #include "seq_oss_midi.h" #include "seq_oss_event.h" +static int snd_seq_oss_synth_info_user(seq_oss_devinfo_t *dp, void __user *arg) +{ + struct synth_info info; + + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + if (snd_seq_oss_synth_make_info(dp, info.device, &info) < 0) + return -EINVAL; + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int snd_seq_oss_midi_info_user(seq_oss_devinfo_t *dp, void __user *arg) +{ + struct midi_info info; + + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + if (snd_seq_oss_midi_make_info(dp, info.device, &info) < 0) + return -EINVAL; + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int snd_seq_oss_oob_user(seq_oss_devinfo_t *dp, void __user *arg) +{ + unsigned char ev[8]; + snd_seq_event_t tmpev; + + if (copy_from_user(ev, arg, 8)) + return -EFAULT; + memset(&tmpev, 0, sizeof(tmpev)); + snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client); + tmpev.time.tick = 0; + if (! snd_seq_oss_process_event(dp, (evrec_t*)ev, &tmpev)) { + snd_seq_oss_dispatch(dp, &tmpev, 0, 0); + } + return 0; +} + int snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg) { int dev, val; - struct synth_info inf; - struct midi_info minf; - unsigned char ev[8]; void __user *arg = (void __user *)carg; int __user *p = arg; - snd_seq_event_t tmpev; switch (cmd) { case SNDCTL_TMR_TIMEBASE: @@ -124,35 +162,15 @@ snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, case SNDCTL_SYNTH_INFO: case SNDCTL_SYNTH_ID: debug_printk(("synth info\n")); - if (copy_from_user(&inf, arg, sizeof(inf))) - return -EFAULT; - if (snd_seq_oss_synth_make_info(dp, inf.device, &inf) < 0) - return -EINVAL; - if (copy_to_user(arg, &inf, sizeof(inf))) - return -EFAULT; - return 0; + return snd_seq_oss_synth_info_user(dp, arg); case SNDCTL_SEQ_OUTOFBAND: - debug_printk(("out of bound\n")); - if (copy_from_user(ev, arg, 8)) - return -EFAULT; - memset(&tmpev, 0, sizeof(tmpev)); - snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client); - tmpev.time.tick = 0; - if (! snd_seq_oss_process_event(dp, (evrec_t*)ev, &tmpev)) { - snd_seq_oss_dispatch(dp, &tmpev, 0, 0); - } - return 0; + debug_printk(("out of band\n")); + return snd_seq_oss_oob_user(dp, arg); case SNDCTL_MIDI_INFO: debug_printk(("midi info\n")); - if (copy_from_user(&minf, arg, sizeof(minf))) - return -EFAULT; - if (snd_seq_oss_midi_make_info(dp, minf.device, &minf) < 0) - return -EINVAL; - if (copy_to_user(arg, &minf, sizeof(minf))) - return -EFAULT; - return 0; + return snd_seq_oss_midi_info_user(dp, arg); case SNDCTL_SEQ_THRESHOLD: debug_printk(("threshold\n")); --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_midi.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/core/seq/oss/seq_oss_midi.c 2004-07-13 17:09:19.000000000 -0700 @@ -171,7 +171,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_ /* * allocate midi info record */ - if ((mdev = snd_kcalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { + if ((mdev = kcalloc(1, sizeof(*mdev), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc midi info\n"); return -ENOMEM; } --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_readq.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss_readq.c 2004-07-13 17:09:19.000000000 -0700 @@ -45,12 +45,12 @@ snd_seq_oss_readq_new(seq_oss_devinfo_t { seq_oss_readq_t *q; - if ((q = snd_kcalloc(sizeof(*q), GFP_KERNEL)) == NULL) { + if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc read queue\n"); return NULL; } - if ((q->q = snd_kcalloc(sizeof(evrec_t) * maxlen, GFP_KERNEL)) == NULL) { + if ((q->q = kcalloc(maxlen, sizeof(evrec_t), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc read queue buffer\n"); kfree(q); return NULL; --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_synth.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/core/seq/oss/seq_oss_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -103,7 +103,7 @@ snd_seq_oss_synth_register(snd_seq_devic snd_seq_oss_reg_t *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); unsigned long flags; - if ((rec = snd_kcalloc(sizeof(*rec), GFP_KERNEL)) == NULL) { + if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc synth info\n"); return -ENOMEM; } @@ -244,7 +244,9 @@ snd_seq_oss_synth_setup(seq_oss_devinfo_ } info->nr_voices = rec->nr_voices; if (info->nr_voices > 0) { - info->ch = snd_kcalloc(sizeof(seq_oss_chinfo_t) * info->nr_voices, GFP_KERNEL); + info->ch = kcalloc(info->nr_voices, sizeof(seq_oss_chinfo_t), GFP_KERNEL); + if (!info->ch) + BUG(); reset_channels(info); } debug_printk(("synth %d assigned\n", i)); @@ -505,7 +507,7 @@ snd_seq_oss_synth_sysex(seq_oss_devinfo_ sysex = dp->synths[dev].sysex; if (sysex == NULL) { - sysex = snd_kcalloc(sizeof(*sysex), GFP_KERNEL); + sysex = kcalloc(1, sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; dp->synths[dev].sysex = sysex; --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_timer.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss_timer.c 2004-07-13 17:09:19.000000000 -0700 @@ -46,7 +46,7 @@ snd_seq_oss_timer_new(seq_oss_devinfo_t { seq_oss_timer_t *rec; - rec = snd_kcalloc(sizeof(*rec), GFP_KERNEL); + rec = kcalloc(1, sizeof(*rec), GFP_KERNEL); if (rec == NULL) return NULL; @@ -168,7 +168,7 @@ snd_seq_oss_timer_start(seq_oss_timer_t tmprec.queue = dp->queue; tmprec.ppq = timer->ppq; tmprec.tempo = timer->tempo; - snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, &tmprec); + snd_seq_set_queue_tempo(dp->cseq, &tmprec); send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0); timer->running = 1; --- linux-2.6.8-rc1/sound/core/seq/oss/seq_oss_writeq.c 2003-06-14 12:18:30.000000000 -0700 +++ 25/sound/core/seq/oss/seq_oss_writeq.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,7 +37,7 @@ snd_seq_oss_writeq_new(seq_oss_devinfo_t seq_oss_writeq_t *q; snd_seq_client_pool_t pool; - if ((q = snd_kcalloc(sizeof(*q), GFP_KERNEL)) == NULL) + if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL) return NULL; q->dp = dp; q->maxlen = maxlen; --- linux-2.6.8-rc1/sound/core/seq/seq.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/seq.c 2004-07-13 17:09:19.000000000 -0700 @@ -50,8 +50,6 @@ int seq_default_timer_resolution = 0; /* MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); static int boot_devs; module_param_array(seq_client_load, int, boot_devs, 0444); @@ -133,6 +131,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_enqu EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); EXPORT_SYMBOL(snd_seq_kernel_client_ctl); EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); +EXPORT_SYMBOL(snd_seq_set_queue_tempo); /* seq_memory.c */ EXPORT_SYMBOL(snd_seq_expand_var_event); EXPORT_SYMBOL(snd_seq_dump_var_event); --- linux-2.6.8-rc1/sound/core/seq/seq_clientmgr.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/seq_clientmgr.c 2004-07-13 17:09:19.000000000 -0700 @@ -202,7 +202,7 @@ static client_t *seq_create_client1(int client_t *client; /* init client data */ - client = snd_kcalloc(sizeof(client_t), GFP_KERNEL); + client = kcalloc(1, sizeof(*client), GFP_KERNEL); if (client == NULL) return NULL; client->pool = snd_seq_pool_new(poolsize); @@ -1694,6 +1694,13 @@ static int snd_seq_ioctl_get_queue_tempo /* SET_QUEUE_TEMPO ioctl() */ +int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo) +{ + if (!snd_seq_queue_check_access(tempo->queue, client)) + return -EPERM; + return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); +} + static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg) { int result; @@ -1702,15 +1709,8 @@ static int snd_seq_ioctl_set_queue_tempo if (copy_from_user(&tempo, arg, sizeof(tempo))) return -EFAULT; - if (snd_seq_queue_check_access(tempo.queue, client->number)) { - result = snd_seq_queue_timer_set_tempo(tempo.queue, client->number, &tempo); - if (result < 0) - return result; - } else { - return -EPERM; - } - - return 0; + result = snd_seq_set_queue_tempo(client->number, &tempo); + return result < 0 ? result : 0; } --- linux-2.6.8-rc1/sound/core/seq/seq_device.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/seq/seq_device.c 2004-07-13 17:09:19.000000000 -0700 @@ -48,8 +48,6 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); /* * driver list @@ -181,7 +179,7 @@ int snd_seq_device_new(snd_card_t *card, if (ops == NULL) return -ENOMEM; - dev = snd_magic_kcalloc(snd_seq_device_t, sizeof(*dev) + argsize, GFP_KERNEL); + dev = kcalloc(1, sizeof(*dev)*2 + argsize, GFP_KERNEL); if (dev == NULL) { unlock_driver(ops); return -ENOMEM; @@ -235,7 +233,7 @@ static int snd_seq_device_free(snd_seq_d free_device(dev, ops); if (dev->private_free) dev->private_free(dev); - snd_magic_kfree(dev); + kfree(dev); unlock_driver(ops); @@ -244,7 +242,7 @@ static int snd_seq_device_free(snd_seq_d static int snd_seq_device_dev_free(snd_device_t *device) { - snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO); + snd_seq_device_t *dev = device->device_data; return snd_seq_device_free(dev); } @@ -253,7 +251,7 @@ static int snd_seq_device_dev_free(snd_d */ static int snd_seq_device_dev_register(snd_device_t *device) { - snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO); + snd_seq_device_t *dev = device->device_data; ops_list_t *ops; ops = find_driver(dev->id, 0); @@ -275,7 +273,7 @@ static int snd_seq_device_dev_register(s */ static int snd_seq_device_dev_disconnect(snd_device_t *device) { - snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO); + snd_seq_device_t *dev = device->device_data; ops_list_t *ops; ops = find_driver(dev->id, 0); @@ -293,7 +291,7 @@ static int snd_seq_device_dev_disconnect */ static int snd_seq_device_dev_unregister(snd_device_t *device) { - snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO); + snd_seq_device_t *dev = device->device_data; return snd_seq_device_free(dev); } --- linux-2.6.8-rc1/sound/core/seq/seq_dummy.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/seq_dummy.c 2004-07-13 17:09:19.000000000 -0700 @@ -63,8 +63,6 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ALSA sequencer MIDI-through client"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); static int ports = 1; static int duplex = 0; @@ -95,7 +93,7 @@ dummy_unuse(void *private_data, snd_seq_ int i; snd_seq_event_t ev; - p = snd_magic_cast(snd_seq_dummy_port_t, private_data, return -EINVAL); + p = private_data; memset(&ev, 0, sizeof(ev)); if (p->duplex) ev.source.port = p->connect; @@ -122,7 +120,7 @@ dummy_input(snd_seq_event_t *ev, int dir snd_seq_dummy_port_t *p; snd_seq_event_t tmpev; - p = snd_magic_cast(snd_seq_dummy_port_t, private_data, return -EINVAL); + p = private_data; if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM || ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR) return 0; /* ignore system messages */ @@ -150,8 +148,8 @@ dummy_free(void *private_data) { snd_seq_dummy_port_t *p; - p = snd_magic_cast(snd_seq_dummy_port_t, private_data, return); - snd_magic_kfree(p); + p = private_data; + kfree(p); } /* @@ -164,7 +162,7 @@ create_port(int idx, int type) snd_seq_port_callback_t pcb; snd_seq_dummy_port_t *rec; - if ((rec = snd_magic_kcalloc(snd_seq_dummy_port_t, 0, GFP_KERNEL)) == NULL) + if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL) return NULL; rec->client = my_client; @@ -190,7 +188,7 @@ create_port(int idx, int type) pcb.private_data = rec; pinfo.kernel = &pcb; if (snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo) < 0) { - snd_magic_kfree(rec); + kfree(rec); return NULL; } rec->port = pinfo.addr.port; --- linux-2.6.8-rc1/sound/core/seq/seq_fifo.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/core/seq/seq_fifo.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,7 +33,7 @@ fifo_t *snd_seq_fifo_new(int poolsize) { fifo_t *f; - f = snd_kcalloc(sizeof(fifo_t), GFP_KERNEL); + f = kcalloc(1, sizeof(*f), GFP_KERNEL); if (f == NULL) { snd_printd("malloc failed for snd_seq_fifo_new() \n"); return NULL; --- linux-2.6.8-rc1/sound/core/seq/seq_instr.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/sound/core/seq/seq_instr.c 2004-07-13 17:09:19.000000000 -0700 @@ -29,8 +29,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); static void snd_instr_lock_ops(snd_seq_kinstr_list_t *list) @@ -53,10 +51,7 @@ static void snd_instr_unlock_ops(snd_seq snd_seq_kcluster_t *snd_seq_cluster_new(int atomic) { - snd_seq_kcluster_t *cluster; - - cluster = (snd_seq_kcluster_t *) snd_kcalloc(sizeof(snd_seq_kcluster_t), atomic ? GFP_ATOMIC : GFP_KERNEL); - return cluster; + return kcalloc(1, sizeof(snd_seq_kcluster_t), atomic ? GFP_ATOMIC : GFP_KERNEL); } void snd_seq_cluster_free(snd_seq_kcluster_t *cluster, int atomic) @@ -70,7 +65,7 @@ snd_seq_kinstr_t *snd_seq_instr_new(int { snd_seq_kinstr_t *instr; - instr = (snd_seq_kinstr_t *) snd_kcalloc(sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); + instr = kcalloc(1, sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); if (instr == NULL) return NULL; instr->add_len = add_len; @@ -94,7 +89,7 @@ snd_seq_kinstr_list_t *snd_seq_instr_lis { snd_seq_kinstr_list_t *list; - list = (snd_seq_kinstr_list_t *) snd_kcalloc(sizeof(snd_seq_kinstr_list_t), GFP_KERNEL); + list = kcalloc(1, sizeof(snd_seq_kinstr_list_t), GFP_KERNEL); if (list == NULL) return NULL; spin_lock_init(&list->lock); --- linux-2.6.8-rc1/sound/core/seq/seq_memory.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/seq_memory.c 2004-07-13 17:09:19.000000000 -0700 @@ -453,7 +453,7 @@ pool_t *snd_seq_pool_new(int poolsize) pool_t *pool; /* create pool block */ - pool = snd_kcalloc(sizeof(pool_t), GFP_KERNEL); + pool = kcalloc(1, sizeof(*pool), GFP_KERNEL); if (pool == NULL) { snd_printd("seq: malloc failed for pool\n"); return NULL; --- linux-2.6.8-rc1/sound/core/seq/seq_midi.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/seq/seq_midi.c 2004-07-13 17:09:19.000000000 -0700 @@ -43,8 +43,6 @@ Possible options for midisynth module: MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); int output_buffer_size = PAGE_SIZE; module_param(output_buffer_size, int, 0644); MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes."); @@ -323,7 +321,7 @@ snd_seq_midisynth_register_port(snd_seq_ client = synths[card->number]; if (client == NULL) { newclient = 1; - client = snd_kcalloc(sizeof(seq_midisynth_client_t), GFP_KERNEL); + client = kcalloc(1, sizeof(*client), GFP_KERNEL); if (client == NULL) { up(®ister_mutex); return -ENOMEM; @@ -341,7 +339,7 @@ snd_seq_midisynth_register_port(snd_seq_ } else if (device == 0) set_client_name(client, card, &info); /* use the first device's name */ - msynth = snd_kcalloc(sizeof(seq_midisynth_t) * ports, GFP_KERNEL); + msynth = kcalloc(ports, sizeof(seq_midisynth_t), GFP_KERNEL); if (msynth == NULL) goto __nomem; --- linux-2.6.8-rc1/sound/core/seq/seq_midi_emul.c 2003-06-14 12:18:34.000000000 -0700 +++ 25/sound/core/seq/seq_midi_emul.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,8 +42,6 @@ MODULE_AUTHOR("Takashi Iwai / Steve Ratcliffe"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI emulation."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); /* Prototypes for static functions */ static void note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int vel); --- linux-2.6.8-rc1/sound/core/seq/seq_midi_event.c 2003-08-08 22:55:14.000000000 -0700 +++ 25/sound/core/seq/seq_midi_event.c 2004-07-13 17:09:19.000000000 -0700 @@ -118,7 +118,7 @@ int snd_midi_event_new(int bufsize, snd_ snd_midi_event_t *dev; *rdev = NULL; - dev = (snd_midi_event_t *)snd_kcalloc(sizeof(snd_midi_event_t), GFP_KERNEL); + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; if (bufsize > 0) { --- linux-2.6.8-rc1/sound/core/seq/seq_ports.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/seq/seq_ports.c 2004-07-13 17:09:19.000000000 -0700 @@ -141,7 +141,7 @@ client_port_t *snd_seq_create_port(clien } /* create a new port */ - new_port = snd_kcalloc(sizeof(client_port_t), GFP_KERNEL); + new_port = kcalloc(1, sizeof(*new_port), GFP_KERNEL); if (! new_port) { snd_printd("malloc failed for registering client port\n"); return NULL; /* failure, out of memory */ @@ -488,7 +488,7 @@ int snd_seq_port_connect(client_t *conne unsigned long flags; int exclusive; - subs = snd_kcalloc(sizeof(*subs), GFP_KERNEL); + subs = kcalloc(1, sizeof(*subs), GFP_KERNEL); if (! subs) return -ENOMEM; --- linux-2.6.8-rc1/sound/core/seq/seq_prioq.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/seq/seq_prioq.c 2004-07-13 17:09:19.000000000 -0700 @@ -59,7 +59,7 @@ prioq_t *snd_seq_prioq_new(void) { prioq_t *f; - f = snd_kcalloc(sizeof(prioq_t), GFP_KERNEL); + f = kcalloc(1, sizeof(*f), GFP_KERNEL); if (f == NULL) { snd_printd("oops: malloc failed for snd_seq_prioq_new()\n"); return NULL; --- linux-2.6.8-rc1/sound/core/seq/seq_queue.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/seq/seq_queue.c 2004-07-13 17:09:19.000000000 -0700 @@ -111,7 +111,7 @@ static queue_t *queue_new(int owner, int { queue_t *q; - q = snd_kcalloc(sizeof(queue_t), GFP_KERNEL); + q = kcalloc(1, sizeof(*q), GFP_KERNEL); if (q == NULL) { snd_printd("malloc failed for snd_seq_queue_new()\n"); return NULL; --- linux-2.6.8-rc1/sound/core/seq/seq_timer.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/core/seq/seq_timer.c 2004-07-13 17:09:19.000000000 -0700 @@ -59,7 +59,7 @@ seq_timer_t *snd_seq_timer_new(void) { seq_timer_t *tmr; - tmr = snd_kcalloc(sizeof(seq_timer_t), GFP_KERNEL); + tmr = kcalloc(1, sizeof(*tmr), GFP_KERNEL); if (tmr == NULL) { snd_printd("malloc failed for snd_seq_timer_new() \n"); return NULL; --- linux-2.6.8-rc1/sound/core/seq/seq_virmidi.c 2003-06-14 12:18:24.000000000 -0700 +++ 25/sound/core/seq/seq_virmidi.c 2004-07-13 17:09:19.000000000 -0700 @@ -115,7 +115,7 @@ int snd_virmidi_receive(snd_rawmidi_t *r { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -EINVAL); + rdev = rmidi->private_data; return snd_virmidi_dev_receive_event(rdev, ev); } @@ -127,7 +127,7 @@ static int snd_virmidi_event_input(snd_s { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL); + rdev = private_data; if (!(rdev->flags & SNDRV_VIRMIDI_USE)) return 0; /* ignored */ return snd_virmidi_dev_receive_event(rdev, ev); @@ -138,7 +138,7 @@ static int snd_virmidi_event_input(snd_s */ static void snd_virmidi_input_trigger(snd_rawmidi_substream_t * substream, int up) { - snd_virmidi_t *vmidi = snd_magic_cast(snd_virmidi_t, substream->runtime->private_data, return); + snd_virmidi_t *vmidi = substream->runtime->private_data; if (up) { vmidi->trigger = 1; @@ -152,7 +152,7 @@ static void snd_virmidi_input_trigger(sn */ static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int up) { - snd_virmidi_t *vmidi = snd_magic_cast(snd_virmidi_t, substream->runtime->private_data, return); + snd_virmidi_t *vmidi = substream->runtime->private_data; int count, res; unsigned char buf[32], *pbuf; @@ -199,17 +199,17 @@ static void snd_virmidi_output_trigger(s */ static int snd_virmidi_input_open(snd_rawmidi_substream_t * substream) { - snd_virmidi_dev_t *rdev = snd_magic_cast(snd_virmidi_dev_t, substream->rmidi->private_data, return -EINVAL); + snd_virmidi_dev_t *rdev = substream->rmidi->private_data; snd_rawmidi_runtime_t *runtime = substream->runtime; snd_virmidi_t *vmidi; unsigned long flags; - vmidi = snd_magic_kcalloc(snd_virmidi_t, 0, GFP_KERNEL); + vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL); if (vmidi == NULL) return -ENOMEM; vmidi->substream = substream; if (snd_midi_event_new(0, &vmidi->parser) < 0) { - snd_magic_kfree(vmidi); + kfree(vmidi); return -ENOMEM; } vmidi->seq_mode = rdev->seq_mode; @@ -228,16 +228,16 @@ static int snd_virmidi_input_open(snd_ra */ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream) { - snd_virmidi_dev_t *rdev = snd_magic_cast(snd_virmidi_dev_t, substream->rmidi->private_data, return -EINVAL); + snd_virmidi_dev_t *rdev = substream->rmidi->private_data; snd_rawmidi_runtime_t *runtime = substream->runtime; snd_virmidi_t *vmidi; - vmidi = snd_magic_kcalloc(snd_virmidi_t, 0, GFP_KERNEL); + vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL); if (vmidi == NULL) return -ENOMEM; vmidi->substream = substream; if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &vmidi->parser) < 0) { - snd_magic_kfree(vmidi); + kfree(vmidi); return -ENOMEM; } vmidi->seq_mode = rdev->seq_mode; @@ -254,11 +254,11 @@ static int snd_virmidi_output_open(snd_r */ static int snd_virmidi_input_close(snd_rawmidi_substream_t * substream) { - snd_virmidi_t *vmidi = snd_magic_cast(snd_virmidi_t, substream->runtime->private_data, return -EINVAL); + snd_virmidi_t *vmidi = substream->runtime->private_data; snd_midi_event_free(vmidi->parser); list_del(&vmidi->list); substream->runtime->private_data = NULL; - snd_magic_kfree(vmidi); + kfree(vmidi); return 0; } @@ -267,10 +267,10 @@ static int snd_virmidi_input_close(snd_r */ static int snd_virmidi_output_close(snd_rawmidi_substream_t * substream) { - snd_virmidi_t *vmidi = snd_magic_cast(snd_virmidi_t, substream->runtime->private_data, return -EINVAL); + snd_virmidi_t *vmidi = substream->runtime->private_data; snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; - snd_magic_kfree(vmidi); + kfree(vmidi); return 0; } @@ -281,7 +281,7 @@ static int snd_virmidi_subscribe(void *p { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL); + rdev = private_data; if (!try_module_get(rdev->card->module)) return -EFAULT; rdev->flags |= SNDRV_VIRMIDI_SUBSCRIBE; @@ -295,7 +295,7 @@ static int snd_virmidi_unsubscribe(void { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL); + rdev = private_data; rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE; module_put(rdev->card->module); return 0; @@ -309,7 +309,7 @@ static int snd_virmidi_use(void *private { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL); + rdev = private_data; if (!try_module_get(rdev->card->module)) return -EFAULT; rdev->flags |= SNDRV_VIRMIDI_USE; @@ -323,7 +323,7 @@ static int snd_virmidi_unuse(void *priva { snd_virmidi_dev_t *rdev; - rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL); + rdev = private_data; rdev->flags &= ~SNDRV_VIRMIDI_USE; module_put(rdev->card->module); return 0; @@ -424,7 +424,7 @@ static void snd_virmidi_dev_detach_seq(s */ static int snd_virmidi_dev_register(snd_rawmidi_t *rmidi) { - snd_virmidi_dev_t *rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO); + snd_virmidi_dev_t *rdev = rmidi->private_data; int err; switch (rdev->seq_mode) { @@ -451,7 +451,7 @@ static int snd_virmidi_dev_register(snd_ */ static int snd_virmidi_dev_unregister(snd_rawmidi_t *rmidi) { - snd_virmidi_dev_t *rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO); + snd_virmidi_dev_t *rdev = rmidi->private_data; if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH) snd_virmidi_dev_detach_seq(rdev); @@ -471,8 +471,8 @@ static snd_rawmidi_global_ops_t snd_virm */ static void snd_virmidi_free(snd_rawmidi_t *rmidi) { - snd_virmidi_dev_t *rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return); - snd_magic_kfree(rdev); + snd_virmidi_dev_t *rdev = rmidi->private_data; + kfree(rdev); } /* @@ -493,7 +493,7 @@ int snd_virmidi_new(snd_card_t *card, in &rmidi)) < 0) return err; strcpy(rmidi->name, rmidi->id); - rdev = snd_magic_kcalloc(snd_virmidi_dev_t, 0, GFP_KERNEL); + rdev = kcalloc(1, sizeof(*rdev), GFP_KERNEL); if (rdev == NULL) { snd_device_free(card, rmidi); return -ENOMEM; --- linux-2.6.8-rc1/sound/core/sound.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/sound.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,19 +44,14 @@ static int device_mode = S_IFCHR | S_IRU MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_SUPPORTED_DEVICE("sound"); module_param(major, int, 0444); MODULE_PARM_DESC(major, "Major # for sound driver."); -MODULE_PARM_SYNTAX(major, "default:116,skill:devel"); module_param(cards_limit, int, 0444); MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); -MODULE_PARM_SYNTAX(cards_limit, "default:8,skill:advanced"); MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); #ifdef CONFIG_DEVFS_FS module_param(device_mode, int, 0444); MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); -MODULE_PARM_SYNTAX(device_mode, "default:0666,base:8"); #endif MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); @@ -439,14 +434,11 @@ EXPORT_SYMBOL(snd_unregister_oss_device) /* memory.c */ #ifdef CONFIG_SND_DEBUG_MEMORY EXPORT_SYMBOL(snd_hidden_kmalloc); +EXPORT_SYMBOL(snd_hidden_kcalloc); EXPORT_SYMBOL(snd_hidden_kfree); EXPORT_SYMBOL(snd_hidden_vmalloc); EXPORT_SYMBOL(snd_hidden_vfree); -EXPORT_SYMBOL(_snd_magic_kmalloc); -EXPORT_SYMBOL(_snd_magic_kcalloc); -EXPORT_SYMBOL(snd_magic_kfree); #endif -EXPORT_SYMBOL(snd_kcalloc); EXPORT_SYMBOL(snd_kmalloc_strdup); EXPORT_SYMBOL(copy_to_user_fromio); EXPORT_SYMBOL(copy_from_user_toio); --- linux-2.6.8-rc1/sound/core/timer.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/core/timer.c 2004-07-13 17:09:19.000000000 -0700 @@ -46,7 +46,6 @@ static int timer_limit = DEFAULT_TIMER_L MODULE_AUTHOR("Jaroslav Kysela , Takashi Iwai "); MODULE_DESCRIPTION("ALSA timer interface"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); module_param(timer_limit, int, 0444); MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); @@ -94,7 +93,7 @@ static void snd_timer_reschedule(snd_tim static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer) { snd_timer_instance_t *timeri; - timeri = snd_kcalloc(sizeof(snd_timer_instance_t), GFP_KERNEL); + timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL); if (timeri == NULL) return NULL; timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL); @@ -761,7 +760,7 @@ int snd_timer_new(snd_card_t *card, char snd_assert(tid != NULL, return -EINVAL); snd_assert(rtimer != NULL, return -EINVAL); *rtimer = NULL; - timer = snd_magic_kcalloc(snd_timer_t, 0, GFP_KERNEL); + timer = kcalloc(1, sizeof(*timer), GFP_KERNEL); if (timer == NULL) return -ENOMEM; timer->tmr_class = tid->dev_class; @@ -792,19 +791,19 @@ static int snd_timer_free(snd_timer_t *t snd_assert(timer != NULL, return -ENXIO); if (timer->private_free) timer->private_free(timer); - snd_magic_kfree(timer); + kfree(timer); return 0; } int snd_timer_dev_free(snd_device_t *device) { - snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO); + snd_timer_t *timer = device->device_data; return snd_timer_free(timer); } int snd_timer_dev_register(snd_device_t *dev) { - snd_timer_t *timer = snd_magic_cast(snd_timer_t, dev->device_data, return -ENXIO); + snd_timer_t *timer = dev->device_data; snd_timer_t *timer1; struct list_head *p; @@ -865,7 +864,7 @@ int snd_timer_unregister(snd_timer_t *ti static int snd_timer_dev_unregister(snd_device_t *device) { - snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO); + snd_timer_t *timer = device->device_data; return snd_timer_unregister(timer); } @@ -1018,7 +1017,7 @@ static int snd_timer_register_system(voi return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; - priv = (struct snd_timer_system_private *) snd_kcalloc(sizeof(struct snd_timer_system_private), GFP_KERNEL); + priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); if (priv == NULL) { snd_timer_free(timer); return -ENOMEM; @@ -1086,7 +1085,7 @@ static void snd_timer_user_interrupt(snd unsigned long resolution, unsigned long ticks) { - snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return); + snd_timer_user_t *tu = timeri->callback_data; snd_timer_read_t *r; int prev; @@ -1129,7 +1128,7 @@ static void snd_timer_user_ccallback(snd struct timespec *tstamp, unsigned long resolution) { - snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return); + snd_timer_user_t *tu = timeri->callback_data; snd_timer_tread_t r1; if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) @@ -1148,7 +1147,7 @@ static void snd_timer_user_tinterrupt(sn unsigned long resolution, unsigned long ticks) { - snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return); + snd_timer_user_t *tu = timeri->callback_data; snd_timer_tread_t *r, r1; struct timespec tstamp; int prev, append = 0; @@ -1200,7 +1199,7 @@ static int snd_timer_user_open(struct in { snd_timer_user_t *tu; - tu = snd_magic_kcalloc(snd_timer_user_t, 0, GFP_KERNEL); + tu = kcalloc(1, sizeof(*tu), GFP_KERNEL); if (tu == NULL) return -ENOMEM; spin_lock_init(&tu->qlock); @@ -1209,7 +1208,7 @@ static int snd_timer_user_open(struct in tu->queue_size = 128; tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); if (tu->queue == NULL) { - snd_magic_kfree(tu); + kfree(tu); return -ENOMEM; } file->private_data = tu; @@ -1221,7 +1220,7 @@ static int snd_timer_user_release(struct snd_timer_user_t *tu; if (file->private_data) { - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; file->private_data = NULL; fasync_helper(-1, file, 0, &tu->fasync); if (tu->timeri) @@ -1230,7 +1229,7 @@ static int snd_timer_user_release(struct kfree(tu->queue); if (tu->tqueue) kfree(tu->tqueue); - snd_magic_kfree(tu); + kfree(tu); } return 0; } @@ -1449,7 +1448,7 @@ static int snd_timer_user_tselect(struct char str[32]; int err; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; if (tu->timeri) snd_timer_close(tu->timeri); if (copy_from_user(&tselect, _tselect, sizeof(tselect))) @@ -1495,7 +1494,7 @@ static int snd_timer_user_info(struct fi snd_timer_info_t info; snd_timer_t *t; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); t = tu->timeri->timer; snd_assert(t != NULL, return -ENXIO); @@ -1520,7 +1519,7 @@ static int snd_timer_user_params(struct snd_timer_tread_t *ttr; int err; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); t = tu->timeri->timer; snd_assert(t != NULL, return -ENXIO); @@ -1608,7 +1607,7 @@ static int snd_timer_user_status(struct snd_timer_user_t *tu; snd_timer_status_t status; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); memset(&status, 0, sizeof(status)); status.tstamp = tu->tstamp; @@ -1628,7 +1627,7 @@ static int snd_timer_user_start(struct f int err; snd_timer_user_t *tu; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); snd_timer_stop(tu->timeri); tu->timeri->lost = 0; @@ -1641,7 +1640,7 @@ static int snd_timer_user_stop(struct fi int err; snd_timer_user_t *tu; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0; } @@ -1651,7 +1650,7 @@ static int snd_timer_user_continue(struc int err; snd_timer_user_t *tu; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); tu->timeri->lost = 0; return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; @@ -1664,7 +1663,7 @@ static int snd_timer_user_ioctl(struct i void __user *argp = (void __user *)arg; int __user *p = argp; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; switch (cmd) { case SNDRV_TIMER_IOCTL_PVERSION: return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; @@ -1710,7 +1709,7 @@ static int snd_timer_user_fasync(int fd, snd_timer_user_t *tu; int err; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; err = fasync_helper(fd, file, on, &tu->fasync); if (err < 0) return err; @@ -1723,7 +1722,7 @@ static ssize_t snd_timer_user_read(struc long result = 0, unit; int err = 0; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO); + tu = file->private_data; unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { @@ -1785,7 +1784,7 @@ static unsigned int snd_timer_user_poll( unsigned int mask; snd_timer_user_t *tu; - tu = snd_magic_cast(snd_timer_user_t, file->private_data, return 0); + tu = file->private_data; poll_wait(file, &tu->qchange_sleep, wait); --- linux-2.6.8-rc1/sound/drivers/dummy.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/dummy.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,8 +34,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Dummy soundcard (/dev/null)"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ALSA,Dummy soundcard}}"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); #define MAX_PCM_DEVICES 4 #define MAX_PCM_SUBSTREAMS 16 @@ -133,22 +132,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for dummy soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for dummy soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(pcm_devs, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); -MODULE_PARM_SYNTAX(pcm_devs, SNDRV_ENABLED ",allows:{{0,4}},default:1,dialog:list"); module_param_array(pcm_substreams, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); -MODULE_PARM_SYNTAX(pcm_substreams, SNDRV_ENABLED ",allows:{{1,16}},default:8,dialog:list"); //module_param_array(midi_devs, int, boot_devs, 0444); //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); -//MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{0,2}},default:8,dialog:list"); #define MIXER_ADDR_MASTER 0 #define MIXER_ADDR_LINE 1 @@ -180,24 +173,10 @@ typedef struct snd_card_dummy_pcm { static snd_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; -static int snd_card_dummy_playback_ioctl(snd_pcm_substream_t * substream, - unsigned int cmd, - void *arg) -{ - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - -static int snd_card_dummy_capture_ioctl(snd_pcm_substream_t * substream, - unsigned int cmd, - void *arg) -{ - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - static void snd_card_dummy_pcm_timer_start(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; dpcm->timer.expires = 1 + jiffies; add_timer(&dpcm->timer); @@ -206,7 +185,7 @@ static void snd_card_dummy_pcm_timer_sta static void snd_card_dummy_pcm_timer_stop(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; del_timer(&dpcm->timer); } @@ -240,7 +219,7 @@ static int snd_card_dummy_capture_trigge static int snd_card_dummy_pcm_prepare(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; unsigned int bps; bps = runtime->rate * runtime->channels; @@ -269,7 +248,7 @@ static int snd_card_dummy_capture_prepar static void snd_card_dummy_pcm_timer_function(unsigned long data) { - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, (void *)data, return); + snd_card_dummy_pcm_t *dpcm = (snd_card_dummy_pcm_t *)data; dpcm->timer.expires = 1 + jiffies; add_timer(&dpcm->timer); @@ -287,7 +266,7 @@ static void snd_card_dummy_pcm_timer_fun static snd_pcm_uframes_t snd_card_dummy_playback_pointer(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; return bytes_to_frames(runtime, dpcm->pcm_buf_pos); } @@ -295,7 +274,7 @@ static snd_pcm_uframes_t snd_card_dummy_ static snd_pcm_uframes_t snd_card_dummy_capture_pointer(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; return bytes_to_frames(runtime, dpcm->pcm_buf_pos); } @@ -338,8 +317,19 @@ static snd_pcm_hardware_t snd_card_dummy static void snd_card_dummy_runtime_free(snd_pcm_runtime_t *runtime) { - snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return); - snd_magic_kfree(dpcm); + snd_card_dummy_pcm_t *dpcm = runtime->private_data; + kfree(dpcm); +} + +static int snd_card_dummy_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); +} + +static int snd_card_dummy_hw_free(snd_pcm_substream_t * substream) +{ + return snd_pcm_lib_free_pages(substream); } static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream) @@ -348,13 +338,9 @@ static int snd_card_dummy_playback_open( snd_card_dummy_pcm_t *dpcm; int err; - dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL); + dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL); if (dpcm == NULL) return -ENOMEM; - if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) { - snd_magic_kfree(dpcm); - return -ENOMEM; - } init_timer(&dpcm->timer); dpcm->timer.data = (unsigned long) dpcm; dpcm->timer.function = snd_card_dummy_pcm_timer_function; @@ -370,7 +356,7 @@ static int snd_card_dummy_playback_open( if (substream->pcm->device & 2) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); if ((err = add_playback_constraints(runtime)) < 0) { - snd_magic_kfree(dpcm); + kfree(dpcm); return err; } @@ -383,14 +369,9 @@ static int snd_card_dummy_capture_open(s snd_card_dummy_pcm_t *dpcm; int err; - dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL); + dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL); if (dpcm == NULL) return -ENOMEM; - if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) { - snd_magic_kfree(dpcm); - return -ENOMEM; - } - memset(runtime->dma_area, 0, runtime->dma_bytes); init_timer(&dpcm->timer); dpcm->timer.data = (unsigned long) dpcm; dpcm->timer.function = snd_card_dummy_pcm_timer_function; @@ -406,7 +387,7 @@ static int snd_card_dummy_capture_open(s if (substream->pcm->device & 2) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); if ((err = add_capture_constraints(runtime)) < 0) { - snd_magic_kfree(dpcm); + kfree(dpcm); return err; } @@ -415,24 +396,20 @@ static int snd_card_dummy_capture_open(s static int snd_card_dummy_playback_close(snd_pcm_substream_t * substream) { - snd_pcm_runtime_t *runtime = substream->runtime; - - snd_free_pages(runtime->dma_area, runtime->dma_bytes); return 0; } static int snd_card_dummy_capture_close(snd_pcm_substream_t * substream) { - snd_pcm_runtime_t *runtime = substream->runtime; - - snd_free_pages(runtime->dma_area, runtime->dma_bytes); return 0; } static snd_pcm_ops_t snd_card_dummy_playback_ops = { .open = snd_card_dummy_playback_open, .close = snd_card_dummy_playback_close, - .ioctl = snd_card_dummy_playback_ioctl, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_card_dummy_hw_params, + .hw_free = snd_card_dummy_hw_free, .prepare = snd_card_dummy_playback_prepare, .trigger = snd_card_dummy_playback_trigger, .pointer = snd_card_dummy_playback_pointer, @@ -441,7 +418,9 @@ static snd_pcm_ops_t snd_card_dummy_play static snd_pcm_ops_t snd_card_dummy_capture_ops = { .open = snd_card_dummy_capture_open, .close = snd_card_dummy_capture_close, - .ioctl = snd_card_dummy_capture_ioctl, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_card_dummy_hw_params, + .hw_free = snd_card_dummy_hw_free, .prepare = snd_card_dummy_capture_prepare, .trigger = snd_card_dummy_capture_trigger, .pointer = snd_card_dummy_capture_pointer, @@ -459,6 +438,9 @@ static int __init snd_card_dummy_pcm(snd pcm->private_data = dummy; pcm->info_flags = 0; strcpy(pcm->name, "Dummy PCM"); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, 64*1024); return 0; } @@ -479,7 +461,7 @@ static int snd_dummy_volume_info(snd_kco static int snd_dummy_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol); + snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); unsigned long flags; int addr = kcontrol->private_value; @@ -492,7 +474,7 @@ static int snd_dummy_volume_get(snd_kcon static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol); + snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); unsigned long flags; int change, addr = kcontrol->private_value; int left, right; @@ -533,7 +515,7 @@ static int snd_dummy_capsrc_info(snd_kco static int snd_dummy_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol); + snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); unsigned long flags; int addr = kcontrol->private_value; @@ -546,7 +528,7 @@ static int snd_dummy_capsrc_get(snd_kcon static int snd_dummy_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol); + snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); unsigned long flags; int change, addr = kcontrol->private_value; int left, right; --- linux-2.6.8-rc1/sound/drivers/mpu401/mpu401.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/drivers/mpu401/mpu401.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,7 +42,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("MPU-401 UART"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -56,24 +55,18 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for MPU-401 device."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for MPU-401 device."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable MPU-401 device."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef USE_ACPI_PNP module_param_array(acpipnp, bool, boot_devs, 0444); MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device."); -MODULE_PARM_SYNTAX(acpipnp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for MPU-401 device."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); #ifndef CONFIG_ACPI_BUS struct acpi_device; --- linux-2.6.8-rc1/sound/drivers/mpu401/mpu401_uart.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/drivers/mpu401/mpu401_uart.c 2004-07-13 17:09:19.000000000 -0700 @@ -123,7 +123,7 @@ static void _snd_mpu401_uart_interrupt(m */ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mpu401_t *mpu = snd_magic_cast(mpu401_t, dev_id, return IRQ_NONE); + mpu401_t *mpu = dev_id; if (mpu == NULL) return IRQ_NONE; @@ -137,7 +137,7 @@ irqreturn_t snd_mpu401_uart_interrupt(in */ static void snd_mpu401_uart_timer(unsigned long data) { - mpu401_t *mpu = snd_magic_cast(mpu401_t, (void *)data, return); + mpu401_t *mpu = (mpu401_t *)data; spin_lock(&mpu->timer_lock); /*mpu->mode |= MPU401_MODE_TIMER;*/ @@ -235,7 +235,7 @@ static int snd_mpu401_uart_input_open(sn mpu401_t *mpu; int err; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return -ENXIO); + mpu = substream->rmidi->private_data; if (mpu->open_input && (err = mpu->open_input(mpu)) < 0) return err; if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) { @@ -253,7 +253,7 @@ static int snd_mpu401_uart_output_open(s mpu401_t *mpu; int err; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return -ENXIO); + mpu = substream->rmidi->private_data; if (mpu->open_output && (err = mpu->open_output(mpu)) < 0) return err; if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { @@ -270,7 +270,7 @@ static int snd_mpu401_uart_input_close(s { mpu401_t *mpu; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return -ENXIO); + mpu = substream->rmidi->private_data; clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); mpu->substream_input = NULL; if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) @@ -284,7 +284,7 @@ static int snd_mpu401_uart_output_close( { mpu401_t *mpu; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return -ENXIO); + mpu = substream->rmidi->private_data; clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); mpu->substream_output = NULL; if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) @@ -303,7 +303,7 @@ static void snd_mpu401_uart_input_trigge mpu401_t *mpu; int max = 64; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return); + mpu = substream->rmidi->private_data; if (up) { if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { /* first time - flush FIFO */ @@ -394,7 +394,7 @@ static void snd_mpu401_uart_output_trigg unsigned long flags; mpu401_t *mpu; - mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return); + mpu = substream->rmidi->private_data; if (up) { set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); @@ -441,14 +441,14 @@ static snd_rawmidi_ops_t snd_mpu401_uart static void snd_mpu401_uart_free(snd_rawmidi_t *rmidi) { - mpu401_t *mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return); + mpu401_t *mpu = rmidi->private_data; if (mpu->irq_flags && mpu->irq >= 0) free_irq(mpu->irq, (void *) mpu); if (mpu->res) { release_resource(mpu->res); kfree_nocheck(mpu->res); } - snd_magic_kfree(mpu); + kfree(mpu); } /** @@ -484,7 +484,7 @@ int snd_mpu401_uart_new(snd_card_t * car *rrawmidi = NULL; if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0) return err; - mpu = snd_magic_kcalloc(mpu401_t, 0, GFP_KERNEL); + mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL); if (mpu == NULL) { snd_device_free(card, rmidi); return -ENOMEM; --- linux-2.6.8-rc1/sound/drivers/mtpav.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/mtpav.c 2004-07-13 17:09:19.000000000 -0700 @@ -69,8 +69,7 @@ MODULE_AUTHOR("Michael T. Mayers"); MODULE_DESCRIPTION("MOTU MidiTimePiece AV multiport MIDI"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{MOTU,MidiTimePiece AV multiport MIDI}}"); +MODULE_SUPPORTED_DEVICE("{{MOTU,MidiTimePiece AV multiport MIDI}}"); // io resources #define MTPAV_IOBASE 0x378 @@ -85,19 +84,14 @@ static int hwports = MTPAV_MAX_PORTS; /* module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for MotuMTPAV MIDI."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for MotuMTPAV MIDI."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param(port, long, 0444); MODULE_PARM_DESC(port, "Parallel port # for MotuMTPAV MIDI."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x378},{0x278}},dialog:list"); module_param(irq, int, 0444); MODULE_PARM_DESC(irq, "Parallel IRQ # for MotuMTPAV MIDI."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{7},{5}},dialog:list"); module_param(hwports, int, 0444); MODULE_PARM_DESC(hwports, "Hardware ports # for MotuMTPAV MIDI."); -MODULE_PARM_SYNTAX(hwports, SNDRV_ENABLED ",allows:{{1,8}},dialog:list"); /* * defines @@ -419,7 +413,7 @@ static void snd_mtpav_input_trigger(snd_ static void snd_mtpav_output_timer(unsigned long data) { - mtpav_t *chip = snd_magic_cast(mtpav_t, (void *)data, return); + mtpav_t *chip = (mtpav_t *)data; int p; spin_lock(&chip->spinlock); @@ -587,7 +581,7 @@ static void snd_mtpav_read_bytes(mtpav_t static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id, struct pt_regs *regs) { - mtpav_t *mcard = snd_magic_cast(mtpav_t, dev_id, return IRQ_NONE); + mtpav_t *mcard = dev_id; //printk("irqh()\n"); spin_lock(&mcard->spinlock); @@ -695,7 +689,7 @@ static int snd_mtpav_get_RAWMIDI(mtpav_t static mtpav_t *new_mtpav(void) { - mtpav_t *ncrd = (mtpav_t *) snd_magic_kcalloc(mtpav_t, 0, GFP_KERNEL); + mtpav_t *ncrd = kcalloc(1, sizeof(*ncrd), GFP_KERNEL); if (ncrd != NULL) { spin_lock_init(&ncrd->spinlock); @@ -728,7 +722,7 @@ static void free_mtpav(mtpav_t * crd) release_resource(crd->res_port); kfree_nocheck(crd->res_port); } - snd_magic_kfree(crd); + kfree(crd); } /* --- linux-2.6.8-rc1/sound/drivers/opl3/opl3_lib.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/drivers/opl3/opl3_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -35,8 +35,6 @@ MODULE_AUTHOR("Jaroslav Kysela private_data, return); + opl3 = hw->private_data; status = inb(opl3->l_port); #if 0 snd_printk("AdLib IRQ status = 0x%x\n", status); @@ -354,13 +352,13 @@ static int snd_opl3_free(opl3_t *opl3) release_resource(opl3->res_r_port); kfree_nocheck(opl3->res_r_port); } - snd_magic_kfree(opl3); + kfree(opl3); return 0; } static int snd_opl3_dev_free(snd_device_t *device) { - opl3_t *opl3 = snd_magic_cast(opl3_t, device->device_data, return -ENXIO); + opl3_t *opl3 = device->device_data; return snd_opl3_free(opl3); } @@ -379,7 +377,7 @@ int snd_opl3_create(snd_card_t * card, *ropl3 = NULL; - opl3 = snd_magic_kcalloc(opl3_t, 0, GFP_KERNEL); + opl3 = kcalloc(1, sizeof(*opl3), GFP_KERNEL); if (opl3 == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/drivers/opl3/opl3_midi.c 2003-06-14 12:18:23.000000000 -0700 +++ 25/sound/drivers/opl3/opl3_midi.c 2004-07-13 17:09:19.000000000 -0700 @@ -313,7 +313,7 @@ void snd_opl3_note_on(void *p, int note, fm_instrument_t *fm; unsigned long flags; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", @@ -672,7 +672,7 @@ void snd_opl3_note_off(void *p, int note unsigned long flags; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("Note off, ch %i, inst %i, note %i\n", @@ -712,7 +712,7 @@ void snd_opl3_key_press(void *p, int not { opl3_t *opl3; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("Key pressure, ch#: %i, inst#: %i\n", chan->number, chan->midi_program); @@ -726,7 +726,7 @@ void snd_opl3_terminate_note(void *p, in { opl3_t *opl3; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("Terminate note, ch#: %i, inst#: %i\n", chan->number, chan->midi_program); @@ -814,7 +814,7 @@ void snd_opl3_control(void *p, int type, { opl3_t *opl3; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n", type, chan->number, chan->midi_program); @@ -851,7 +851,7 @@ void snd_opl3_nrpn(void *p, snd_midi_cha { opl3_t *opl3; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("NRPN, ch#: %i, inst#: %i\n", chan->number, chan->midi_program); @@ -866,7 +866,7 @@ void snd_opl3_sysex(void *p, unsigned ch { opl3_t *opl3; - opl3 = snd_magic_cast(opl3_t, p, return); + opl3 = p; #ifdef DEBUG_MIDI snd_printk("SYSEX\n"); #endif --- linux-2.6.8-rc1/sound/drivers/opl3/opl3_oss.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/opl3/opl3_oss.c 2004-07-13 17:09:19.000000000 -0700 @@ -57,7 +57,7 @@ static snd_seq_oss_callback_t oss_callba static int snd_opl3_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return -EINVAL); + opl3_t *opl3 = private_data; if (ev->type != SNDRV_SEQ_EVENT_OSS) snd_midi_process_event(&opl3_ops, ev, opl3->oss_chset); @@ -68,7 +68,7 @@ static int snd_opl3_oss_event_input(snd_ static void snd_opl3_oss_free_port(void *private_data) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return); + opl3_t *opl3 = private_data; snd_midi_channel_free_set(opl3->oss_chset); } @@ -156,7 +156,7 @@ void snd_opl3_free_seq_oss(opl3_t *opl3) /* open OSS sequencer */ static int snd_opl3_open_seq_oss(snd_seq_oss_arg_t *arg, void *closure) { - opl3_t *opl3 = snd_magic_cast(opl3_t, closure, return -EINVAL); + opl3_t *opl3 = closure; int err; snd_assert(arg != NULL, return -ENXIO); @@ -182,7 +182,7 @@ static int snd_opl3_close_seq_oss(snd_se opl3_t *opl3; snd_assert(arg != NULL, return -ENXIO); - opl3 = snd_magic_cast(opl3_t, arg->private_data, return -EINVAL); + opl3 = arg->private_data; snd_opl3_synth_cleanup(opl3); @@ -213,7 +213,7 @@ static int snd_opl3_load_patch_seq_oss(s int err = -EINVAL; snd_assert(arg != NULL, return -ENXIO); - opl3 = snd_magic_cast(opl3_t, arg->private_data, return -EINVAL); + opl3 = arg->private_data; if ((format == FM_PATCH) || (format == OPL3_PATCH)) { struct sbi_instrument sbi; @@ -241,7 +241,7 @@ static int snd_opl3_load_patch_seq_oss(s } size = sizeof(*put) + sizeof(fm_xinstrument_t); - put = (snd_seq_instr_header_t *)snd_kcalloc(size, GFP_KERNEL); + put = kcalloc(1, size, GFP_KERNEL); if (put == NULL) return -ENOMEM; /* build header */ @@ -325,7 +325,7 @@ static int snd_opl3_ioctl_seq_oss(snd_se opl3_t *opl3; snd_assert(arg != NULL, return -ENXIO); - opl3 = snd_magic_cast(opl3_t, arg->private_data, return -EINVAL); + opl3 = arg->private_data; switch (cmd) { case SNDCTL_FM_LOAD_INSTR: snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); @@ -350,7 +350,7 @@ static int snd_opl3_reset_seq_oss(snd_se opl3_t *opl3; snd_assert(arg != NULL, return -ENXIO); - opl3 = snd_magic_cast(opl3_t, arg->private_data, return -EINVAL); + opl3 = arg->private_data; return 0; } --- linux-2.6.8-rc1/sound/drivers/opl3/opl3_seq.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/opl3/opl3_seq.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,7 +30,6 @@ MODULE_AUTHOR("Uros Bizjak "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ALSA driver for OPL3 FM synth"); -MODULE_CLASSES("{sound}"); int use_internal_drums = 0; module_param(use_internal_drums, bool, 0444); @@ -99,7 +98,7 @@ void snd_opl3_synth_cleanup(opl3_t * opl int snd_opl3_synth_use(void *private_data, snd_seq_port_subscribe_t * info) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return -ENXIO); + opl3_t *opl3 = private_data; int err; if ((err = snd_opl3_synth_setup(opl3)) < 0) @@ -126,7 +125,7 @@ int snd_opl3_synth_use(void *private_dat int snd_opl3_synth_unuse(void *private_data, snd_seq_port_subscribe_t * info) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return -ENXIO); + opl3_t *opl3 = private_data; snd_opl3_synth_cleanup(opl3); @@ -151,7 +150,7 @@ snd_midi_op_t opl3_ops = { static int snd_opl3_synth_event_input(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return -EINVAL); + opl3_t *opl3 = private_data; if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN && ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) { @@ -169,7 +168,7 @@ static int snd_opl3_synth_event_input(sn static void snd_opl3_synth_free_port(void *private_data) { - opl3_t *opl3 = snd_magic_cast(opl3_t, private_data, return); + opl3_t *opl3 = private_data; snd_midi_channel_free_set(opl3->chset); } --- linux-2.6.8-rc1/sound/drivers/opl3/opl3_synth.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/opl3/opl3_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -74,7 +74,7 @@ static int snd_opl3_set_connection(opl3_ */ int snd_opl3_open(snd_hwdep_t * hw, struct file *file) { - opl3_t *opl3 = snd_magic_cast(opl3_t, hw->private_data, return -ENXIO); + opl3_t *opl3 = hw->private_data; down(&opl3->access_mutex); if (opl3->used) { @@ -93,7 +93,7 @@ int snd_opl3_open(snd_hwdep_t * hw, stru int snd_opl3_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) { - opl3_t *opl3 = snd_magic_cast(opl3_t, hw->private_data, return -ENXIO); + opl3_t *opl3 = hw->private_data; void __user *argp = (void __user *)arg; snd_assert(opl3 != NULL, return -EINVAL); @@ -176,7 +176,7 @@ int snd_opl3_ioctl(snd_hwdep_t * hw, str */ int snd_opl3_release(snd_hwdep_t * hw, struct file *file) { - opl3_t *opl3 = snd_magic_cast(opl3_t, hw->private_data, return -ENXIO); + opl3_t *opl3 = hw->private_data; snd_opl3_reset(opl3); down(&opl3->access_mutex); --- linux-2.6.8-rc1/sound/drivers/opl4/Makefile 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/drivers/opl4/Makefile 2004-07-13 17:09:19.000000000 -0700 @@ -15,4 +15,4 @@ snd-opl4-synth-objs := opl4_seq.o opl4_s sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o -obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o \ No newline at end of file +obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o --- linux-2.6.8-rc1/sound/drivers/opl4/opl4_lib.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/drivers/opl4/opl4_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,7 +26,6 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("OPL4 driver"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); static void inline snd_opl4_wait(opl4_t *opl4) { @@ -141,7 +140,7 @@ static int snd_opl4_detect(opl4_t *opl4) #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) static void snd_opl4_seq_dev_free(snd_seq_device_t *seq_dev) { - opl4_t *opl4 = snd_magic_cast(opl4_t, seq_dev->private_data, return); + opl4_t *opl4 = seq_dev->private_data; opl4->seq_dev = NULL; } @@ -172,12 +171,12 @@ static void snd_opl4_free(opl4_t *opl4) release_resource(opl4->res_pcm_port); kfree_nocheck(opl4->res_pcm_port); } - snd_magic_kfree(opl4); + kfree(opl4); } static int snd_opl4_dev_free(snd_device_t *device) { - opl4_t *opl4 = snd_magic_cast(opl4_t, device->device_data, return -ENXIO); + opl4_t *opl4 = device->device_data; snd_opl4_free(opl4); return 0; } @@ -199,7 +198,7 @@ int snd_opl4_create(snd_card_t *card, if (ropl4) *ropl4 = NULL; - opl4 = snd_magic_kcalloc(opl4_t, 0, GFP_KERNEL); + opl4 = kcalloc(1, sizeof(*opl4), GFP_KERNEL); if (!opl4) return -ENOMEM; --- linux-2.6.8-rc1/sound/drivers/opl4/opl4_mixer.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/sound/drivers/opl4/opl4_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -20,8 +20,6 @@ #include "opl4_local.h" #include -#define chip_t opl4_t - static int snd_opl4_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; --- linux-2.6.8-rc1/sound/drivers/opl4/opl4_proc.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/opl4/opl4_proc.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,7 +26,7 @@ static int snd_opl4_mem_proc_open(snd_info_entry_t *entry, unsigned short mode, void **file_private_data) { - opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + opl4_t *opl4 = entry->private_data; down(&opl4->access_mutex); if (opl4->memory_access) { @@ -41,7 +41,7 @@ static int snd_opl4_mem_proc_open(snd_in static int snd_opl4_mem_proc_release(snd_info_entry_t *entry, unsigned short mode, void *file_private_data) { - opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + opl4_t *opl4 = entry->private_data; down(&opl4->access_mutex); opl4->memory_access--; @@ -52,7 +52,7 @@ static int snd_opl4_mem_proc_release(snd static long snd_opl4_mem_proc_read(snd_info_entry_t *entry, void *file_private_data, struct file *file, char __user *_buf, long count) { - opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + opl4_t *opl4 = entry->private_data; long size; char* buf; @@ -78,7 +78,7 @@ static long snd_opl4_mem_proc_read(snd_i static long snd_opl4_mem_proc_write(snd_info_entry_t *entry, void *file_private_data, struct file *file, const char __user *_buf, long count) { - opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + opl4_t *opl4 = entry->private_data; long size; char *buf; --- linux-2.6.8-rc1/sound/drivers/opl4/opl4_seq.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/opl4/opl4_seq.c 2004-07-13 17:09:19.000000000 -0700 @@ -39,13 +39,11 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("OPL4 wavetable synth driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_CLASSES("{sound}"); int volume_boost = 8; module_param(volume_boost, int, 0644); MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds."); -MODULE_PARM_SYNTAX(volume_boost, "default:8"); static int snd_opl4_seq_use_inc(opl4_t *opl4) { @@ -61,7 +59,7 @@ static void snd_opl4_seq_use_dec(opl4_t static int snd_opl4_seq_use(void *private_data, snd_seq_port_subscribe_t *info) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + opl4_t *opl4 = private_data; int err; down(&opl4->access_mutex); @@ -88,7 +86,7 @@ static int snd_opl4_seq_use(void *privat static int snd_opl4_seq_unuse(void *private_data, snd_seq_port_subscribe_t *info) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + opl4_t *opl4 = private_data; snd_opl4_synth_shutdown(opl4); @@ -112,7 +110,7 @@ static snd_midi_op_t opl4_ops = { static int snd_opl4_seq_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + opl4_t *opl4 = private_data; snd_midi_process_event(&opl4_ops, ev, opl4->chset); return 0; @@ -120,7 +118,7 @@ static int snd_opl4_seq_event_input(snd_ static void snd_opl4_seq_free_port(void *private_data) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; snd_midi_channel_free_set(opl4->chset); } --- linux-2.6.8-rc1/sound/drivers/opl4/opl4_synth.c 2003-08-08 22:55:14.000000000 -0700 +++ 25/sound/drivers/opl4/opl4_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -472,7 +472,7 @@ static void snd_opl4_wait_for_wave_heade void snd_opl4_note_on(void *private_data, int note, int vel, snd_midi_channel_t *chan) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; const opl4_region_ptr_t *regions; opl4_voice_t *voice[2]; const opl4_sound_t *sound[2]; @@ -553,7 +553,7 @@ static void snd_opl4_voice_off(opl4_t *o void snd_opl4_note_off(void *private_data, int note, int vel, snd_midi_channel_t *chan) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off); } @@ -569,14 +569,14 @@ static void snd_opl4_terminate_voice(opl void snd_opl4_terminate_note(void *private_data, int note, snd_midi_channel_t *chan) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice); } void snd_opl4_control(void *private_data, int type, snd_midi_channel_t *chan) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; switch (type) { case MIDI_CTL_MSB_MODWHEEL: @@ -616,7 +616,7 @@ void snd_opl4_control(void *private_data void snd_opl4_sysex(void *private_data, unsigned char *buf, int len, int parsed, snd_midi_channel_set_t *chset) { - opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + opl4_t *opl4 = private_data; if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME) snd_opl4_do_for_all(opl4, snd_opl4_update_volume); --- linux-2.6.8-rc1/sound/drivers/serial-u16550.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/serial-u16550.c 2004-07-13 17:09:19.000000000 -0700 @@ -46,8 +46,7 @@ MODULE_DESCRIPTION("MIDI serial u16550"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ALSA, MIDI serial u16550}}"); +MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}"); #define SNDRV_SERIAL_SOUNDCANVAS 0 /* Roland Soundcanvas; F5 NN selects part */ #define SNDRV_SERIAL_MS124T 1 /* Midiator MS-124T */ @@ -81,38 +80,27 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Serial MIDI."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Serial MIDI."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable UART16550A chip."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for UART16550A chip."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for UART16550A chip."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(speed, int, boot_devs, 0444); MODULE_PARM_DESC(speed, "Speed in bauds."); -MODULE_PARM_SYNTAX(speed, SNDRV_ENABLED ",allows:{9600,19200,38400,57600,115200},dialog:list"); module_param_array(base, int, boot_devs, 0444); MODULE_PARM_DESC(base, "Base for divisor in bauds."); -MODULE_PARM_SYNTAX(base, SNDRV_ENABLED ",allows:{57600,115200,230400,460800},dialog:list"); module_param_array(outs, int, boot_devs, 0444); MODULE_PARM_DESC(outs, "Number of MIDI outputs."); module_param_array(ins, int, boot_devs, 0444); MODULE_PARM_DESC(ins, "Number of MIDI inputs."); module_param_array(droponfull, bool, boot_devs, 0444); MODULE_PARM_DESC(droponfull, "Flag to enable drop-on-full buffer mode"); -MODULE_PARM_SYNTAX(droponfull, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); -MODULE_PARM_SYNTAX(outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); -MODULE_PARM_SYNTAX(ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); module_param_array(adaptor, int, boot_devs, 0444); MODULE_PARM_DESC(adaptor, "Type of adaptor."); -MODULE_PARM_SYNTAX(adaptor, SNDRV_ENABLED ",allows:{{0=Soundcanvas,1=MS-124T,2=MS-124W S/A,3=MS-124W M/B,4=Generic}},dialog:list"); /*#define SNDRV_SERIAL_MS124W_MB_NOCOMBO 1*/ /* Address outs as 0-3 instead of bitmap */ @@ -524,7 +512,7 @@ static void snd_uart16550_do_close(snd_u static int snd_uart16550_input_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -538,7 +526,7 @@ static int snd_uart16550_input_open(snd_ static int snd_uart16550_input_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_INPUT_OPEN; @@ -552,7 +540,7 @@ static int snd_uart16550_input_close(snd static void snd_uart16550_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (up) { @@ -566,7 +554,7 @@ static void snd_uart16550_input_trigger( static int snd_uart16550_output_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (uart->filemode == SERIAL_MODE_NOT_OPENED) @@ -580,7 +568,7 @@ static int snd_uart16550_output_open(snd static int snd_uart16550_output_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return -ENXIO); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); uart->filemode &= ~SERIAL_MODE_OUTPUT_OPEN; @@ -652,7 +640,7 @@ static void snd_uart16550_output_write(s { unsigned long flags; unsigned char midi_byte, addr_byte; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return); + snd_uart16550_t *uart = substream->rmidi->private_data; char first; static unsigned long lasttime=0; @@ -730,7 +718,7 @@ static void snd_uart16550_output_write(s static void snd_uart16550_output_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return); + snd_uart16550_t *uart = substream->rmidi->private_data; spin_lock_irqsave(&uart->open_lock, flags); if (up) { @@ -765,13 +753,13 @@ static int snd_uart16550_free(snd_uart16 release_resource(uart->res_base); kfree_nocheck(uart->res_base); } - snd_magic_kfree(uart); + kfree(uart); return 0; }; static int snd_uart16550_dev_free(snd_device_t *device) { - snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, device->device_data, return -ENXIO); + snd_uart16550_t *uart = device->device_data; return snd_uart16550_free(uart); } @@ -791,7 +779,7 @@ static int __init snd_uart16550_create(s int err; - if ((uart = snd_magic_kcalloc(snd_uart16550_t, 0, GFP_KERNEL)) == NULL) + if ((uart = kcalloc(1, sizeof(*uart), GFP_KERNEL)) == NULL) return -ENOMEM; uart->adaptor = adaptor; uart->card = card; --- linux-2.6.8-rc1/sound/drivers/virmidi.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/drivers/virmidi.c 2004-07-13 17:09:19.000000000 -0700 @@ -57,8 +57,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("Dummy soundcard for virtual rawmidi devices"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ALSA,Virtual rawmidi device}}"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual rawmidi device}}"); #define MAX_MIDI_DEVICES 8 @@ -70,16 +69,12 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for virmidi soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for virmidi soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable this soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(midi_devs, int, boot_devs, 0444); MODULE_PARM_DESC(midi_devs, "MIDI devices # (1-8)"); -MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{1,8}}"); typedef struct snd_card_virmidi { snd_card_t *card; @@ -113,7 +108,7 @@ static int __init snd_card_virmidi_probe snd_virmidi_dev_t *rdev; if ((err = snd_virmidi_new(card, idx, &rmidi)) < 0) goto __nodev; - rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, continue); + rdev = rmidi->private_data; vmidi->midi[idx] = rmidi; strcpy(rmidi->name, "Virtual Raw MIDI"); rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; --- linux-2.6.8-rc1/sound/drivers/vx/vx_core.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/drivers/vx/vx_core.c 2004-07-13 17:09:19.000000000 -0700 @@ -506,7 +506,7 @@ static int vx_test_irq_src(vx_core_t *ch */ static void vx_interrupt(unsigned long private_data) { - vx_core_t *chip = snd_magic_cast(vx_core_t, (void*)private_data, return); + vx_core_t *chip = (vx_core_t *) private_data; unsigned int events; if (chip->chip_status & VX_STAT_IS_STALE) @@ -550,7 +550,7 @@ static void vx_interrupt(unsigned long p */ irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs) { - vx_core_t *chip = snd_magic_cast(vx_core_t, dev, return IRQ_NONE); + vx_core_t *chip = dev; if (! (chip->chip_status & VX_STAT_CHIP_INIT) || (chip->chip_status & VX_STAT_IS_STALE)) @@ -572,6 +572,7 @@ static void vx_reset_board(vx_core_t *ch if (cold_reset) { chip->audio_source_target = chip->audio_source; chip->clock_source = INTERNAL_QUARTZ; + chip->clock_mode = VX_CLOCK_MODE_AUTO; chip->freq = 48000; chip->uer_detected = VX_UER_MODE_NOT_PRESENT; chip->uer_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; @@ -603,9 +604,10 @@ static void vx_reset_board(vx_core_t *ch static void vx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - vx_core_t *chip = snd_magic_cast(vx_core_t, entry->private_data, return); + vx_core_t *chip = entry->private_data; static char *audio_src_vxp[] = { "Line", "Mic", "Digital" }; static char *audio_src_vx2[] = { "Analog", "Analog", "Digital" }; + static char *clock_mode[] = { "Auto", "Internal", "External" }; static char *clock_src[] = { "Internal", "External" }; static char *uer_type[] = { "Consumer", "Professional", "Not Present" }; @@ -629,6 +631,7 @@ static void vx_proc_read(snd_info_entry_ snd_iprintf(buffer, "Input Source: %s\n", vx_is_pcmcia(chip) ? audio_src_vxp[chip->audio_source] : audio_src_vx2[chip->audio_source]); + snd_iprintf(buffer, "Clock Mode: %s\n", clock_mode[chip->clock_mode]); snd_iprintf(buffer, "Clock Source: %s\n", clock_src[chip->clock_source]); snd_iprintf(buffer, "Frequency: %d\n", chip->freq); snd_iprintf(buffer, "Detected Frequency: %d\n", chip->freq_detected); @@ -731,7 +734,7 @@ vx_core_t *snd_vx_create(snd_card_t *car snd_assert(card && hw && ops, return NULL); - chip = snd_magic_kcalloc(vx_core_t, extra_size, GFP_KERNEL); + chip = kcalloc(1, sizeof(chip) + extra_size, GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "vx_core: no memory\n"); return NULL; --- linux-2.6.8-rc1/sound/drivers/vx/vx_hwdep.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/sound/drivers/vx/vx_hwdep.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,7 +44,7 @@ static int vx_hwdep_dsp_status(snd_hwdep [VX_TYPE_VXPOCKET] = "vxpocket", [VX_TYPE_VXP440] = "vxp440", }; - vx_core_t *vx = snd_magic_cast(vx_core_t, hw->private_data, return -ENXIO); + vx_core_t *vx = hw->private_data; snd_assert(type_ids[vx->type], return -EINVAL); strcpy(info->id, type_ids[vx->type]); @@ -60,7 +60,7 @@ static int vx_hwdep_dsp_status(snd_hwdep static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) { - vx_core_t *vx = snd_magic_cast(vx_core_t, hw->private_data, return -ENXIO); + vx_core_t *vx = hw->private_data; int index, err; snd_assert(vx->ops->load_dsp, return -ENXIO); --- linux-2.6.8-rc1/sound/drivers/vx/vx_mixer.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/drivers/vx/vx_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,8 +26,6 @@ #include #include "vx_cmd.h" -#define chip_t vx_core_t - /* * write a codec data (24bit) @@ -524,6 +522,54 @@ static snd_kcontrol_new_t vx_control_aud }; /* + * clock mode selection + */ +static int vx_clock_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[3] = { + "Auto", "Internal", "External" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} + +static int vx_clock_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + ucontrol->value.enumerated.item[0] = chip->clock_mode; + return 0; +} + +static int vx_clock_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + down(&chip->mixer_mutex); + if (chip->clock_mode != ucontrol->value.enumerated.item[0]) { + chip->clock_mode = ucontrol->value.enumerated.item[0]; + vx_set_clock(chip, chip->freq); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_clock_mode = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Mode", + .info = vx_clock_mode_info, + .get = vx_clock_mode_get, + .put = vx_clock_mode_put, +}; + +/* * Audio Gain */ static int vx_audio_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -913,6 +959,9 @@ int snd_vx_mixer_new(vx_core_t *chip) /* Audio source */ if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0) return err; + /* clock mode */ + if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0) + return err; /* IEC958 controls */ if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0) return err; --- linux-2.6.8-rc1/sound/drivers/vx/vx_pcm.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/drivers/vx/vx_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -48,14 +48,13 @@ #include #include #include +#include #include #include #include #include #include "vx_cmd.h" -#define chip_t vx_core_t - /* * we use a vmalloc'ed (sg-)buffer @@ -381,7 +380,7 @@ static int vx_send_irqa(vx_core_t *chip) */ static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state) { - int err, i, cur_state, delay; + int err, i, cur_state; /* Check the pipe is not already in the requested state */ if (vx_get_pipe_state(chip, pipe, &cur_state) < 0) @@ -394,17 +393,14 @@ static int vx_toggle_pipe(vx_core_t *chi * enough sound buffer for this pipe) */ if (state) { - int delay = CAN_START_DELAY; for (i = 0 ; i < MAX_WAIT_FOR_DSP; i++) { - snd_vx_delay(chip, delay); err = vx_pipe_can_start(chip, pipe); if (err > 0) break; /* Wait for a few, before asking again * to avoid flooding the DSP with our requests */ - if ((i % 4 ) == 0) - delay <<= 1; + mdelay(1); } } @@ -418,15 +414,12 @@ static int vx_toggle_pipe(vx_core_t *chi * reaching the expected state before returning * Check one pipe only (since they are synchronous) */ - delay = WAIT_STATE_DELAY; for (i = 0; i < MAX_WAIT_FOR_DSP; i++) { - snd_vx_delay(chip, delay); err = vx_get_pipe_state(chip, pipe, &cur_state); if (err < 0 || cur_state == state) break; err = -EIO; - if ((i % 4 ) == 0) - delay <<= 1; + mdelay(1); } return err < 0 ? -EIO : 0; } @@ -480,7 +473,7 @@ static int vx_alloc_pipe(vx_core_t *chip return err; /* initialize the pipe record */ - pipe = snd_magic_kcalloc(vx_pipe_t, 0, GFP_KERNEL); + pipe = kcalloc(1, sizeof(*pipe), GFP_KERNEL); if (! pipe) { /* release the pipe */ vx_init_rmh(&rmh, CMD_FREE_PIPE); @@ -514,7 +507,7 @@ static int vx_free_pipe(vx_core_t *chip, vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); vx_send_msg(chip, &rmh); - snd_magic_kfree(pipe); + kfree(pipe); return 0; } @@ -629,7 +622,7 @@ static int vx_pcm_playback_close(snd_pcm if (! subs->runtime->private_data) return -EINVAL; - pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + pipe = subs->runtime->private_data; if (--pipe->references == 0) { chip->playback_pipes[pipe->number] = 0; @@ -778,8 +771,8 @@ static void vx_pcm_playback_update(vx_co static void vx_pcm_delayed_start(unsigned long arg) { snd_pcm_substream_t *subs = (snd_pcm_substream_t *)arg; - vx_core_t *chip = snd_magic_cast(vx_core_t, subs->pcm->private_data, return); - vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return); + vx_core_t *chip = subs->pcm->private_data; + vx_pipe_t *pipe = subs->runtime->private_data; int err; /* printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/ @@ -801,7 +794,7 @@ static void vx_pcm_delayed_start(unsigne static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd) { vx_core_t *chip = snd_pcm_substream_chip(subs); - vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + vx_pipe_t *pipe = subs->runtime->private_data; int err; if (chip->chip_status & VX_STAT_IS_STALE) @@ -846,7 +839,7 @@ static int vx_pcm_trigger(snd_pcm_substr static snd_pcm_uframes_t vx_pcm_playback_pointer(snd_pcm_substream_t *subs) { snd_pcm_runtime_t *runtime = subs->runtime; - vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + vx_pipe_t *pipe = runtime->private_data; return pipe->position; } @@ -874,7 +867,7 @@ static int vx_pcm_prepare(snd_pcm_substr { vx_core_t *chip = snd_pcm_substream_chip(subs); snd_pcm_runtime_t *runtime = subs->runtime; - vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + vx_pipe_t *pipe = runtime->private_data; int err, data_mode; // int max_size, nchunks; @@ -1037,7 +1030,7 @@ static int vx_pcm_capture_close(snd_pcm_ if (! subs->runtime->private_data) return -EINVAL; - pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + pipe = subs->runtime->private_data; chip->capture_pipes[pipe->number] = 0; pipe_out_monitoring = pipe->monitoring_pipe; @@ -1141,7 +1134,7 @@ static void vx_pcm_capture_update(vx_cor static snd_pcm_uframes_t vx_pcm_capture_pointer(snd_pcm_substream_t *subs) { snd_pcm_runtime_t *runtime = subs->runtime; - vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + vx_pipe_t *pipe = runtime->private_data; return bytes_to_frames(runtime, pipe->hw_ptr); } @@ -1265,7 +1258,7 @@ static int vx_init_audio_io(vx_core_t *c */ static void snd_vx_pcm_free(snd_pcm_t *pcm) { - vx_core_t *chip = snd_magic_cast(vx_core_t, pcm->private_data, return); + vx_core_t *chip = pcm->private_data; chip->pcm[pcm->device] = NULL; if (chip->playback_pipes) { kfree(chip->playback_pipes); --- linux-2.6.8-rc1/sound/drivers/vx/vx_uer.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/sound/drivers/vx/vx_uer.c 2004-07-13 17:09:19.000000000 -0700 @@ -263,17 +263,17 @@ int vx_set_clock(vx_core_t *chip, unsign /* change the audio source if possible */ vx_sync_audio_source(chip); - switch (chip->audio_source) { - case VX_AUDIO_SRC_DIGITAL: + if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL || + (chip->clock_mode == VX_CLOCK_MODE_AUTO && + chip->audio_source == VX_AUDIO_SRC_DIGITAL)) { if (chip->clock_source != UER_SYNC) { vx_change_clock_source(chip, UER_SYNC); mdelay(6); src_changed = 1; } - if (chip->freq == freq) - return 0; - break; - default: + } else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL || + (chip->clock_mode == VX_CLOCK_MODE_AUTO && + chip->audio_source != VX_AUDIO_SRC_DIGITAL)) { if (chip->clock_source != INTERNAL_QUARTZ) { vx_change_clock_source(chip, INTERNAL_QUARTZ); src_changed = 1; @@ -283,8 +283,9 @@ int vx_set_clock(vx_core_t *chip, unsign vx_set_internal_clock(chip, freq); if (src_changed) vx_modify_board_inputs(chip); - break; } + if (chip->freq == freq) + return 0; chip->freq = freq; vx_modify_board_clock(chip, 1); return 0; --- linux-2.6.8-rc1/sound/i2c/cs8427.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/i2c/cs8427.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,8 +34,6 @@ MODULE_AUTHOR("Jaroslav Kysela >1) /* fixed address */ typedef struct { @@ -109,7 +107,7 @@ int snd_cs8427_reg_read(snd_i2c_device_t static int snd_cs8427_select_corudata(snd_i2c_device_t *device, int udata) { - cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); + cs8427_t *chip = device->private_data; int err; udata = udata ? CS8427_BSEL : 0; @@ -128,7 +126,7 @@ static int snd_cs8427_send_corudata(snd_ unsigned char *ndata, int count) { - cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); + cs8427_t *chip = device->private_data; char *hw_data = udata ? chip->playback.hw_udata : chip->playback.hw_status; char data[32]; int err, idx; @@ -159,7 +157,7 @@ static int snd_cs8427_send_corudata(snd_ static void snd_cs8427_free(snd_i2c_device_t *device) { if (device->private_data) - snd_magic_kfree(device->private_data); + kfree(device->private_data); } int snd_cs8427_create(snd_i2c_bus_t *bus, @@ -211,7 +209,7 @@ int snd_cs8427_create(snd_i2c_bus_t *bus if ((err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7), &device)) < 0) return err; - chip = device->private_data = snd_magic_kcalloc(cs8427_t, 0, GFP_KERNEL); + chip = device->private_data = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) { snd_i2c_device_free(device); return -ENOMEM; @@ -297,7 +295,7 @@ void snd_cs8427_reset(snd_i2c_device_t * int data; snd_assert(cs8427, return); - chip = snd_magic_cast(cs8427_t, cs8427->private_data, return); + chip = cs8427->private_data; snd_i2c_lock(cs8427->bus); chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK); snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]); @@ -389,7 +387,7 @@ static int snd_cs8427_spdif_get(snd_kcon snd_ctl_elem_value_t * ucontrol) { snd_i2c_device_t *device = snd_kcontrol_chip(kcontrol); - cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); + cs8427_t *chip = device->private_data; snd_i2c_lock(device->bus); memcpy(ucontrol->value.iec958.status, chip->playback.def_status, 24); @@ -401,7 +399,7 @@ static int snd_cs8427_spdif_put(snd_kcon snd_ctl_elem_value_t * ucontrol) { snd_i2c_device_t *device = snd_kcontrol_chip(kcontrol); - cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); + cs8427_t *chip = device->private_data; unsigned char *status = kcontrol->private_value ? chip->playback.pcm_status : chip->playback.def_status; snd_pcm_runtime_t *runtime = chip->playback.substream ? chip->playback.substream->runtime : NULL; int err, change; @@ -487,7 +485,7 @@ int snd_cs8427_iec958_build(snd_i2c_devi snd_pcm_substream_t *play_substream, snd_pcm_substream_t *cap_substream) { - cs8427_t *chip = snd_magic_cast(cs8427_t, cs8427->private_data, return -ENXIO); + cs8427_t *chip = cs8427->private_data; snd_kcontrol_t *kctl; unsigned int idx; int err; @@ -517,7 +515,7 @@ int snd_cs8427_iec958_active(snd_i2c_dev cs8427_t *chip; snd_assert(cs8427, return -ENXIO); - chip = snd_magic_cast(cs8427_t, cs8427->private_data, return -ENXIO); + chip = cs8427->private_data; if (active) memcpy(chip->playback.pcm_status, chip->playback.def_status, 24); chip->playback.pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; @@ -533,7 +531,7 @@ int snd_cs8427_iec958_pcm(snd_i2c_device int err, reset; snd_assert(cs8427, return -ENXIO); - chip = snd_magic_cast(cs8427_t, cs8427->private_data, return -ENXIO); + chip = cs8427->private_data; status = chip->playback.pcm_status; snd_i2c_lock(cs8427->bus); if (status[0] & IEC958_AES0_PROFESSIONAL) { --- linux-2.6.8-rc1/sound/i2c/i2c.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/i2c/i2c.c 2004-07-13 17:09:19.000000000 -0700 @@ -62,13 +62,13 @@ static int snd_i2c_bus_free(snd_i2c_bus_ } if (bus->private_free) bus->private_free(bus); - snd_magic_kfree(bus); + kfree(bus); return 0; } static int snd_i2c_bus_dev_free(snd_device_t *device) { - snd_i2c_bus_t *bus = snd_magic_cast(snd_i2c_bus_t, device->device_data, return -ENXIO); + snd_i2c_bus_t *bus = device->device_data; return snd_i2c_bus_free(bus); } @@ -81,7 +81,7 @@ int snd_i2c_bus_create(snd_card_t *card, }; *ri2c = NULL; - bus = (snd_i2c_bus_t *)snd_magic_kcalloc(snd_i2c_bus_t, 0, GFP_KERNEL); + bus = kcalloc(1, sizeof(*bus), GFP_KERNEL); if (bus == NULL) return -ENOMEM; init_MUTEX(&bus->lock_mutex); @@ -108,7 +108,7 @@ int snd_i2c_device_create(snd_i2c_bus_t *rdevice = NULL; snd_assert(bus != NULL, return -EINVAL); - device = (snd_i2c_device_t *)snd_magic_kcalloc(snd_i2c_device_t, 0, GFP_KERNEL); + device = kcalloc(1, sizeof(*device), GFP_KERNEL); if (device == NULL) return -ENOMEM; device->addr = addr; @@ -125,7 +125,7 @@ int snd_i2c_device_free(snd_i2c_device_t list_del(&device->list); if (device->private_free) device->private_free(device); - snd_magic_kfree(device); + kfree(device); return 0; } --- linux-2.6.8-rc1/sound/i2c/l3/uda1341.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/i2c/l3/uda1341.c 2004-07-13 17:09:19.000000000 -0700 @@ -17,7 +17,7 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ -/* $Id: uda1341.c,v 1.10 2003/10/23 14:34:52 perex Exp $ */ +/* $Id: uda1341.c,v 1.12 2004/07/01 08:33:42 tiwai Exp $ */ #include #include @@ -131,7 +131,6 @@ struct uda1341 { //hack for ALSA magic casting typedef struct l3_client l3_client_t; -#define chip_t l3_client_t /* transfer 8bit integer into string with binary representation */ void int2str_bin8(uint8_t val, char *buf){ @@ -332,7 +331,7 @@ int snd_uda1341_cfg_write(struct l3_clie static void snd_uda1341_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - struct l3_client *clnt = snd_magic_cast(l3_client_t, entry->private_data, return); + struct l3_client *clnt = entry->private_data; struct uda1341 *uda = clnt->driver_data; int peak; @@ -397,7 +396,7 @@ static void snd_uda1341_proc_read(snd_in static void snd_uda1341_proc_regs_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - struct l3_client *clnt = snd_magic_cast(l3_client_t, entry->private_data, return); + struct l3_client *clnt = entry->private_data; struct uda1341 *uda = clnt->driver_data; int reg; char buf[12]; @@ -653,12 +652,12 @@ static snd_kcontrol_new_t snd_uda1341_co static void uda1341_free(struct l3_client *uda1341) { l3_detach_client(uda1341); // calls kfree for driver_data (uda1341_t) - snd_magic_kfree(uda1341); + kfree(uda1341); } static int uda1341_dev_free(snd_device_t *device) { - struct l3_client *clnt = snd_magic_cast(l3_client_t, device->device_data, return); + struct l3_client *clnt = device->device_data; uda1341_free(clnt); return 0; } @@ -673,7 +672,7 @@ int __init snd_chip_uda1341_mixer_new(sn snd_assert(card != NULL, return -EINVAL); - uda1341 = snd_magic_kcalloc(l3_client_t, 0, GFP_KERNEL); + uda1341 = kcalloc(1, sizeof(*uda1341), GFP_KERNEL); if (uda1341 == NULL) return -ENOMEM; @@ -710,7 +709,7 @@ static int uda1341_attach(struct l3_clie { struct uda1341 *uda; - uda = snd_magic_kcalloc(uda1341_t, 0, GFP_KERNEL); + uda = kcalloc(1, sizeof(*uda), 0, GFP_KERNEL); if (!uda) return -ENOMEM; @@ -734,7 +733,7 @@ static int uda1341_attach(struct l3_clie static void uda1341_detach(struct l3_client *clnt) { if (clnt->driver_data) - snd_magic_kfree(clnt->driver_data); + kfree(clnt->driver_data); } static int @@ -821,8 +820,7 @@ module_exit(uda1341_exit); MODULE_AUTHOR("Tomas Kasparek "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Philips UDA1341 CODEC driver for ALSA"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{UDA1341,UDA1341TS}}"); +MODULE_SUPPORTED_DEVICE("{{UDA1341,UDA1341TS}}"); EXPORT_SYMBOL(snd_chip_uda1341_mixer_new); --- linux-2.6.8-rc1/sound/i2c/other/ak4117.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/i2c/other/ak4117.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,8 +33,6 @@ MODULE_AUTHOR("Jaroslav Kysela timer); - snd_magic_kfree(chip); + kfree(chip); } static int snd_ak4117_dev_free(snd_device_t *device) { - ak4117_t *chip = snd_magic_cast(ak4117_t, device->device_data, return -ENXIO); + ak4117_t *chip = device->device_data; snd_ak4117_free(chip); return 0; } @@ -85,7 +83,7 @@ int snd_ak4117_create(snd_card_t *card, .dev_free = snd_ak4117_dev_free, }; - chip = (ak4117_t *)snd_magic_kcalloc(ak4117_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->lock); @@ -544,7 +542,7 @@ int snd_ak4117_check_rate_and_errors(ak4 static void snd_ak4117_timer(unsigned long data) { - ak4117_t *chip = snd_magic_cast(ak4117_t, (void *)data, return); + ak4117_t *chip = (ak4117_t *)data; if (chip->init) return; --- linux-2.6.8-rc1/sound/i2c/other/ak4xxx-adda.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/i2c/other/ak4xxx-adda.c 2004-07-13 17:09:19.000000000 -0700 @@ -237,7 +237,7 @@ static int snd_akm4xxx_volume_info(snd_k static int snd_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value); @@ -250,7 +250,7 @@ static int snd_akm4xxx_volume_get(snd_kc static int snd_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); int invert = AK_GET_INVERT(kcontrol->private_value); @@ -277,7 +277,7 @@ static int snd_akm4xxx_ipga_gain_info(sn static int snd_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f; @@ -286,7 +286,7 @@ static int snd_akm4xxx_ipga_gain_get(snd static int snd_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; @@ -312,7 +312,7 @@ static int snd_akm4xxx_deemphasis_info(s static int snd_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); int shift = AK_GET_SHIFT(kcontrol->private_value); @@ -322,7 +322,7 @@ static int snd_akm4xxx_deemphasis_get(sn static int snd_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); int chip = AK_GET_CHIP(kcontrol->private_value); int addr = AK_GET_ADDR(kcontrol->private_value); int shift = AK_GET_SHIFT(kcontrol->private_value); --- linux-2.6.8-rc1/sound/i2c/tea6330t.c 2003-06-14 12:18:20.000000000 -0700 +++ 25/sound/i2c/tea6330t.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,6 @@ MODULE_AUTHOR("Jaroslav Kysela >1) /* fixed address */ #define TEA6330T_SADDR_VOLUME_LEFT 0x00 /* volume left */ @@ -270,8 +268,8 @@ TEA6330T_TREBLE("Tone Control - Treble", static void snd_tea6330_free(snd_i2c_device_t *device) { - tea6330t_t *tea = snd_magic_cast(tea6330t_t, device->private_data, return); - snd_magic_kfree(tea); + tea6330t_t *tea = device->private_data; + kfree(tea); } int snd_tea6330t_update_mixer(snd_card_t * card, @@ -286,11 +284,11 @@ int snd_tea6330t_update_mixer(snd_card_t u8 default_treble, default_bass; unsigned char bytes[7]; - tea = snd_magic_kcalloc(tea6330t_t, 0, GFP_KERNEL); + tea = kcalloc(1, sizeof(*tea), GFP_KERNEL); if (tea == NULL) return -ENOMEM; if ((err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device)) < 0) { - snd_magic_kfree(tea); + kfree(tea); return err; } tea->device = device; --- linux-2.6.8-rc1/sound/isa/ad1816a/ad1816a.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/ad1816a/ad1816a.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,15 +30,12 @@ #include #include -#define chip_t ad1816a_t - #define PFX "ad1816a: " MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("AD1816A, AD1815"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Highscreen,Sound-Boostar 16 3D}," +MODULE_SUPPORTED_DEVICE("{{Highscreen,Sound-Boostar 16 3D}," "{Analog Devices,AD1815}," "{Analog Devices,AD1816A}," "{TerraTec,Base 64}," @@ -60,34 +57,24 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for ad1816a driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ad1816a driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for ad1816a driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for ad1816a driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ad1816a driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); struct snd_card_ad1816a { struct pnp_dev *dev; --- linux-2.6.8-rc1/sound/isa/ad1816a/ad1816a_lib.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/isa/ad1816a/ad1816a_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,8 +34,6 @@ MODULE_AUTHOR("Massimo Piccioni lock); @@ -550,13 +548,13 @@ static int snd_ad1816a_free(ad1816a_t *c snd_dma_disable(chip->dma2); free_dma(chip->dma2); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_ad1816a_dev_free(snd_device_t *device) { - ad1816a_t *chip = snd_magic_cast(ad1816a_t, device->device_data, return -ENXIO); + ad1816a_t *chip = device->device_data; return snd_ad1816a_free(chip); } @@ -585,7 +583,7 @@ int snd_ad1816a_create(snd_card_t *card, *rchip = NULL; - chip = snd_magic_kcalloc(ad1816a_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->irq = -1; @@ -661,7 +659,7 @@ static snd_pcm_ops_t snd_ad1816a_capture static void snd_ad1816a_pcm_free(snd_pcm_t *pcm) { - ad1816a_t *chip = snd_magic_cast(ad1816a_t, pcm->private_data, return); + ad1816a_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -696,7 +694,7 @@ int snd_ad1816a_pcm(ad1816a_t *chip, int static void snd_ad1816a_timer_free(snd_timer_t *timer) { - ad1816a_t *chip = snd_magic_cast(ad1816a_t, timer->private_data, return); + ad1816a_t *chip = timer->private_data; chip->timer = NULL; } --- linux-2.6.8-rc1/sound/isa/ad1848/ad1848.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/ad1848/ad1848.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,13 +30,10 @@ #include #include -#define chip_t ad1848_t - MODULE_AUTHOR("Tugrul Galatali , Jaroslav Kysela "); MODULE_DESCRIPTION("AD1848/AD1847/CS4248"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Analog Devices,AD1848}," +MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848}," "{Analog Devices,AD1847}," "{Crystal Semiconductors,CS4248}}"); @@ -51,25 +48,18 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for AD1848 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for AD1848 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable AD1848 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for AD1848 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for AD1848 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for AD1848 driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(thinkpad, bool, boot_devs, 0444); MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series."); -MODULE_PARM_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); static snd_card_t *snd_ad1848_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/ad1848/ad1848_lib.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/ad1848/ad1848_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -39,8 +39,6 @@ MODULE_AUTHOR("Jaroslav Kysela mode & AD1848_MODE_PLAY) && chip->playback_substream && (chip->mode & AD1848_MODE_RUNNING)) @@ -649,7 +647,7 @@ static void snd_ad1848_thinkpad_twiddle( #ifdef CONFIG_PM static int snd_ad1848_suspend(snd_card_t *card, unsigned int state) { - ad1848_t *chip = snd_magic_cast(ad1848_t, card->pm_private_data, return -EINVAL); + ad1848_t *chip = card->pm_private_data; if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; @@ -666,7 +664,7 @@ static int snd_ad1848_suspend(snd_card_t static int snd_ad1848_resume(snd_card_t *card, unsigned int state) { - ad1848_t *chip = snd_magic_cast(ad1848_t, card->pm_private_data, return -EINVAL); + ad1848_t *chip = card->pm_private_data; if (card->power_state == SNDRV_CTL_POWER_D0) return 0; @@ -867,13 +865,13 @@ static int snd_ad1848_free(ad1848_t *chi snd_dma_disable(chip->dma); free_dma(chip->dma); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_ad1848_dev_free(snd_device_t *device) { - ad1848_t *chip = snd_magic_cast(ad1848_t, device->device_data, return -ENXIO); + ad1848_t *chip = device->device_data; return snd_ad1848_free(chip); } @@ -901,7 +899,7 @@ int snd_ad1848_create(snd_card_t * card, int err; *rchip = NULL; - chip = snd_magic_kcalloc(ad1848_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -977,7 +975,7 @@ static snd_pcm_ops_t snd_ad1848_capture_ static void snd_ad1848_pcm_free(snd_pcm_t *pcm) { - ad1848_t *chip = snd_magic_cast(ad1848_t, pcm->private_data, return); + ad1848_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } --- linux-2.6.8-rc1/sound/isa/als100.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/als100.c 2004-07-13 17:09:19.000000000 -0700 @@ -32,15 +32,12 @@ #include #include -#define chip_t sb_t - #define PFX "als100: " MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("Avance Logic ALS1X0"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Avance Logic,ALS100 - PRO16PNP}," +MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," "{Avance Logic,ALS110}," "{Avance Logic,ALS120}," "{Avance Logic,ALS200}," @@ -63,34 +60,24 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for als100 based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for als100 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for als100 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for als100 driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for als100 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for als100 driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for als100 driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); module_param_array(dma16, int, boot_devs, 0444); MODULE_PARM_DESC(dma16, "16-bit DMA # for als100 driver."); -MODULE_PARM_SYNTAX(dma16, SNDRV_DMA16_DESC); struct snd_card_als100 { int dev_no; --- linux-2.6.8-rc1/sound/isa/azt2320.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/azt2320.c 2004-07-13 17:09:19.000000000 -0700 @@ -43,15 +43,12 @@ #include #include -#define chip_t cs4231_t - #define PFX "azt2320: " MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("Aztech Systems AZT2320"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Aztech Systems,PRO16V}," +MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V}," "{Aztech Systems,AZT2320}," "{Aztech Systems,AZT3300}," "{Aztech Systems,AZT2320}," @@ -72,37 +69,26 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for azt2320 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(wss_port, long, boot_devs, 0444); MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver."); -MODULE_PARM_SYNTAX(wss_port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); struct snd_card_azt2320 { int dev_no; --- linux-2.6.8-rc1/sound/isa/cmi8330.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/cmi8330.c 2004-07-13 17:09:19.000000000 -0700 @@ -63,8 +63,7 @@ MODULE_AUTHOR("George Talusan "); MODULE_DESCRIPTION("C-Media CMI8330"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); +MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -83,41 +82,30 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for CMI8330 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable CMI8330 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(sbport, long, boot_devs, 0444); MODULE_PARM_DESC(sbport, "Port # for CMI8330 SB driver."); -MODULE_PARM_SYNTAX(sbport, SNDRV_ENABLED ",allows:{{0x220,0x280,0x20}},prefers:{0x220},base:16,dialog:list"); module_param_array(sbirq, int, boot_devs, 0444); MODULE_PARM_DESC(sbirq, "IRQ # for CMI8330 SB driver."); -MODULE_PARM_SYNTAX(sbirq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10},{11},{12}},prefers:{5},dialog:list"); module_param_array(sbdma8, int, boot_devs, 0444); MODULE_PARM_DESC(sbdma8, "DMA8 for CMI8330 SB driver."); -MODULE_PARM_SYNTAX(sbdma8, SNDRV_DMA8_DESC ",prefers:{1}"); module_param_array(sbdma16, int, boot_devs, 0444); MODULE_PARM_DESC(sbdma16, "DMA16 for CMI8330 SB driver."); -MODULE_PARM_SYNTAX(sbdma16, SNDRV_ENABLED ",allows:{{5},{7}},prefers:{5},dialog:list"); module_param_array(wssport, long, boot_devs, 0444); MODULE_PARM_DESC(wssport, "Port # for CMI8330 WSS driver."); -MODULE_PARM_SYNTAX(wssport, SNDRV_ENABLED ",allows:{{0x530},{0xe80,0xf40,0xc0}},prefers:{0x530},base:16,dialog:list"); module_param_array(wssirq, int, boot_devs, 0444); MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver."); -MODULE_PARM_SYNTAX(wssirq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10},{11},{12}},prefers:{11},dialog:list"); module_param_array(wssdma, int, boot_devs, 0444); MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver."); -MODULE_PARM_SYNTAX(wssdma, SNDRV_DMA8_DESC ",prefers:{0}"); #define CMI8330_RMUX3D 16 #define CMI8330_MUTEMUX 17 @@ -385,7 +373,7 @@ static int __devinit snd_cmi8330_pnp(int static int snd_cmi8330_playback_open(snd_pcm_substream_t * substream) { - struct snd_cmi8330 *chip = (struct snd_cmi8330 *)_snd_pcm_substream_chip(substream); + struct snd_cmi8330 *chip = snd_pcm_substream_chip(substream); /* replace the private_data and call the original open callback */ substream->private_data = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].private_data; @@ -394,7 +382,7 @@ static int snd_cmi8330_playback_open(snd static int snd_cmi8330_capture_open(snd_pcm_substream_t * substream) { - struct snd_cmi8330 *chip = (struct snd_cmi8330 *)_snd_pcm_substream_chip(substream); + struct snd_cmi8330 *chip = snd_pcm_substream_chip(substream); /* replace the private_data and call the original open callback */ substream->private_data = chip->streams[SNDRV_PCM_STREAM_CAPTURE].private_data; --- linux-2.6.8-rc1/sound/isa/cs423x/cs4231.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/cs423x/cs4231.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,13 +30,10 @@ #include #include -#define chip_t cs4231_t - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Generic CS4231"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Crystal Semiconductors,CS4231}}"); +MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4231}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -51,31 +48,22 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for CS4231 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for CS4231 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable CS4231 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for CS4231 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for CS4231 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for CS4231 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for CS4231 driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for CS4231 driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for CS4231 driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); static snd_card_t *snd_cs4231_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/cs423x/cs4231_lib.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/cs423x/cs4231_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -43,8 +43,6 @@ MODULE_AUTHOR("Jaroslav Kysela pm_private_data, return -EINVAL); + cs4231_t *chip = card->pm_private_data; if (chip->suspend) { chip->suspend(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -1417,7 +1415,7 @@ static int snd_cs4231_pm_suspend(snd_car static int snd_cs4231_pm_resume(snd_card_t *card, unsigned int state) { - cs4231_t *chip = snd_magic_cast(cs4231_t, card->pm_private_data, return -EINVAL); + cs4231_t *chip = card->pm_private_data; if (chip->resume) { chip->resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -1453,13 +1451,13 @@ static int snd_cs4231_free(cs4231_t *chi } if (chip->timer) snd_device_free(chip->card, chip->timer); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_cs4231_dev_free(snd_device_t *device) { - cs4231_t *chip = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO); + cs4231_t *chip = device->device_data; return snd_cs4231_free(chip); } @@ -1493,7 +1491,7 @@ static int snd_cs4231_new(snd_card_t * c cs4231_t *chip; *rchip = NULL; - chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->hardware = hardware; @@ -1626,7 +1624,7 @@ static snd_pcm_ops_t snd_cs4231_capture_ static void snd_cs4231_pcm_free(snd_pcm_t *pcm) { - cs4231_t *chip = snd_magic_cast(cs4231_t, pcm->private_data, return); + cs4231_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1686,7 +1684,7 @@ int snd_cs4231_pcm(cs4231_t *chip, int d static void snd_cs4231_timer_free(snd_timer_t *timer) { - cs4231_t *chip = snd_magic_cast(cs4231_t, timer->private_data, return); + cs4231_t *chip = timer->private_data; chip->timer = NULL; } --- linux-2.6.8-rc1/sound/isa/cs423x/cs4236.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/cs423x/cs4236.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,14 +30,11 @@ #include #include -#define chip_t cs4231_t - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); #ifdef CS4232 MODULE_DESCRIPTION("Cirrus Logic CS4232"); -MODULE_DEVICES("{{Turtle Beach,TBS-2000}," +MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000}," "{Turtle Beach,Tropez Plus}," "{SIC CrystalWave 32}," "{Hewlett Packard,Omnibook 5500}," @@ -45,7 +42,7 @@ MODULE_DEVICES("{{Turtle Beach,TBS-2000} "{Philips,PCA70PS}}"); #else MODULE_DESCRIPTION("Cirrus Logic CS4235-9"); -MODULE_DEVICES("{{Crystal Semiconductors,CS4235}," +MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235}," "{Crystal Semiconductors,CS4236}," "{Crystal Semiconductors,CS4237}," "{Crystal Semiconductors,CS4238}," @@ -99,45 +96,32 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " IDENT " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " IDENT " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " IDENT " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for " IDENT " driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(cport, long, boot_devs, 0444); MODULE_PARM_DESC(cport, "Control port # for " IDENT " driver."); -MODULE_PARM_SYNTAX(cport, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " IDENT " driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for " IDENT " driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(sb_port, long, boot_devs, 0444); MODULE_PARM_DESC(sb_port, "SB port # for " IDENT " driver (optional)."); -MODULE_PARM_SYNTAX(sb_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for " IDENT " driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " IDENT " driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); struct snd_card_cs4236 { struct resource *res_sb_port; --- linux-2.6.8-rc1/sound/isa/cs423x/cs4236_lib.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/sound/isa/cs423x/cs4236_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -93,8 +93,6 @@ MODULE_AUTHOR("Jaroslav Kysela #include -#define chip_t sb_t - #define PFX "dt019x: " MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Diamond Technologies DT-019X}," +MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," "{Avance Logic ALS-007}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -57,31 +54,22 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for dt019x driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for dt019x driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for dt019x driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for dt019x driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for dt019x driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for dt019x driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); struct snd_card_dt019x { struct pnp_dev *dev; --- linux-2.6.8-rc1/sound/isa/es1688/es1688.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/es1688/es1688.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,8 +37,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ESS ESx688 AudioDrive"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100}," +MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100}," "{ESS,ES1688 PnP AudioDrive,pnp:ESS0102}," "{ESS,ES688 AudioDrive,pnp:ESS6881}," "{ESS,ES1688 AudioDrive,pnp:ESS1681}}"); @@ -55,28 +54,20 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ESx688 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ESx688 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ESx688 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for ESx688 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ESx688 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for ESx688 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ESx688 driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for ESx688 driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); static snd_card_t *snd_audiodrive_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/es1688/es1688_lib.c 2004-05-09 21:07:28.000000000 -0700 +++ 25/sound/isa/es1688/es1688_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,7 +34,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ESS ESx688 lowlevel module"); -MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); static int snd_es1688_dsp_command(es1688_t *chip, unsigned char val) @@ -482,7 +481,7 @@ static int snd_es1688_capture_trigger(sn irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - es1688_t *chip = snd_magic_cast(es1688_t, dev_id, return IRQ_NONE); + es1688_t *chip = dev_id; if (chip->trigger_value == 0x05) /* ok.. playback is active */ snd_pcm_period_elapsed(chip->playback_substream); @@ -616,13 +615,13 @@ static int snd_es1688_free(es1688_t *chi disable_dma(chip->dma8); free_dma(chip->dma8); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_es1688_dev_free(snd_device_t *device) { - es1688_t *chip = snd_magic_cast(es1688_t, device->device_data, return -ENXIO); + es1688_t *chip = device->device_data; return snd_es1688_free(chip); } @@ -650,7 +649,7 @@ int snd_es1688_create(snd_card_t * card, int err; *rchip = NULL; - chip = snd_magic_kcalloc(es1688_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->irq = -1; @@ -728,7 +727,7 @@ static snd_pcm_ops_t snd_es1688_capture_ static void snd_es1688_pcm_free(snd_pcm_t *pcm) { - es1688_t *chip = snd_magic_cast(es1688_t, pcm->private_data, return); + es1688_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } --- linux-2.6.8-rc1/sound/isa/es18xx.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/es18xx.c 2004-07-13 17:09:19.000000000 -0700 @@ -157,8 +157,6 @@ struct _snd_es18xx { typedef struct _snd_es18xx es18xx_t; -#define chip_t es18xx_t - /* Lowlevel */ #define DAC1 0x01 @@ -728,7 +726,7 @@ static int snd_es18xx_playback_trigger(s static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - es18xx_t *chip = snd_magic_cast(es18xx_t, dev_id, return IRQ_NONE); + es18xx_t *chip = dev_id; unsigned char status; if (chip->caps & ES18XX_CONTROL) { @@ -1027,7 +1025,7 @@ static int snd_es18xx_get_hw_switch(snd_ static void snd_es18xx_hwv_free(snd_kcontrol_t *kcontrol) { - es18xx_t *chip = snd_magic_cast(es18xx_t, _snd_kcontrol_chip(kcontrol), return); + es18xx_t *chip = snd_kcontrol_chip(kcontrol); chip->master_volume = NULL; chip->master_switch = NULL; chip->hw_volume = NULL; @@ -1561,7 +1559,7 @@ static snd_pcm_ops_t snd_es18xx_capture_ static void snd_es18xx_pcm_free(snd_pcm_t *pcm) { - es18xx_t *codec = snd_magic_cast(es18xx_t, pcm->private_data, return); + es18xx_t *codec = pcm->private_data; codec->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1611,7 +1609,7 @@ int __devinit snd_es18xx_pcm(es18xx_t *c #ifdef CONFIG_PM static int snd_es18xx_suspend(snd_card_t *card, unsigned int state) { - es18xx_t *chip = snd_magic_cast(es18xx_t, card->pm_private_data, return -EINVAL); + es18xx_t *chip = card->pm_private_data; snd_pcm_suspend_all(chip->pcm); @@ -1627,7 +1625,7 @@ static int snd_es18xx_suspend(snd_card_t static int snd_es18xx_resume(snd_card_t *card, unsigned int state) { - es18xx_t *chip = snd_magic_cast(es18xx_t, card->pm_private_data, return -EINVAL); + es18xx_t *chip = card->pm_private_data; /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); @@ -1661,13 +1659,13 @@ static int snd_es18xx_free(es18xx_t *chi disable_dma(chip->dma2); free_dma(chip->dma2); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_es18xx_dev_free(snd_device_t *device) { - es18xx_t *chip = snd_magic_cast(es18xx_t, device->device_data, return -ENXIO); + es18xx_t *chip = device->device_data; return snd_es18xx_free(chip); } @@ -1685,7 +1683,7 @@ static int __devinit snd_es18xx_new_devi int err; *rchip = NULL; - chip = snd_magic_kcalloc(es18xx_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -1830,8 +1828,7 @@ static int __devinit snd_es18xx_mixer(es MODULE_AUTHOR("Christian Fischbach , Abramo Bagnara "); MODULE_DESCRIPTION("ESS ES18xx AudioDrive"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ESS,ES1868 PnP AudioDrive}," +MODULE_SUPPORTED_DEVICE("{{ESS,ES1868 PnP AudioDrive}," "{ESS,ES1869 PnP AudioDrive}," "{ESS,ES1878 PnP AudioDrive}," "{ESS,ES1879 PnP AudioDrive}," @@ -1860,36 +1857,26 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ES18xx soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ES18xx soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ES18xx soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for ES18xx driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x280,0x20}},prefers:{0x220},base:16,dialog:list"); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ES18xx driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x300,0x330,0x30},{0x800,0xffe,0x2}},prefers:{0x330,0x300},base:16,dialog:combo"); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for ES18xx driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388},{0x800,0xffc,0x4}},prefers:{0x388},base:16,dialog:combo"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for ES18xx driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC ",prefers:{5}"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA 1 # for ES18xx driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA8_DESC ",prefers:{1}"); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{0},{1},{3},{5}},dialog:list,prefers:{0}"); struct snd_audiodrive { #ifdef CONFIG_PNP --- linux-2.6.8-rc1/sound/isa/gus/gusclassic.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gusclassic.c 2004-07-13 17:09:19.000000000 -0700 @@ -35,8 +35,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Gravis UltraSound Classic"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Gravis,UltraSound Classic}}"); +MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -53,34 +52,24 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for GUS Classic soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for GUS Classic soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable GUS Classic soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for GUS Classic driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x260,0x10}},dialog:list"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for GUS Classic driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for GUS Classic driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list"); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for GUS Classic driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list"); module_param_array(joystick_dac, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Classic driver."); -MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}"); module_param_array(channels, int, boot_devs, 0444); MODULE_PARM_DESC(channels, "GF1 channels for GUS Classic driver."); -MODULE_PARM_SYNTAX(channels, SNDRV_ENABLED ",allows:{{14,32}}"); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Classic driver."); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}"); static snd_card_t *snd_gusclassic_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/gus/gusextreme.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gusextreme.c 2004-07-13 17:09:19.000000000 -0700 @@ -38,8 +38,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Gravis UltraSound Extreme"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Gravis,UltraSound Extreme}}"); +MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -60,46 +59,32 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for GUS Extreme soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for GUS Extreme soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable GUS Extreme soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220,0x260,0x20}},dialog:list"); module_param_array(gf1_port, long, boot_devs, 0444); MODULE_PARM_DESC(gf1_port, "GF1 port # for GUS Extreme driver (optional)."); -MODULE_PARM_SYNTAX(gf1_port, SNDRV_ENABLED ",allows:{{0x210,0x270,0x10}},dialog:list"); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x300,0x320,0x10}},dialog:list"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10}},dialog:list"); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{10}},dialog:list"); module_param_array(gf1_irq, int, boot_devs, 0444); MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(gf1_irq, SNDRV_ENABLED ",allows:{{2},{3},{5},{9},{11},{12},{15}},dialog:list"); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "GF1 DMA # for GUS Extreme driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(joystick_dac, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS Extreme driver."); -MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}"); module_param_array(channels, int, boot_devs, 0444); MODULE_PARM_DESC(channels, "GF1 channels for GUS Extreme driver."); -MODULE_PARM_SYNTAX(channels, SNDRV_ENABLED ",allows:{{14,32}}"); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Extreme driver."); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}"); static snd_card_t *snd_gusextreme_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/gus/gus_instr.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gus_instr.c 2004-07-13 17:09:19.000000000 -0700 @@ -31,7 +31,7 @@ int snd_gus_iwffff_put_sample(void *private_data, iwffff_wave_t *wave, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; snd_gf1_mem_block_t *block; int err; @@ -61,7 +61,7 @@ int snd_gus_iwffff_put_sample(void *priv int snd_gus_iwffff_get_sample(void *private_data, iwffff_wave_t *wave, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, wave->format & IWFFFF_WAVE_ROM ? 1 : 0); @@ -70,7 +70,7 @@ int snd_gus_iwffff_get_sample(void *priv int snd_gus_iwffff_remove_sample(void *private_data, iwffff_wave_t *wave, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; if (wave->format & IWFFFF_WAVE_ROM) return 0; /* it's probably ok - verify the address? */ @@ -84,7 +84,7 @@ int snd_gus_iwffff_remove_sample(void *p int snd_gus_gf1_put_sample(void *private_data, gf1_wave_t *wave, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; snd_gf1_mem_block_t *block; int err; @@ -112,7 +112,7 @@ int snd_gus_gf1_put_sample(void *private int snd_gus_gf1_get_sample(void *private_data, gf1_wave_t *wave, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0); } @@ -120,7 +120,7 @@ int snd_gus_gf1_get_sample(void *private int snd_gus_gf1_remove_sample(void *private_data, gf1_wave_t *wave, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory); } @@ -132,7 +132,7 @@ int snd_gus_gf1_remove_sample(void *priv int snd_gus_simple_put_sample(void *private_data, simple_instrument_t *instr, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; snd_gf1_mem_block_t *block; int err; @@ -159,7 +159,7 @@ int snd_gus_simple_put_sample(void *priv int snd_gus_simple_get_sample(void *private_data, simple_instrument_t *instr, char __user *data, long len, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0); } @@ -167,7 +167,7 @@ int snd_gus_simple_get_sample(void *priv int snd_gus_simple_remove_sample(void *private_data, simple_instrument_t *instr, int atomic) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return -ENXIO); + snd_gus_card_t *gus = private_data; return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory); } --- linux-2.6.8-rc1/sound/isa/gus/gus_irq.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/gus/gus_irq.c 2004-07-13 17:09:19.000000000 -0700 @@ -32,7 +32,7 @@ irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - snd_gus_card_t * gus = snd_magic_cast(snd_gus_card_t, dev_id, return IRQ_NONE); + snd_gus_card_t * gus = dev_id; unsigned char status; int loop = 100; int handled = 0; @@ -114,7 +114,7 @@ static void snd_gus_irq_info_read(snd_in snd_gus_voice_t *pvoice; int idx; - gus = snd_magic_cast(snd_gus_card_t, entry->private_data, return); + gus = entry->private_data; snd_iprintf(buffer, "midi out = %u\n", gus->gf1.interrupt_stat_midi_out); snd_iprintf(buffer, "midi in = %u\n", gus->gf1.interrupt_stat_midi_in); snd_iprintf(buffer, "timer1 = %u\n", gus->gf1.interrupt_stat_timer1); --- linux-2.6.8-rc1/sound/isa/gus/gus_main.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/gus/gus_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -35,8 +35,6 @@ MODULE_AUTHOR("Jaroslav Kysela gf1.dma2); free_dma(gus->gf1.dma2); } - snd_magic_kfree(gus); + kfree(gus); return 0; } static int snd_gus_dev_free(snd_device_t *device) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, device->device_data, return -ENXIO); + snd_gus_card_t *gus = device->device_data; return snd_gus_free(gus); } @@ -159,7 +157,7 @@ int snd_gus_create(snd_card_t * card, }; *rgus = NULL; - gus = snd_magic_kcalloc(snd_gus_card_t, 0, GFP_KERNEL); + gus = kcalloc(1, sizeof(*gus), GFP_KERNEL); if (gus == NULL) return -ENOMEM; gus->gf1.irq = -1; @@ -421,7 +419,7 @@ static int snd_gus_check_version(snd_gus static void snd_gus_seq_dev_free(snd_seq_device_t *seq_dev) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, seq_dev->private_data, return); + snd_gus_card_t *gus = seq_dev->private_data; gus->seq_dev = NULL; } --- linux-2.6.8-rc1/sound/isa/gus/gusmax.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gusmax.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,8 +36,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Gravis UltraSound MAX"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Gravis,UltraSound MAX}}"); +MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -54,34 +53,24 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for GUS MAX soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for GUS MAX soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable GUS MAX soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for GUS MAX driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220},{0x230},{0x240},{0x250},{0x260}},dialog:list"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for GUS MAX driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for GUS MAX driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for GUS MAX driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); module_param_array(joystick_dac, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for GUS MAX driver."); -MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}"); module_param_array(channels, int, boot_devs, 0444); MODULE_PARM_DESC(channels, "Used GF1 channels for GUS MAX driver."); -MODULE_PARM_SYNTAX(channels, SNDRV_ENABLED ",allows:{{14,32}}"); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS MAX driver."); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}"); struct snd_gusmax { int irq; --- linux-2.6.8-rc1/sound/isa/gus/gus_mem.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/gus/gus_mem.c 2004-07-13 17:09:19.000000000 -0700 @@ -297,7 +297,7 @@ static void snd_gf1_mem_info_read(snd_in unsigned int total, used; int i; - gus = snd_magic_cast(snd_gus_card_t, entry->private_data, return); + gus = entry->private_data; alloc = &gus->gf1.mem_alloc; down(&alloc->memory_mutex); snd_iprintf(buffer, "8-bit banks : \n "); --- linux-2.6.8-rc1/sound/isa/gus/gus_mem_proc.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gus_mem_proc.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,7 +36,7 @@ static long snd_gf1_mem_proc_dump(snd_in struct file *file, char __user *buf, long count) { long size; - gus_proc_private_t *priv = snd_magic_cast(gus_proc_private_t, entry->private_data, return -ENXIO); + gus_proc_private_t *priv = entry->private_data; snd_gus_card_t *gus = priv->gus; int err; @@ -58,7 +58,7 @@ static long long snd_gf1_mem_proc_llseek long long offset, int orig) { - gus_proc_private_t *priv = snd_magic_cast(gus_proc_private_t, entry->private_data, return -ENXIO); + gus_proc_private_t *priv = entry->private_data; switch (orig) { case 0: /* SEEK_SET */ @@ -80,8 +80,8 @@ static long long snd_gf1_mem_proc_llseek static void snd_gf1_mem_proc_free(snd_info_entry_t *entry) { - gus_proc_private_t *priv = snd_magic_cast(gus_proc_private_t, entry->private_data, return); - snd_magic_kfree(priv); + gus_proc_private_t *priv = entry->private_data; + kfree(priv); } static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { @@ -98,7 +98,7 @@ int snd_gf1_mem_proc_init(snd_gus_card_t for (idx = 0; idx < 4; idx++) { if (gus->gf1.mem_alloc.banks_8[idx].size > 0) { - priv = snd_magic_kcalloc(gus_proc_private_t, 0, GFP_KERNEL); + priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; priv->gus = gus; @@ -115,7 +115,7 @@ int snd_gf1_mem_proc_init(snd_gus_card_t } for (idx = 0; idx < 4; idx++) { if (gus->gf1.rom_present & (1 << idx)) { - priv = snd_magic_kcalloc(gus_proc_private_t, 0, GFP_KERNEL); + priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; priv->rom = 1; --- linux-2.6.8-rc1/sound/isa/gus/gus_mixer.c 2003-06-14 12:17:57.000000000 -0700 +++ 25/sound/isa/gus/gus_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,8 +26,6 @@ #include #include -#define chip_t snd_gus_card_t - /* * */ --- linux-2.6.8-rc1/sound/isa/gus/gus_pcm.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/gus/gus_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,8 +34,6 @@ #include #include "gus_tables.h" -#define chip_t snd_gus_card_t - /* maximum rate */ #define SNDRV_GF1_PCM_RATE 48000 @@ -66,7 +64,7 @@ static int snd_gf1_pcm_use_dma = 1; static void snd_gf1_pcm_block_change_ack(snd_gus_card_t * gus, void *private_data) { - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, private_data, return); + gus_pcm_private_t *pcmp = private_data; if (pcmp) { atomic_dec(&pcmp->dma_count); @@ -81,7 +79,7 @@ static int snd_gf1_pcm_block_change(snd_ { snd_gf1_dma_block_t block; snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; count += offset & 31; offset &= ~31; @@ -106,7 +104,7 @@ static int snd_gf1_pcm_block_change(snd_ static void snd_gf1_pcm_trigger_up(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return); + gus_pcm_private_t *pcmp = runtime->private_data; snd_gus_card_t * gus = pcmp->gus; unsigned long flags; unsigned char voice_ctrl, ramp_ctrl; @@ -194,7 +192,7 @@ static void snd_gf1_pcm_interrupt_wave(s snd_gf1_smart_stop_voice(gus, pvoice->number); return; } - pcmp = snd_magic_cast(gus_pcm_private_t, pvoice->private_data, return); + pcmp = pvoice->private_data; if (pcmp == NULL) { snd_printd("snd_gf1_pcm: unknown wave irq?\n"); snd_gf1_smart_stop_voice(gus, pvoice->number); @@ -267,7 +265,7 @@ static void snd_gf1_pcm_interrupt_volume { unsigned short vol; int cvoice; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, pvoice->private_data, return); + gus_pcm_private_t *pcmp = pvoice->private_data; /* stop ramp, but leave rollover bit untouched */ spin_lock(&gus->reg_lock); @@ -350,7 +348,7 @@ static int snd_gf1_pcm_playback_copy(snd snd_pcm_uframes_t count) { snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; unsigned int bpos, len; bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); @@ -379,7 +377,7 @@ static int snd_gf1_pcm_playback_silence( snd_pcm_uframes_t count) { snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; unsigned int bpos, len; bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); @@ -406,7 +404,7 @@ static int snd_gf1_pcm_playback_hw_param { snd_gus_card_t *gus = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) @@ -453,7 +451,7 @@ static int snd_gf1_pcm_playback_hw_param static int snd_gf1_pcm_playback_hw_free(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; snd_pcm_lib_free_pages(substream); if (pcmp->pvoices[0]) { @@ -474,7 +472,7 @@ static int snd_gf1_pcm_playback_hw_free( static int snd_gf1_pcm_playback_prepare(snd_pcm_substream_t * substream) { snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; pcmp->bpos = 0; pcmp->dma_size = snd_pcm_lib_buffer_bytes(substream); @@ -488,7 +486,7 @@ static int snd_gf1_pcm_playback_trigger( { snd_gus_card_t *gus = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; int voice; if (cmd == SNDRV_PCM_TRIGGER_START) { @@ -513,7 +511,7 @@ static snd_pcm_uframes_t snd_gf1_pcm_pla { snd_gus_card_t *gus = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; unsigned int pos; unsigned char voice_ctrl; @@ -657,8 +655,8 @@ static snd_pcm_hardware_t snd_gf1_pcm_ca static void snd_gf1_pcm_playback_free(snd_pcm_runtime_t *runtime) { - gus_pcm_private_t * pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return); - snd_magic_kfree(pcmp); + gus_pcm_private_t * pcmp = runtime->private_data; + kfree(pcmp); } static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) @@ -668,7 +666,7 @@ static int snd_gf1_pcm_playback_open(snd snd_pcm_runtime_t *runtime = substream->runtime; int err; - pcmp = snd_magic_kcalloc(gus_pcm_private_t, 0, GFP_KERNEL); + pcmp = kcalloc(1, sizeof(*pcmp), GFP_KERNEL); if (pcmp == NULL) return -ENOMEM; pcmp->gus = gus; @@ -697,7 +695,7 @@ static int snd_gf1_pcm_playback_close(sn { snd_gus_card_t *gus = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - gus_pcm_private_t *pcmp = snd_magic_cast(gus_pcm_private_t, runtime->private_data, return -ENXIO); + gus_pcm_private_t *pcmp = runtime->private_data; unsigned long jiffies_old; jiffies_old = jiffies; @@ -738,7 +736,7 @@ static int snd_gf1_pcm_capture_close(snd static void snd_gf1_pcm_free(snd_pcm_t *pcm) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, pcm->private_data, return); + snd_gus_card_t *gus = pcm->private_data; gus->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -790,7 +788,7 @@ static int snd_gf1_pcm_volume_put(snd_kc pvoice = &gus->gf1.voices[idx]; if (!pvoice->pcm) continue; - pcmp = snd_magic_cast(gus_pcm_private_t, pvoice->private_data, return -ENXIO); + pcmp = pvoice->private_data; if (!(pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE)) continue; /* load real volume - better precision */ --- linux-2.6.8-rc1/sound/isa/gus/gus_synth.c 2003-06-14 12:18:22.000000000 -0700 +++ 25/sound/isa/gus/gus_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -134,7 +134,7 @@ static void snd_gus_synth_instr_notify(v int what) { unsigned int idx; - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, private_data, return); + snd_gus_card_t *gus = private_data; snd_gus_voice_t *pvoice; unsigned long flags; --- linux-2.6.8-rc1/sound/isa/gus/gus_timer.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/sound/isa/gus/gus_timer.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,8 +26,6 @@ #include #include -#define chip_t snd_gus_card_t - /* * Timer 1 - 80us */ @@ -146,13 +144,13 @@ static struct _snd_timer_hardware snd_gf static void snd_gf1_timer1_free(snd_timer_t *timer) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, timer->private_data, return); + snd_gus_card_t *gus = timer->private_data; gus->gf1.timer1 = NULL; } static void snd_gf1_timer2_free(snd_timer_t *timer) { - snd_gus_card_t *gus = snd_magic_cast(snd_gus_card_t, timer->private_data, return); + snd_gus_card_t *gus = timer->private_data; gus->gf1.timer2 = NULL; } --- linux-2.6.8-rc1/sound/isa/gus/gus_uart.c 2003-06-14 12:18:04.000000000 -0700 +++ 25/sound/isa/gus/gus_uart.c 2004-07-13 17:09:19.000000000 -0700 @@ -95,7 +95,7 @@ static int snd_gf1_uart_output_open(snd_ unsigned long flags; snd_gus_card_t *gus; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return -ENXIO); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (!(gus->gf1.uart_cmd & 0x80)) { /* input active? */ snd_gf1_uart_reset(gus, 0); @@ -115,7 +115,7 @@ static int snd_gf1_uart_input_open(snd_r snd_gus_card_t *gus; int i; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return -ENXIO); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) { snd_gf1_uart_reset(gus, 0); @@ -141,7 +141,7 @@ static int snd_gf1_uart_output_close(snd unsigned long flags; snd_gus_card_t *gus; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return -ENXIO); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (gus->gf1.interrupt_handler_midi_in != snd_gf1_interrupt_midi_in) snd_gf1_uart_reset(gus, 1); @@ -156,7 +156,7 @@ static int snd_gf1_uart_input_close(snd_ unsigned long flags; snd_gus_card_t *gus; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return -ENXIO); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (gus->gf1.interrupt_handler_midi_out != snd_gf1_interrupt_midi_out) snd_gf1_uart_reset(gus, 1); @@ -171,7 +171,7 @@ static void snd_gf1_uart_input_trigger(s snd_gus_card_t *gus; unsigned long flags; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (up) { @@ -191,7 +191,7 @@ static void snd_gf1_uart_output_trigger( char byte; int timeout; - gus = snd_magic_cast(snd_gus_card_t, substream->rmidi->private_data, return); + gus = substream->rmidi->private_data; spin_lock_irqsave(&gus->uart_cmd_lock, flags); if (up) { --- linux-2.6.8-rc1/sound/isa/gus/interwave.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/isa/gus/interwave.c 2004-07-13 17:09:19.000000000 -0700 @@ -41,18 +41,17 @@ #include MODULE_AUTHOR("Jaroslav Kysela "); -MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); #ifndef SNDRV_STB MODULE_DESCRIPTION("AMD InterWave"); -MODULE_DEVICES("{{Gravis,UltraSound Plug & Play}," +MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Plug & Play}," "{STB,SoundRage32}," "{MED,MED3210}," "{Dynasonix,Dynasonix Pro}," "{Panasonic,PCA761AW}}"); #else MODULE_DESCRIPTION("AMD InterWave STB with TEA6330T"); -MODULE_DEVICES("{{AMD,InterWave STB with TEA6330T}}"); +MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}"); #endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -77,10 +76,8 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for InterWave soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for InterWave soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable InterWave soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); @@ -91,33 +88,24 @@ MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_ #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for InterWave driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x210,0x260,0x10}},dialog:list"); #ifdef SNDRV_STB module_param_array(port_tc, long, boot_devs, 0444); MODULE_PARM_DESC(port_tc, "Tone control (TEA6330T - i2c bus) port # for InterWave driver."); -MODULE_PARM_SYNTAX(port_tc, SNDRV_ENABLED ",allows:{{0x350,0x380,0x10}},dialog:list"); #endif module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for InterWave driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{3},{5},{9},{11},{12},{15}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for InterWave driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for InterWave driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); module_param_array(joystick_dac, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for InterWave driver."); -MODULE_PARM_SYNTAX(joystick_dac, SNDRV_ENABLED ",allows:{{0,31}}"); module_param_array(midi, int, boot_devs, 0444); MODULE_PARM_DESC(midi, "MIDI UART enable for InterWave driver."); -MODULE_PARM_SYNTAX(midi, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for InterWave driver."); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",allows:{{2,16}}"); module_param_array(effect, int, boot_devs, 0444); MODULE_PARM_DESC(effect, "Effects enable for InterWave driver."); -MODULE_PARM_SYNTAX(effect, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); struct snd_interwave { int irq; --- linux-2.6.8-rc1/sound/isa/gus/Makefile 2003-06-14 12:18:50.000000000 -0700 +++ 25/sound/isa/gus/Makefile 2004-07-13 17:09:19.000000000 -0700 @@ -27,14 +27,10 @@ sequencer = $(if $(subst y,,$(CONFIG_SND # Toplevel Module Dependency obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o -obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += snd-gus-synth.o obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o -obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += snd-gus-synth.o obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o -obj-$(call sequencer,$(CONFIG_SND_GUSEXTREME)) += snd-gus-synth.o obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE)) += snd-gus-synth.o obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o -obj-$(call sequencer,$(CONFIG_SND_INTERWAVE_STB)) += snd-gus-synth.o +obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o obj-m := $(sort $(obj-m)) --- linux-2.6.8-rc1/sound/isa/Kconfig 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/isa/Kconfig 2004-07-13 17:09:19.000000000 -0700 @@ -77,11 +77,15 @@ config SND_ES18XX help Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips. +config SND_GUS_SYNTH + tristate + config SND_GUSCLASSIC tristate "Gravis UltraSound Classic" depends on SND select SND_RAWMIDI select SND_PCM + select SND_GUS_SYNTH help Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard. @@ -91,6 +95,7 @@ config SND_GUSEXTREME select SND_HWDEP select SND_MPU401_UART select SND_PCM + select SND_GUS_SYNTH help Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard. @@ -99,6 +104,7 @@ config SND_GUSMAX depends on SND select SND_RAWMIDI select SND_PCM + select SND_GUS_SYNTH help Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard. @@ -107,6 +113,7 @@ config SND_INTERWAVE depends on SND select SND_RAWMIDI select SND_PCM + select SND_GUS_SYNTH help Say 'Y' or 'M' to include support for AMD InterWave based soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro, @@ -117,6 +124,7 @@ config SND_INTERWAVE_STB depends on SND select SND_RAWMIDI select SND_PCM + select SND_GUS_SYNTH help Say 'Y' or 'M' to include support for AMD InterWave based soundcards with TEA6330T bass and treble regulator (UltraSound 32-Pro). --- linux-2.6.8-rc1/sound/isa/opl3sa2.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/opl3sa2.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,8 +37,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Yamaha OPL3SA2+"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Yamaha,YMF719E-S}," +MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S}," "{Genius,Sound Maker 3DX}," "{Yamaha,OPL3SA3}," "{Intel,AL440LX sound}," @@ -63,45 +62,32 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for OPL3-SA soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable OPL3-SA soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0xf86},{0x370},{0x100}},dialog:list"); module_param_array(sb_port, long, boot_devs, 0444); MODULE_PARM_DESC(sb_port, "SB port # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(sb_port, SNDRV_ENABLED ",allows:{{0x220},{0x240},{0x260}},dialog:list"); module_param_array(wss_port, long, boot_devs, 0444); MODULE_PARM_DESC(wss_port, "WSS port # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(wss_port, SNDRV_ENABLED ",allows:{{0x530},{0xe80},{0xf40},{0x604}},dialog:list"); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388}},dialog:list"); module_param_array(midi_port, long, boot_devs, 0444); MODULE_PARM_DESC(midi_port, "MIDI port # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(midi_port, SNDRV_ENABLED ",allows:{{0x330},{0x300}},dialog:list"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{0},{1},{3},{5},{9},{11},{12},{15}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list"); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for OPL3-SA driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_ENABLED ",allows:{{1},{3},{5},{6},{7}},dialog:list"); module_param_array(opl3sa3_ymode, int, boot_devs, 0444); MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi."); -MODULE_PARM_SYNTAX(opl3sa3_ymode, SNDRV_ENABLED ",allows:{{0,3}},dialog:list"); /* SL Added */ /* control ports */ #define OPL3SA2_PM_CTRL 0x01 @@ -131,7 +117,6 @@ MODULE_PARM_SYNTAX(opl3sa3_ymode, SNDRV_ #define OPL3SA2_PM_D3 (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX) typedef struct snd_opl3sa2 opl3sa2_t; -#define chip_t opl3sa2_t struct snd_opl3sa2 { snd_card_t *card; @@ -304,7 +289,7 @@ static int __init snd_opl3sa2_detect(opl static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned short status; - opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, dev_id, return IRQ_NONE); + opl3sa2_t *chip = dev_id; int handled = 0; if (chip == NULL || chip->card == NULL) @@ -496,7 +481,7 @@ OPL3SA2_DOUBLE("Tone Control - Treble", static void snd_opl3sa2_master_free(snd_kcontrol_t *kcontrol) { - opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, _snd_kcontrol_chip(kcontrol), return); + opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); chip->master_switch = NULL; chip->master_volume = NULL; } @@ -551,7 +536,7 @@ static int __init snd_opl3sa2_mixer(opl3 #ifdef CONFIG_PM static int snd_opl3sa2_suspend(snd_card_t *card, unsigned int state) { - opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, card->pm_private_data, return -EINVAL); + opl3sa2_t *chip = card->pm_private_data; snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */ chip->cs4231_suspend(chip->cs4231); @@ -565,7 +550,7 @@ static int snd_opl3sa2_suspend(snd_card_ static int snd_opl3sa2_resume(snd_card_t *card, unsigned int state) { - opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, card->pm_private_data, return -EINVAL); + opl3sa2_t *chip = card->pm_private_data; int i; /* power up */ @@ -656,13 +641,13 @@ static int snd_opl3sa2_free(opl3sa2_t *c release_resource(chip->res_port); kfree_nocheck(chip->res_port); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_opl3sa2_dev_free(snd_device_t *device) { - opl3sa2_t *chip = snd_magic_cast(opl3sa2_t, device->device_data, return -ENXIO); + opl3sa2_t *chip = device->device_data; return snd_opl3sa2_free(chip); } @@ -707,7 +692,7 @@ static int __devinit snd_opl3sa2_probe(i return -ENOMEM; strcpy(card->driver, "OPL3SA2"); strcpy(card->shortname, "Yamaha OPL3-SA2"); - chip = snd_magic_kcalloc(opl3sa2_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) { err = -ENOMEM; goto __error; --- linux-2.6.8-rc1/sound/isa/opti9xx/opti92x-ad1848.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/opti9xx/opti92x-ad1848.c 2004-07-13 17:09:19.000000000 -0700 @@ -52,19 +52,18 @@ #include MODULE_AUTHOR("Massimo Piccioni "); -MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); #ifdef OPTi93X MODULE_DESCRIPTION("OPTi93X"); -MODULE_DEVICES("{{OPTi,82C931/3}}"); +MODULE_SUPPORTED_DEVICE("{{OPTi,82C931/3}}"); #else /* OPTi93X */ #ifdef CS4231 MODULE_DESCRIPTION("OPTi92X - CS4231"); -MODULE_DEVICES("{{OPTi,82C924 (CS4231)}," +MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (CS4231)}," "{OPTi,82C925 (CS4231)}}"); #else /* CS4231 */ MODULE_DESCRIPTION("OPTi92X - AD1848"); -MODULE_DEVICES("{{OPTi,82C924 (AD1848)}," +MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)}," "{OPTi,82C925 (AD1848)}," "{OAK,Mozart}}"); #endif /* CS4231 */ @@ -86,38 +85,27 @@ static int dma2 = SNDRV_DEFAULT_DMA1; / module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for opti9xx based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); //module_param(enable, bool, 0444); //MODULE_PARM_DESC(enable, "Enable opti9xx soundcard."); -//MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param(isapnp, bool, 0444); MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); module_param(port, long, 0444); MODULE_PARM_DESC(port, "WSS port # for opti9xx driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT_DESC); module_param(mpu_port, long, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for opti9xx driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC); module_param(fm_port, long, 0444); MODULE_PARM_DESC(fm_port, "FM port # for opti9xx driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT_DESC); module_param(irq, int, 0444); MODULE_PARM_DESC(irq, "WSS irq # for opti9xx driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param(mpu_irq, int, 0444); MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for opti9xx driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param(dma1, int, 0444); MODULE_PARM_DESC(dma1, "1st dma # for opti9xx driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); #if defined(CS4231) || defined(OPTi93X) module_param(dma2, int, 0444); MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); #endif /* CS4231 || OPTi93X */ #define OPTi9XX_HW_DETECT 0 @@ -474,7 +462,6 @@ static int __devinit snd_opti9xx_configu unsigned char dma_bits; unsigned char mpu_port_bits = 0; unsigned char mpu_irq_bits; - unsigned long flags; switch (chip->hardware) { #ifndef OPTi93X @@ -601,13 +588,11 @@ __skip_base: dma_bits |= 0x04; #endif /* CS4231 || OPTi93X */ - spin_lock_irqsave(&chip->lock, flags); #ifndef OPTi93X outb(irq_bits << 3 | dma_bits, chip->wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ - spin_unlock_irqrestore(&chip->lock, flags); __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { @@ -664,8 +649,6 @@ __skip_mpu: #ifdef OPTi93X -#define chip_t opti93x_t - static unsigned char snd_opti93x_default_image[32] = { 0x00, /* 00/00 - l_mixout_outctrl */ @@ -767,15 +750,10 @@ static void snd_opti93x_mce_down(opti93x static void snd_opti93x_mute(opti93x_t *chip, int mute) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); - mute = mute ? 1 : 0; - if (chip->mute == mute) { - spin_unlock_irqrestore(&chip->lock, flags); + if (chip->mute == mute) return; - } + chip->mute = mute; snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); @@ -800,8 +778,6 @@ static void snd_opti93x_mute(opti93x_t * snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute); - - spin_unlock_irqrestore(&chip->lock, flags); } @@ -873,10 +849,8 @@ static unsigned char snd_opti93x_get_for static void snd_opti93x_playback_format(opti93x_t *chip, unsigned char fmt) { - unsigned long flags; unsigned char mask; - spin_lock_irqsave(&chip->lock, flags); snd_opti93x_mute(chip, 1); snd_opti93x_mce_up(chip); @@ -885,14 +859,10 @@ static void snd_opti93x_playback_format( snd_opti93x_mce_down(chip); snd_opti93x_mute(chip, 0); - spin_unlock_irqrestore(&chip->lock, flags); } static void snd_opti93x_capture_format(opti93x_t *chip, unsigned char fmt) { - unsigned long flags; - - spin_lock_irqsave(&chip->lock, flags); snd_opti93x_mute(chip, 1); snd_opti93x_mce_up(chip); @@ -904,7 +874,6 @@ static void snd_opti93x_capture_format(o snd_opti93x_mce_down(chip); snd_opti93x_mute(chip, 0); - spin_unlock_irqrestore(&chip->lock, flags); } @@ -1128,7 +1097,7 @@ static void snd_opti93x_overrange(opti93 irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - opti93x_t *codec = snd_magic_cast(opti93x_t, dev_id, return IRQ_NONE); + opti93x_t *codec = dev_id; unsigned char status; status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); @@ -1274,13 +1243,13 @@ static int snd_opti93x_free(opti93x_t *c if (chip->irq >= 0) { free_irq(chip->irq, chip); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_opti93x_dev_free(snd_device_t *device) { - opti93x_t *chip = snd_magic_cast(opti93x_t, device->device_data, return -ENXIO); + opti93x_t *chip = device->device_data; return snd_opti93x_free(chip); } @@ -1305,7 +1274,7 @@ int snd_opti93x_create(snd_card_t *card, opti93x_t *codec; *rcodec = NULL; - codec = snd_magic_kcalloc(opti93x_t, 0, GFP_KERNEL); + codec = kcalloc(1, sizeof(*codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; codec->irq = -1; @@ -1385,7 +1354,7 @@ static snd_pcm_ops_t snd_opti93x_capture static void snd_opti93x_pcm_free(snd_pcm_t *pcm) { - opti93x_t *codec = snd_magic_cast(opti93x_t, pcm->private_data, return); + opti93x_t *codec = pcm->private_data; codec->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } --- linux-2.6.8-rc1/sound/isa/sb/emu8000.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/sb/emu8000.c 2004-07-13 17:09:19.000000000 -0700 @@ -821,8 +821,6 @@ snd_emu8000_update_reverb_mode(emu8000_t * mixer interface *----------------------------------------------------------------*/ -#define chip_t emu8000_t - /* * bass/treble */ @@ -1070,7 +1068,7 @@ static int snd_emu8000_free(emu8000_t *h release_resource(hw->res_port3); kfree_nocheck(hw->res_port3); } - snd_magic_kfree(hw); + kfree(hw); return 0; } @@ -1078,7 +1076,7 @@ static int snd_emu8000_free(emu8000_t *h */ static int snd_emu8000_dev_free(snd_device_t *device) { - emu8000_t *hw = snd_magic_cast(emu8000_t, device->device_data, return -ENXIO); + emu8000_t *hw = device->device_data; return snd_emu8000_free(hw); } @@ -1101,7 +1099,7 @@ snd_emu8000_new(snd_card_t *card, int in if (seq_ports <= 0) return 0; - hw = snd_magic_kcalloc(emu8000_t, 0, GFP_KERNEL); + hw = kcalloc(1, sizeof(*hw), GFP_KERNEL); if (hw == NULL) return -ENOMEM; spin_lock_init(&hw->reg_lock); --- linux-2.6.8-rc1/sound/isa/sb/emu8000_callback.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/sb/emu8000_callback.c 2004-07-13 17:09:19.000000000 -0700 @@ -94,7 +94,7 @@ release_voice(snd_emux_voice_t *vp) int dcysusv; emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, vp->hw, return); + hw = vp->hw; dcysusv = 0x8000 | (unsigned char)vp->reg.parm.modrelease; EMU8000_DCYSUS_WRITE(hw, vp->ch, dcysusv); dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease; @@ -109,7 +109,7 @@ terminate_voice(snd_emux_voice_t *vp) { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, vp->hw, return); + hw = vp->hw; EMU8000_DCYSUSV_WRITE(hw, vp->ch, 0x807F); } @@ -121,7 +121,7 @@ update_voice(snd_emux_voice_t *vp, int u { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, vp->hw, return); + hw = vp->hw; if (update & SNDRV_EMUX_UPDATE_VOLUME) set_volume(hw, vp); if (update & SNDRV_EMUX_UPDATE_PITCH) @@ -168,7 +168,7 @@ get_voice(snd_emux_t *emu, snd_emux_port } best[END]; struct best *bp; - hw = snd_magic_cast(emu8000_t, emu->hw, return NULL); + hw = emu->hw; for (i = 0; i < END; i++) { best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */; @@ -235,7 +235,7 @@ start_voice(snd_emux_voice_t *vp) snd_midi_channel_t *chan; emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, vp->hw, return -EINVAL); + hw = vp->hw; ch = vp->ch; chan = vp->chan; @@ -313,7 +313,7 @@ trigger_voice(snd_emux_voice_t *vp) unsigned int temp; emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, vp->hw, return); + hw = vp->hw; /* set reverb and pitch target */ temp = vp->reg.parm.reverb; @@ -333,7 +333,7 @@ reset_voice(snd_emux_t *emu, int ch) { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, emu->hw, return); + hw = emu->hw; EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F); snd_emu8000_tweak_voice(hw, ch); } @@ -457,7 +457,7 @@ sysex(snd_emux_t *emu, char *buf, int le { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, emu->hw, return); + hw = emu->hw; switch (parsed) { case SNDRV_MIDI_SYSEX_GS_CHORUS_MODE: @@ -482,7 +482,7 @@ oss_ioctl(snd_emux_t *emu, int cmd, int { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, emu->hw, return -EINVAL); + hw = emu->hw; switch (cmd) { case _EMUX_OSS_REVERB_MODE: @@ -526,7 +526,7 @@ static int load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len) { emu8000_t *hw; - hw = snd_magic_cast(emu8000_t, emu->hw, return -EINVAL); + hw = emu->hw; switch (type) { case SNDRV_EMU8000_LOAD_CHORUS_FX: --- linux-2.6.8-rc1/sound/isa/sb/emu8000_patch.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/emu8000_patch.c 2004-07-13 17:09:19.000000000 -0700 @@ -155,7 +155,7 @@ snd_emu8000_sample_new(snd_emux_t *rec, int dram_offset, dram_start; emu8000_t *emu; - emu = snd_magic_cast(emu8000_t, rec->hw, return -EINVAL); + emu = rec->hw; snd_assert(sp != NULL, return -EINVAL); if (sp->v.size == 0) --- linux-2.6.8-rc1/sound/isa/sb/emu8000_pcm.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/emu8000_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -23,8 +23,6 @@ #include #include -#define chip_t emu8000_t - /* * define the following if you want to use this pcm with non-interleaved mode */ @@ -235,7 +233,7 @@ static int emu8k_pcm_open(snd_pcm_substr emu8k_pcm_t *rec; snd_pcm_runtime_t *runtime = subs->runtime; - rec = snd_kcalloc(sizeof(*rec), GFP_KERNEL); + rec = kcalloc(1, sizeof(*rec), GFP_KERNEL); if (! rec) return -ENOMEM; --- linux-2.6.8-rc1/sound/isa/sb/emu8000_synth.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/sb/emu8000_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -27,7 +27,6 @@ MODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe"); MODULE_DESCRIPTION("Emu8000 synth plug-in routine"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); /*----------------------------------------------------------------*/ --- linux-2.6.8-rc1/sound/isa/sb/es968.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/es968.c 2004-07-13 17:09:19.000000000 -0700 @@ -29,15 +29,12 @@ #include #include -#define chip_t sb_t - #define PFX "es968: " MODULE_AUTHOR("Massimo Piccioni "); MODULE_DESCRIPTION("ESS AudioDrive ES968"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ESS,AudioDrive ES968}}"); +MODULE_SUPPORTED_DEVICE("{{ESS,AudioDrive ES968}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -49,22 +46,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for es968 based soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for es968 based soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable es968 based soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for es968 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for es968 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); struct snd_card_es968 { struct pnp_dev *dev; @@ -82,7 +73,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_es968_ static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); + sb_t *chip = dev_id; if (chip->open & SB_OPEN_PCM) { return snd_sb8dsp_interrupt(chip); --- linux-2.6.8-rc1/sound/isa/sb/sb16.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/sb16.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,8 +37,6 @@ #define SNDRV_LEGACY_FIND_FREE_DMA #include -#define chip_t sb_t - #ifdef SNDRV_SBAWE #define PFX "sbawe: " #else @@ -47,17 +45,16 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); #ifndef SNDRV_SBAWE MODULE_DESCRIPTION("Sound Blaster 16"); -MODULE_DEVICES("{{Creative Labs,SB 16}," +MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 16}," "{Creative Labs,SB Vibra16S}," "{Creative Labs,SB Vibra16C}," "{Creative Labs,SB Vibra16CL}," "{Creative Labs,SB Vibra16X}}"); #else MODULE_DESCRIPTION("Sound Blaster AWE"); -MODULE_DEVICES("{{Creative Labs,SB AWE 32}," +MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32}," "{Creative Labs,SB AWE 64}," "{Creative Labs,SB AWE 64 Gold}}"); #endif @@ -96,53 +93,39 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for SB16 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED ",allows:{{0x220},{0x240},{0x260},{0x280}},dialog:list"); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0x330},{0x300}},dialog:list"); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0x388},{0x38c},{0x390},{0x394}},dialog:list"); #ifdef SNDRV_SBAWE_EMU8000 module_param_array(awe_port, long, boot_devs, 0444); MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver."); -MODULE_PARM_SYNTAX(awe_port, SNDRV_ENABLED ",allows:{{0x620},{0x640},{0x660},{0x680}},dialog:list"); #endif module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for SB16 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); module_param_array(dma16, int, boot_devs, 0444); MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver."); -MODULE_PARM_SYNTAX(dma16, SNDRV_DMA16_DESC); module_param_array(mic_agc, int, boot_devs, 0444); MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch."); -MODULE_PARM_SYNTAX(mic_agc, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); #ifdef CONFIG_SND_SB16_CSP module_param_array(csp, int, boot_devs, 0444); MODULE_PARM_DESC(csp, "ASP/CSP chip support."); -MODULE_PARM_SYNTAX(csp, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); #endif #ifdef SNDRV_SBAWE_EMU8000 module_param_array(seq_ports, int, boot_devs, 0444); MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth."); -MODULE_PARM_SYNTAX(seq_ports, SNDRV_ENABLED ",allows:{{0,8}},skill:advanced"); #endif struct snd_card_sb16 { --- linux-2.6.8-rc1/sound/isa/sb/sb16_csp.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/sb16_csp.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,12 +33,9 @@ #include #include -#define chip_t snd_sb_csp_t - MODULE_AUTHOR("Uros Bizjak "); MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); #ifdef SNDRV_LITTLE_ENDIAN #define CSP_HDR_VALUE(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) @@ -127,7 +124,7 @@ int snd_sb_csp_new(sb_t *chip, int devic if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0) return err; - if ((p = snd_magic_kcalloc(snd_sb_csp_t, 0, GFP_KERNEL)) == NULL) { + if ((p = kcalloc(1, sizeof(*p), GFP_KERNEL)) == NULL) { snd_device_free(chip->card, hw); return -ENOMEM; } @@ -165,11 +162,11 @@ int snd_sb_csp_new(sb_t *chip, int devic */ static void snd_sb_csp_free(snd_hwdep_t *hwdep) { - snd_sb_csp_t *p = snd_magic_cast(snd_sb_csp_t, hwdep->private_data, return); + snd_sb_csp_t *p = hwdep->private_data; if (p) { if (p->running & SNDRV_SB_CSP_ST_RUNNING) snd_sb_csp_stop(p); - snd_magic_kfree(p); + kfree(p); } } @@ -180,7 +177,7 @@ static void snd_sb_csp_free(snd_hwdep_t */ static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file) { - snd_sb_csp_t *p = snd_magic_cast(snd_sb_csp_t, hw->private_data, return -ENXIO); + snd_sb_csp_t *p = hw->private_data; return (snd_sb_csp_use(p)); } @@ -189,7 +186,7 @@ static int snd_sb_csp_open(snd_hwdep_t * */ static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) { - snd_sb_csp_t *p = snd_magic_cast(snd_sb_csp_t, hw->private_data, return -ENXIO); + snd_sb_csp_t *p = hw->private_data; snd_sb_csp_info_t info; snd_sb_csp_start_t start_info; int err; @@ -258,7 +255,7 @@ static int snd_sb_csp_ioctl(snd_hwdep_t */ static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file) { - snd_sb_csp_t *p = snd_magic_cast(snd_sb_csp_t, hw->private_data, return -ENXIO); + snd_sb_csp_t *p = hw->private_data; return (snd_sb_csp_unuse(p)); } @@ -1110,7 +1107,7 @@ static int init_proc_entry(snd_sb_csp_t static void info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - snd_sb_csp_t *p = snd_magic_cast(snd_sb_csp_t, entry->private_data, return); + snd_sb_csp_t *p = entry->private_data; snd_iprintf(buffer, "Creative Signal Processor [v%d.%d]\n", (p->version >> 4), (p->version & 0x0f)); snd_iprintf(buffer, "State: %cx%c%c%c\n", ((p->running & SNDRV_SB_CSP_ST_QSOUND) ? 'Q' : '-'), --- linux-2.6.8-rc1/sound/isa/sb/sb16_main.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/isa/sb/sb16_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -49,13 +49,11 @@ MODULE_AUTHOR("Jaroslav Kysela hardware == SB_HW_16CSP) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->running & SNDRV_SB_CSP_ST_LOADED) { /* manually loaded codec */ @@ -103,7 +101,7 @@ static void snd_sb16_csp_playback_prepar static void snd_sb16_csp_capture_prepare(sb_t *chip, snd_pcm_runtime_t *runtime) { if (chip->hardware == SB_HW_16CSP) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->running & SNDRV_SB_CSP_ST_LOADED) { /* manually loaded codec */ @@ -141,7 +139,7 @@ static void snd_sb16_csp_capture_prepare static void snd_sb16_csp_update(sb_t *chip) { if (chip->hardware == SB_HW_16CSP) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->qpos_changed) { spin_lock(&chip->reg_lock); @@ -155,7 +153,7 @@ static void snd_sb16_csp_playback_open(s { /* CSP decoders (QSound excluded) support only 16bit transfers */ if (chip->hardware == SB_HW_16CSP) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->running & SNDRV_SB_CSP_ST_LOADED) { /* manually loaded codec */ @@ -173,7 +171,7 @@ static void snd_sb16_csp_playback_open(s static void snd_sb16_csp_playback_close(sb_t *chip) { if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_WRITE)) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->ops.csp_stop(csp) == 0) { csp->ops.csp_unuse(csp); @@ -186,7 +184,7 @@ static void snd_sb16_csp_capture_open(sb { /* CSP coders support only 16bit transfers */ if (chip->hardware == SB_HW_16CSP) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->running & SNDRV_SB_CSP_ST_LOADED) { /* manually loaded codec */ @@ -204,7 +202,7 @@ static void snd_sb16_csp_capture_open(sb static void snd_sb16_csp_capture_close(sb_t *chip) { if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_READ)) { - snd_sb_csp_t *csp = snd_magic_cast(snd_sb_csp_t, chip->csp, return); + snd_sb_csp_t *csp = chip->csp; if (csp->ops.csp_stop(csp) == 0) { csp->ops.csp_unuse(csp); @@ -395,7 +393,7 @@ static int snd_sb16_capture_trigger(snd_ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); + sb_t *chip = dev_id; unsigned char status; int ok; --- linux-2.6.8-rc1/sound/isa/sb/sb8.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sb/sb8.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,13 +30,10 @@ #define SNDRV_LEGACY_AUTO_PROBE #include -#define chip_t sb_t - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}"); +MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -48,22 +45,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for SB8 driver."); -MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for SB8 driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(dma8, int, boot_devs, 0444); MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver."); -MODULE_PARM_SYNTAX(dma8, SNDRV_DMA8_DESC); struct snd_sb8 { struct resource *fm_res; /* used to block FM i/o region for legacy cards */ @@ -73,7 +64,7 @@ static snd_card_t *snd_sb8_cards[SNDRV_C static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); + sb_t *chip = dev_id; if (chip->open & SB_OPEN_PCM) { return snd_sb8dsp_interrupt(chip); --- linux-2.6.8-rc1/sound/isa/sb/sb8_main.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/isa/sb/sb8_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,8 +42,6 @@ MODULE_AUTHOR("Jaroslav Kysela rmidi->private_data, return -ENXIO); + chip = substream->rmidi->private_data; valid_open_flags = chip->hardware >= SB_HW_20 ? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0; spin_lock_irqsave(&chip->open_lock, flags); @@ -100,7 +100,7 @@ static int snd_sb8dsp_midi_output_open(s sb_t *chip; unsigned int valid_open_flags; - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); + chip = substream->rmidi->private_data; valid_open_flags = chip->hardware >= SB_HW_20 ? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0; spin_lock_irqsave(&chip->open_lock, flags); @@ -126,7 +126,7 @@ static int snd_sb8dsp_midi_input_close(s unsigned long flags; sb_t *chip; - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); + chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->open_lock, flags); chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER); chip->midi_substream_input = NULL; @@ -144,7 +144,7 @@ static int snd_sb8dsp_midi_output_close( unsigned long flags; sb_t *chip; - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); + chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->open_lock, flags); chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER); chip->midi_substream_output = NULL; @@ -162,7 +162,7 @@ static void snd_sb8dsp_midi_input_trigge unsigned long flags; sb_t *chip; - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); + chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->open_lock, flags); if (up) { if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) { @@ -188,7 +188,7 @@ static void snd_sb8dsp_midi_output_write int max = 32; /* how big is Tx FIFO? */ - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); + chip = substream->rmidi->private_data; while (max-- > 0) { spin_lock_irqsave(&chip->open_lock, flags); if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) { @@ -219,7 +219,7 @@ static void snd_sb8dsp_midi_output_write static void snd_sb8dsp_midi_output_timer(unsigned long data) { snd_rawmidi_substream_t * substream = (snd_rawmidi_substream_t *) data; - sb_t * chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); + sb_t * chip = substream->rmidi->private_data; unsigned long flags; spin_lock_irqsave(&chip->open_lock, flags); @@ -234,7 +234,7 @@ static void snd_sb8dsp_midi_output_trigg unsigned long flags; sb_t *chip; - chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); + chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->open_lock, flags); if (up) { if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { --- linux-2.6.8-rc1/sound/isa/sb/sb_common.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/isa/sb/sb_common.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,12 +33,9 @@ #include #include -#define chip_t sb_t - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); #define BUSY_LOOPS 100000 @@ -197,13 +194,13 @@ static int snd_sbdsp_free(sb_t *chip) free_dma(chip->dma16); } #endif - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_sbdsp_dev_free(snd_device_t *device) { - sb_t *chip = snd_magic_cast(sb_t, device->device_data, return -ENXIO); + sb_t *chip = device->device_data; return snd_sbdsp_free(chip); } @@ -224,7 +221,7 @@ int snd_sbdsp_create(snd_card_t *card, snd_assert(r_chip != NULL, return -EINVAL); *r_chip = NULL; - chip = snd_magic_kcalloc(sb_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); --- linux-2.6.8-rc1/sound/isa/sb/sb_mixer.c 2003-06-14 12:18:08.000000000 -0700 +++ 25/sound/isa/sb/sb_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -27,8 +27,6 @@ #include #include -#define chip_t sb_t - #undef IO_DEBUG void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data) --- linux-2.6.8-rc1/sound/isa/sgalaxy.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sgalaxy.c 2004-07-13 17:09:19.000000000 -0700 @@ -39,8 +39,7 @@ MODULE_AUTHOR("Christopher Butler "); MODULE_DESCRIPTION("Aztech Sound Galaxy"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Aztech Systems,Sound Galaxy}}"); +MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -53,22 +52,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(sbport, long, boot_devs, 0444); MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); -MODULE_PARM_SYNTAX(sbport, SNDRV_ENABLED ",allows:{{0x220},{0x240}},dialog:list"); module_param_array(wssport, long, boot_devs, 0444); MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); -MODULE_PARM_SYNTAX(wssport, SNDRV_ENABLED ",allows:{{0x530},{0xe80},{0xf40},{0x604}},dialog:list"); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_ENABLED ",allows:{{7},{9},{10},{11}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA8_DESC); #define SGALAXY_AUXC_LEFT 18 #define SGALAXY_AUXC_RIGHT 19 --- linux-2.6.8-rc1/sound/isa/sscape.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/sscape.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,8 +36,6 @@ #include -#define chip_t cs4231_t - MODULE_AUTHOR("Chris Rankin"); MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver"); @@ -53,27 +51,21 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "Description for SoundScape card"); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(port, long, boot_devs, 0444); MODULE_PARM_DESC(port, "Port # for SoundScape driver."); -MODULE_PARM_SYNTAX(port, SNDRV_ENABLED); module_param_array(irq, int, boot_devs, 0444); MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver."); -MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); module_param_array(mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver."); -MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); module_param_array(dma, int, boot_devs, 0444); MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); -MODULE_PARM_SYNTAX(dma, SNDRV_DMA8_DESC); #ifdef CONFIG_PNP static struct pnp_card_device_id sscape_pnpids[] = { --- linux-2.6.8-rc1/sound/isa/wavefront/wavefront.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/wavefront/wavefront.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,13 +30,10 @@ #include #include -#define chip_t cs4231_t - MODULE_AUTHOR("Paul Barton-Davis "); MODULE_DESCRIPTION("Turtle Beach Wavefront"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Turtle Beach,Maui/Tropez/Tropez+}}"); +MODULE_SUPPORTED_DEVICE("{{Turtle Beach,Maui/Tropez/Tropez+}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -56,48 +53,34 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for WaveFront soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for WaveFront soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable WaveFront soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef CONFIG_PNP module_param_array(isapnp, bool, boot_devs, 0444); MODULE_PARM_DESC(isapnp, "ISA PnP detection for WaveFront soundcards."); -MODULE_PARM_SYNTAX(isapnp, SNDRV_ISAPNP_DESC); #endif module_param_array(cs4232_pcm_port, long, boot_devs, 0444); MODULE_PARM_DESC(cs4232_pcm_port, "Port # for CS4232 PCM interface."); -MODULE_PARM_SYNTAX(cs4232_pcm_port, SNDRV_PORT12_DESC); module_param_array(cs4232_pcm_irq, int, boot_devs, 0444); MODULE_PARM_DESC(cs4232_pcm_irq, "IRQ # for CS4232 PCM interface."); -MODULE_PARM_SYNTAX(cs4232_pcm_irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{11},{12},{15}},dialog:list"); module_param_array(dma1, int, boot_devs, 0444); MODULE_PARM_DESC(dma1, "DMA1 # for CS4232 PCM interface."); -MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC); module_param_array(dma2, int, boot_devs, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for CS4232 PCM interface."); -MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); module_param_array(cs4232_mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(cs4232_mpu_port, "port # for CS4232 MPU-401 interface."); -MODULE_PARM_SYNTAX(cs4232_mpu_port, SNDRV_PORT12_DESC); module_param_array(cs4232_mpu_irq, int, boot_devs, 0444); MODULE_PARM_DESC(cs4232_mpu_irq, "IRQ # for CS4232 MPU-401 interface."); -MODULE_PARM_SYNTAX(cs4232_mpu_irq, SNDRV_ENABLED ",allows:{{9},{11},{12},{15}},dialog:list"); module_param_array(ics2115_irq, int, boot_devs, 0444); MODULE_PARM_DESC(ics2115_irq, "IRQ # for ICS2115."); -MODULE_PARM_SYNTAX(ics2115_irq, SNDRV_ENABLED ",allows:{{9},{11},{12},{15}},dialog:list"); module_param_array(ics2115_port, long, boot_devs, 0444); MODULE_PARM_DESC(ics2115_port, "Port # for ICS2115."); -MODULE_PARM_SYNTAX(ics2115_port, SNDRV_PORT12_DESC); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port #."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC); module_param_array(use_cs4232_midi, bool, boot_devs, 0444); MODULE_PARM_DESC(use_cs4232_midi, "Use CS4232 MPU-401 interface (inaccessibly located inside your computer)"); -MODULE_PARM_SYNTAX(use_cs4232_midi, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); static snd_card_t *snd_wavefront_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; --- linux-2.6.8-rc1/sound/isa/wavefront/wavefront_fx.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/isa/wavefront/wavefront_fx.c 2004-07-13 17:09:55.000000000 -0700 @@ -34,7 +34,7 @@ /* weird stuff, derived from port I/O tracing with dosemu */ -static unsigned char page_zero[] __initdata = { +unsigned char page_zero[] __initdata = { 0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, @@ -61,7 +61,7 @@ static unsigned char page_zero[] __initd 0x1d, 0x02, 0xdf }; -static unsigned char page_one[] __initdata = { +unsigned char page_one[] __initdata = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, 0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, @@ -88,7 +88,7 @@ static unsigned char page_one[] __initda 0x60, 0x00, 0x1b }; -static unsigned char page_two[] __initdata = { +unsigned char page_two[] __initdata = { 0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, 0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -103,7 +103,7 @@ static unsigned char page_two[] __initda 0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 }; -static unsigned char page_three[] __initdata = { +unsigned char page_three[] __initdata = { 0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -118,7 +118,7 @@ static unsigned char page_three[] __init 0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 }; -static unsigned char page_four[] __initdata = { +unsigned char page_four[] __initdata = { 0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -133,7 +133,7 @@ static unsigned char page_four[] __initd 0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 }; -static unsigned char page_six[] __initdata = { +unsigned char page_six[] __initdata = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, @@ -154,7 +154,7 @@ static unsigned char page_six[] __initda 0x80, 0x00, 0x7e, 0x80, 0x80 }; -static unsigned char page_seven[] __initdata = { +unsigned char page_seven[] __initdata = { 0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, @@ -181,7 +181,7 @@ static unsigned char page_seven[] __init 0x00, 0x02, 0x00 }; -static unsigned char page_zero_v2[] __initdata = { +unsigned char page_zero_v2[] __initdata = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -193,7 +193,7 @@ static unsigned char page_zero_v2[] __in 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static unsigned char page_one_v2[] __initdata = { +unsigned char page_one_v2[] __initdata = { 0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -205,21 +205,21 @@ static unsigned char page_one_v2[] __ini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static unsigned char page_two_v2[] __initdata = { +unsigned char page_two_v2[] __initdata = { 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static unsigned char page_three_v2[] __initdata = { +unsigned char page_three_v2[] __initdata = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static unsigned char page_four_v2[] __initdata = { +unsigned char page_four_v2[] __initdata = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -227,7 +227,7 @@ static unsigned char page_four_v2[] __in 0x00, 0x00, 0x00, 0x00 }; -static unsigned char page_seven_v2[] __initdata = { +unsigned char page_seven_v2[] __initdata = { 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -239,7 +239,7 @@ static unsigned char page_seven_v2[] __i 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static unsigned char mod_v2[] __initdata = { +unsigned char mod_v2[] __initdata = { 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, 0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, @@ -269,7 +269,7 @@ static unsigned char mod_v2[] __initdata 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, 0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 }; -static unsigned char coefficients[] __initdata = { +unsigned char coefficients[] __initdata = { 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, 0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, @@ -305,14 +305,14 @@ static unsigned char coefficients[] __in 0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, 0xba }; -static unsigned char coefficients2[] __initdata = { +unsigned char coefficients2[] __initdata = { 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, 0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, 0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 }; -static unsigned char coefficients3[] __initdata = { +unsigned char coefficients3[] __initdata = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, 0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, --- linux-2.6.8-rc1/sound/isa/wavefront/wavefront_synth.c 2004-06-15 23:29:48.000000000 -0700 +++ 25/sound/isa/wavefront/wavefront_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -1961,6 +1961,12 @@ wavefront_download_firmware (snd_wavefro break; } + if (section_length < 0 || section_length > WF_SECTION_MAX) { + snd_printk ("invalid firmware section length %d\n", + section_length); + goto failure; + } + if (sys_read (fd, section, section_length) != section_length) { snd_printk ("firmware section " "read error.\n"); --- linux-2.6.8-rc1/sound/oss/i810_audio.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/oss/i810_audio.c 2004-07-13 17:09:49.000000000 -0700 @@ -450,12 +450,38 @@ struct i810_card { /* extract register offset from codec struct */ #define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id]) -#define GET_CIV(port) MODULOP2(inb((port) + OFF_CIV), SG_LEN) -#define GET_LVI(port) MODULOP2(inb((port) + OFF_LVI), SG_LEN) +#define I810_IOREAD(size, type, card, off) \ +({ \ + type val; \ + if (card->use_mmio) \ + val=read##size(card->iobase_mmio+off); \ + else \ + val=in##size(card->iobase+off); \ + val; \ +}) + +#define I810_IOREADL(card, off) I810_IOREAD(l, u32, card, off) +#define I810_IOREADW(card, off) I810_IOREAD(w, u16, card, off) +#define I810_IOREADB(card, off) I810_IOREAD(b, u8, card, off) + +#define I810_IOWRITE(size, val, card, off) \ +({ \ + if (card->use_mmio) \ + write##size(val, card->iobase_mmio+off); \ + else \ + out##size(val, card->iobase+off); \ +}) + +#define I810_IOWRITEL(val, card, off) I810_IOWRITE(l, val, card, off) +#define I810_IOWRITEW(val, card, off) I810_IOWRITE(w, val, card, off) +#define I810_IOWRITEB(val, card, off) I810_IOWRITE(b, val, card, off) + +#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN) +#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN) /* set LVI from CIV */ -#define CIV_TO_LVI(port, off) \ - outb(MODULOP2(GET_CIV((port)) + (off), SG_LEN), (port) + OFF_LVI) +#define CIV_TO_LVI(card, port, off) \ + I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI) static struct i810_card *devs = NULL; @@ -714,9 +740,9 @@ static inline unsigned i810_get_dma_addr return 0; if (rec) - port = state->card->iobase + dmabuf->read_channel->port; + port = dmabuf->read_channel->port; else - port = state->card->iobase + dmabuf->write_channel->port; + port = dmabuf->write_channel->port; if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) { port_picb = port + OFF_SR; @@ -725,8 +751,8 @@ static inline unsigned i810_get_dma_addr port_picb = port + OFF_PICB; do { - civ = GET_CIV(port); - offset = inw(port_picb); + civ = GET_CIV(state->card, port); + offset = I810_IOREADW(state->card, port_picb); /* Must have a delay here! */ if(offset == 0) udelay(1); @@ -745,7 +771,7 @@ static inline unsigned i810_get_dma_addr * that we won't have to worry about the chip still being * out of sync with reality ;-) */ - } while (civ != GET_CIV(port) || offset != inw(port_picb)); + } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb)); return (((civ + 1) * dmabuf->fragsize - (bytes * offset)) % dmabuf->dmasize); @@ -758,15 +784,15 @@ static inline void __stop_adc(struct i81 struct i810_card *card = state->card; dmabuf->enable &= ~ADC_RUNNING; - outb(0, card->iobase + PI_CR); + I810_IOWRITEB(0, card, PI_CR); // wait for the card to acknowledge shutdown - while( inb(card->iobase + PI_CR) != 0 ) ; + while( I810_IOREADB(card, PI_CR) != 0 ) ; // now clear any latent interrupt bits (like the halt bit) if(card->pci_id == PCI_DEVICE_ID_SI_7012) - outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB ); + I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB ); else - outb( inb(card->iobase + PI_SR), card->iobase + PI_SR ); - outl( inl(card->iobase + GLOB_STA) & INT_PI, card->iobase + GLOB_STA); + I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR ); + I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA); } static void stop_adc(struct i810_state *state) @@ -787,7 +813,7 @@ static inline void __start_adc(struct i8 (dmabuf->trigger & PCM_ENABLE_INPUT)) { dmabuf->enable |= ADC_RUNNING; // Interrupt enable, LVI enable, DMA enable - outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR); + I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR); } } @@ -808,15 +834,15 @@ static inline void __stop_dac(struct i81 struct i810_card *card = state->card; dmabuf->enable &= ~DAC_RUNNING; - outb(0, card->iobase + PO_CR); + I810_IOWRITEB(0, card, PO_CR); // wait for the card to acknowledge shutdown - while( inb(card->iobase + PO_CR) != 0 ) ; + while( I810_IOREADB(card, PO_CR) != 0 ) ; // now clear any latent interrupt bits (like the halt bit) if(card->pci_id == PCI_DEVICE_ID_SI_7012) - outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB ); + I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB ); else - outb( inb(card->iobase + PO_SR), card->iobase + PO_SR ); - outl( inl(card->iobase + GLOB_STA) & INT_PO, card->iobase + GLOB_STA); + I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR ); + I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA); } static void stop_dac(struct i810_state *state) @@ -837,7 +863,7 @@ static inline void __start_dac(struct i8 (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { dmabuf->enable |= DAC_RUNNING; // Interrupt enable, LVI enable, DMA enable - outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR); + I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR); } } static void start_dac(struct i810_state *state) @@ -1000,12 +1026,12 @@ static int prog_dmabuf(struct i810_state sg++; } spin_lock_irqsave(&state->card->lock, flags); - outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ - while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ; - outl((u32)state->card->chandma + + I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */ + while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ; + I810_IOWRITEL((u32)state->card->chandma + c->num*sizeof(struct i810_channel), - state->card->iobase+c->port+OFF_BDBAR); - CIV_TO_LVI(state->card->iobase+c->port, 0); + state->card, c->port+OFF_BDBAR); + CIV_TO_LVI(state->card, c->port, 0); spin_unlock_irqrestore(&state->card->lock, flags); @@ -1037,14 +1063,13 @@ static void __i810_update_lvi(struct i81 void (*start)(struct i810_state *); count = dmabuf->count; - port = state->card->iobase; if (rec) { - port += dmabuf->read_channel->port; + port = dmabuf->read_channel->port; trigger = PCM_ENABLE_INPUT; start = __start_adc; count = dmabuf->dmasize - count; } else { - port += dmabuf->write_channel->port; + port = dmabuf->write_channel->port; trigger = PCM_ENABLE_OUTPUT; start = __start_dac; } @@ -1059,14 +1084,14 @@ static void __i810_update_lvi(struct i81 return; start(state); - while (!(inb(port + OFF_CR) & ((1<<4) | (1<<2)))) + while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2)))) ; } /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */ x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize); x >>= dmabuf->fragshift; - outb(x, port + OFF_LVI); + I810_IOWRITEB(x, state->card, port + OFF_LVI); } static void i810_update_lvi(struct i810_state *state, int rec) @@ -1108,8 +1133,8 @@ static void i810_update_ptr(struct i810_ /* this is normal for the end of a read */ /* only give an error if we went past the */ /* last valid sg entry */ - if (GET_CIV(state->card->iobase + PI_BASE) != - GET_LVI(state->card->iobase + PI_BASE)) { + if (GET_CIV(state->card, PI_BASE) != + GET_LVI(state->card, PI_BASE)) { printk(KERN_WARNING "i810_audio: DMA overrun on read\n"); dmabuf->error++; } @@ -1133,13 +1158,13 @@ static void i810_update_ptr(struct i810_ /* this is normal for the end of a write */ /* only give an error if we went past the */ /* last valid sg entry */ - if (GET_CIV(state->card->iobase + PO_BASE) != - GET_LVI(state->card->iobase + PO_BASE)) { + if (GET_CIV(state->card, PO_BASE) != + GET_LVI(state->card, PO_BASE)) { printk(KERN_WARNING "i810_audio: DMA overrun on write\n"); printk("i810_audio: CIV %d, LVI %d, hwptr %x, " "count %d\n", - GET_CIV(state->card->iobase + PO_BASE), - GET_LVI(state->card->iobase + PO_BASE), + GET_CIV(state->card, PO_BASE), + GET_LVI(state->card, PO_BASE), dmabuf->hwptr, dmabuf->count); dmabuf->error++; } @@ -1287,7 +1312,7 @@ static void i810_channel_interrupt(struc struct i810_state *state = card->states[i]; struct i810_channel *c; struct dmabuf *dmabuf; - unsigned long port = card->iobase; + unsigned long port; u16 status; if(!state) @@ -1302,12 +1327,12 @@ static void i810_channel_interrupt(struc } else /* This can occur going from R/W to close */ continue; - port+=c->port; + port = c->port; if(card->pci_id == PCI_DEVICE_ID_SI_7012) - status = inw(port + OFF_PICB); + status = I810_IOREADW(card, port + OFF_PICB); else - status = inw(port + OFF_SR); + status = I810_IOREADW(card, port + OFF_SR); #ifdef DEBUG_INTERRUPTS printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status); @@ -1340,7 +1365,7 @@ static void i810_channel_interrupt(struc if(dmabuf->enable & ADC_RUNNING) count = dmabuf->dmasize - count; if (count >= (int)dmabuf->fragsize) { - outb(inb(port+OFF_CR) | 1, port+OFF_CR); + I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR); #ifdef DEBUG_INTERRUPTS printk(" CONTINUE "); #endif @@ -1356,9 +1381,9 @@ static void i810_channel_interrupt(struc } } if(card->pci_id == PCI_DEVICE_ID_SI_7012) - outw(status & DMA_INT_MASK, port + OFF_PICB); + I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB); else - outw(status & DMA_INT_MASK, port + OFF_SR); + I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR); } #ifdef DEBUG_INTERRUPTS printk(")\n"); @@ -1372,7 +1397,7 @@ static irqreturn_t i810_interrupt(int ir spin_lock(&card->lock); - status = inl(card->iobase + GLOB_STA); + status = I810_IOREADL(card, GLOB_STA); if(!(status & INT_MASK)) { @@ -1384,7 +1409,7 @@ static irqreturn_t i810_interrupt(int ir i810_channel_interrupt(card); /* clear 'em */ - outl(status & INT_MASK, card->iobase + GLOB_STA); + I810_IOWRITEL(status & INT_MASK, card, GLOB_STA); spin_unlock(&card->lock); return IRQ_HANDLED; } @@ -1784,13 +1809,13 @@ static int i810_ioctl(struct inode *inod __stop_adc(state); } if (c != NULL) { - outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ - while ( inb(state->card->iobase+c->port+OFF_CR) & 2 ) + I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */ + while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 ) cpu_relax(); - outl((u32)state->card->chandma + + I810_IOWRITEL((u32)state->card->chandma + c->num*sizeof(struct i810_channel), - state->card->iobase+c->port+OFF_BDBAR); - CIV_TO_LVI(state->card->iobase+c->port, 0); + state->card, c->port+OFF_BDBAR); + CIV_TO_LVI(state->card, c->port, 0); } spin_unlock_irqrestore(&state->card->lock, flags); @@ -1920,7 +1945,7 @@ static int i810_ioctl(struct inode *inod /* Global Status and Global Control register are now */ /* used to indicate this. */ - i_glob_cnt = inl(state->card->iobase + GLOB_CNT); + i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT); /* Current # of channels enabled */ if ( i_glob_cnt & 0x0100000 ) @@ -1932,14 +1957,14 @@ static int i810_ioctl(struct inode *inod switch ( val ) { case 2: /* 2 channels is always supported */ - outl(i_glob_cnt & 0xffcfffff, - state->card->iobase + GLOB_CNT); + I810_IOWRITEL(i_glob_cnt & 0xffcfffff, + state->card, GLOB_CNT); /* Do we need to change mixer settings???? */ break; case 4: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 4 ) { - outl((i_glob_cnt & 0xffcfffff) | 0x100000, - state->card->iobase + GLOB_CNT); + I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000, + state->card, GLOB_CNT); /* Do we need to change mixer settings??? */ } else { val = ret; @@ -1947,8 +1972,8 @@ static int i810_ioctl(struct inode *inod break; case 6: /* Supported on some chipsets, better check first */ if ( state->card->channels >= 6 ) { - outl((i_glob_cnt & 0xffcfffff) | 0x200000, - state->card->iobase + GLOB_CNT); + I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000, + state->card, GLOB_CNT); /* Do we need to change mixer settings??? */ } else { val = ret; @@ -2477,8 +2502,8 @@ found_virt: } else { i810_set_dac_rate(state, 8000); /* Put the ACLink in 2 channel mode by default */ - i = inl(card->iobase + GLOB_CNT); - outl(i & 0xffcfffff, card->iobase + GLOB_CNT); + i = I810_IOREADL(card, GLOB_CNT); + I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT); } } @@ -2569,7 +2594,7 @@ static u16 i810_ac97_get_io(struct ac97_ int count = 100; u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - while(count-- && (inb(card->iobase + CAS) & 1)) + while(count-- && (I810_IOREADB(card, CAS) & 1)) udelay(1); return inw(card->ac97base + reg_set); @@ -2597,7 +2622,7 @@ static void i810_ac97_set_io(struct ac97 int count = 100; u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - while(count-- && (inb(card->iobase + CAS) & 1)) + while(count-- && (I810_IOREADB(card, CAS) & 1)) udelay(1); outw(data, card->ac97base + reg_set); @@ -2686,7 +2711,7 @@ static /*const*/ struct file_operations static inline int i810_ac97_exists(struct i810_card *card, int ac97_number) { - u32 reg = inl(card->iobase + GLOB_STA); + u32 reg = I810_IOREADL(card, GLOB_STA); switch (ac97_number) { case 0: return reg & (1<<8); @@ -2757,7 +2782,7 @@ static inline int ich_use_mmio(struct i8 static int i810_ac97_power_up_bus(struct i810_card *card) { - u32 reg = inl(card->iobase + GLOB_CNT); + u32 reg = I810_IOREADL(card, GLOB_CNT); int i; int primary_codec_id = 0; @@ -2769,14 +2794,14 @@ static int i810_ac97_power_up_bus(struct reg&=~8; /* ACLink on */ /* At this point we deassert AC_RESET # */ - outl(reg , card->iobase + GLOB_CNT); + I810_IOWRITEL(reg , card, GLOB_CNT); /* We must now allow time for the Codec initialisation. 600mS is the specified time */ for(i=0;i<10;i++) { - if((inl(card->iobase+GLOB_CNT)&4)==0) + if((I810_IOREADL(card, GLOB_CNT)&4)==0) break; set_current_state(TASK_UNINTERRUPTIBLE); @@ -2795,8 +2820,11 @@ static int i810_ac97_power_up_bus(struct * See if the primary codec comes ready. This must happen * before we start doing DMA stuff */ - /* see i810_ac97_init for the next 7 lines (jsaw) */ - inw(card->ac97base); + /* see i810_ac97_init for the next 10 lines (jsaw) */ + if (card->use_mmio) + readw(card->ac97base_mmio); + else + inw(card->ac97base); if (ich_use_mmio(card)) { primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3; printk(KERN_INFO "i810_audio: Primary codec has ID %d\n", @@ -2814,7 +2842,10 @@ static int i810_ac97_power_up_bus(struct else printk("no response.\n"); } - inw(card->ac97base); + if (card->use_mmio) + readw(card->ac97base_mmio); + else + inw(card->ac97base); return 1; } @@ -2839,15 +2870,15 @@ static int __devinit i810_ac97_init(stru /* to check.... */ card->channels = 2; - reg = inl(card->iobase + GLOB_STA); + reg = I810_IOREADL(card, GLOB_STA); if ( reg & 0x0200000 ) card->channels = 6; else if ( reg & 0x0100000 ) card->channels = 4; printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels); printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n"); - reg = inl(card->iobase + GLOB_CNT); - outl(reg & 0xffcfffff, card->iobase + GLOB_CNT); + reg = I810_IOREADL(card, GLOB_CNT); + I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT); for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) card->ac97_codec[num_ac97] = NULL; @@ -2858,8 +2889,10 @@ static int __devinit i810_ac97_init(stru for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) { /* codec reset */ printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97); - if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97); - else inw(card->ac97base + 0x80*num_ac97); + if (card->use_mmio) + readw(card->ac97base_mmio + 0x80*num_ac97); + else + inw(card->ac97base + 0x80*num_ac97); /* If we have the SDATA_IN Map Register, as on ICH4, we do not loop thru all possible codec IDs but thru all @@ -3062,7 +3095,7 @@ static void __devinit i810_configure_clo goto config_out; } dmabuf->count = dmabuf->dmasize; - CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, -1); + CIV_TO_LVI(card, dmabuf->write_channel->port, -1); local_irq_save(flags); start_dac(state); offset = i810_get_dma_addr(state, 0); @@ -3106,13 +3139,6 @@ static int __devinit i810_probe(struct p return -ENODEV; } - if( pci_resource_start(pci_dev, 1) == 0) - { - /* MMIO only ICH5 .. here be dragons .. */ - printk(KERN_ERR "i810_audio: Pure MMIO interfaces not yet supported.\n"); - return -ENODEV; - } - if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "i810_audio: out of memory\n"); return -ENOMEM; @@ -3125,6 +3151,11 @@ static int __devinit i810_probe(struct p card->ac97base = pci_resource_start (pci_dev, 0); card->iobase = pci_resource_start (pci_dev, 1); + if (!(card->ac97base) || !(card->iobase)) { + card->ac97base = 0; + card->iobase = 0; + } + /* if chipset could have mmio capability, check it */ if (card_cap[pci_id->driver_data].flags & CAP_MMIO) { card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2); @@ -3139,6 +3170,11 @@ static int __devinit i810_probe(struct p } } + if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) { + printk(KERN_ERR "i810_audio: No I/O resources available.\n"); + goto out_mem; + } + card->irq = pci_dev->irq; card->next = devs; card->magic = I810_CARD_MAGIC; @@ -3184,8 +3220,14 @@ static int __devinit i810_probe(struct p } /* claim our iospace and irq */ - request_region(card->iobase, 64, card_names[pci_id->driver_data]); - request_region(card->ac97base, 256, card_names[pci_id->driver_data]); + if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) { + printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase); + goto out_region1; + } + if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) { + printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base); + goto out_region2; + } if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { @@ -3259,7 +3301,9 @@ out_iospace: } out_pio: release_region(card->iobase, 64); +out_region2: release_region(card->ac97base, 256); +out_region1: pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH, card->channel, card->chandma); out_mem: --- linux-2.6.8-rc1/sound/oss/kahlua.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/oss/kahlua.c 2004-07-13 17:35:10.000000000 -0700 @@ -28,6 +28,7 @@ */ #include +#include #include #include #include --- linux-2.6.8-rc1/sound/parisc/harmony.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/parisc/harmony.c 2004-07-13 17:09:19.000000000 -0700 @@ -80,8 +80,7 @@ MODULE_AUTHOR("Laurent Canet "); MODULE_DESCRIPTION("ALSA Harmony sound driver"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ALSA,Harmony soundcard}}"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Harmony soundcard}}"); #undef DEBUG #ifdef DEBUG @@ -138,13 +137,10 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); /* Register offset (from base hpa) */ #define REG_ID 0x00 @@ -216,7 +212,6 @@ typedef struct snd_card_harmony { snd_pcm_substream_t *capture_substream; snd_info_entry_t *proc_entry; } snd_card_harmony_t; -#define chip_t snd_card_harmony_t static snd_card_t *snd_harmony_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; @@ -556,7 +551,7 @@ static int snd_card_harmony_playback_pre harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); /* data format */ - harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format); + harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format); /* number of channels */ if (runtime->channels == 2) @@ -587,7 +582,7 @@ static int snd_card_harmony_capture_prep harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); /* data format */ - harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format); + harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format); /* number of channels */ if (runtime->channels == 1) @@ -751,6 +746,8 @@ static int snd_card_harmony_hw_params(sn int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err > 0 && substream->dma_device.type == SNDRV_DMA_TYPE_CONTINUOUS) + substream->runtime->dma_addr = __pa(substream->runtime->dma_area); DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err, (unsigned long)substream->runtime->dma_addr); return err; @@ -784,7 +781,7 @@ static snd_pcm_ops_t snd_card_harmony_ca .pointer = snd_card_harmony_capture_pointer, }; -static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device) +static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony) { snd_pcm_t *pcm; int err; @@ -797,7 +794,7 @@ static int snd_card_harmony_pcm_init(snd snd_harmony_disable_interrupts(harmony); - if ((err = snd_pcm_new(harmony->card, "Harmony", device, 1, 1, &pcm)) < 0) + if ((err = snd_pcm_new(harmony->card, "Harmony", 0, 1, 1, &pcm)) < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops); @@ -813,26 +810,46 @@ static int snd_card_harmony_pcm_init(snd harmony->dma_dev.dev = &harmony->pa_dev->dev; err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS, &harmony->graveyard_dma); - if (err < 0) + if (err == -ENOMEM) { + /* use continuous buffers */ + harmony->dma_dev.type = SNDRV_DMA_TYPE_CONTINUOUS; + harmony->dma_dev.dev = snd_dma_continuous_data(GFP_KERNEL); + err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS, + &harmony->graveyard_dma); + } + if (err < 0) { + printk(KERN_ERR PFX "can't allocate graveyard buffer\n"); return err; + } harmony->graveyard_count = 0; /* initialize silence buffers */ err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*SILENCE_BUFS, &harmony->silence_dma); - if (err < 0) + if (err < 0) { + printk(KERN_ERR PFX "can't allocate silence buffer\n"); return err; + } harmony->silence_count = 0; + if (harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS) { + harmony->graveyard_dma.addr = __pa(harmony->graveyard_dma.area); + harmony->silence_dma.addr = __pa(harmony->silence_dma.area); + } + harmony->ply_stopped = harmony->cap_stopped = 1; harmony->playback_substream = NULL; harmony->capture_substream = NULL; harmony->graveyard_count = 0; - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - &harmony->pa_dev->dev, - MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); + + err = snd_pcm_lib_preallocate_pages_for_all(pcm, harmony->dma_dev.type, + harmony->dma_dev.dev, + MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); + if (err < 0) { + printk(KERN_ERR PFX "buffer allocation error %d\n", err); + // return err; + } return 0; } @@ -871,7 +888,7 @@ static int snd_harmony_mixercontrol_info static int snd_harmony_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_harmony_t *harmony = _snd_kcontrol_chip(kcontrol); + snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol); int shift_left = (kcontrol->private_value) & 0xff; int shift_right = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -896,7 +913,7 @@ static int snd_harmony_volume_get(snd_kc static int snd_harmony_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - snd_card_harmony_t *harmony = _snd_kcontrol_chip(kcontrol); + snd_card_harmony_t *harmony = snd_kcontrol_chip(kcontrol); int shift_left = (kcontrol->private_value) & 0xff; int shift_right = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; @@ -1037,7 +1054,7 @@ static int __init snd_card_harmony_probe snd_card_free(card); return err; } - if ((err = snd_card_harmony_pcm_init(chip, dev)) < 0) { + if ((err = snd_card_harmony_pcm_init(chip)) < 0) { printk(KERN_ERR PFX "PCM Init failed\n"); snd_card_free(card); return err; --- linux-2.6.8-rc1/sound/pci/ac97/ac97_codec.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ac97/ac97_codec.c 2004-07-13 17:09:19.000000000 -0700 @@ -45,9 +45,6 @@ static int enable_loopback; module_param(enable_loopback, bool, 0444); MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); -MODULE_PARM_SYNTAX(enable_loopback, SNDRV_BOOLEAN_FALSE_DESC); - -#define chip_t ac97_t /* @@ -108,12 +105,13 @@ static const ac97_codec_id_t snd_ac97_co { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, { 0x414c4300, 0xffffff00, "ALC100/100P", NULL, NULL }, { 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL }, +{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */ +{ 0x414c4722, 0xffffffff, "ALC650E", NULL, NULL }, /* already patched */ +{ 0x414c4723, 0xffffffff, "ALC650F", NULL, NULL }, /* already patched */ { 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL }, -{ 0x414c4721, 0xfffffff0, "ALC650D", patch_alc650, NULL }, -{ 0x414c4722, 0xfffffff0, "ALC650E", patch_alc650, NULL }, -{ 0x414c4723, 0xfffffff0, "ALC650F", patch_alc650, NULL }, { 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL }, { 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL }, +{ 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL }, { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, @@ -274,7 +272,7 @@ void snd_ac97_write(ac97_t *ac97, unsign { if (!snd_ac97_valid_reg(ac97, reg)) return; - if ((ac97->id & 0xffffff00) == 0x414c4300) { + if ((ac97->id & 0xffffff00) == AC97_ID_ALC100) { /* Fix H/W bug of ALC100/100P */ if (reg == AC97_MASTER || reg == AC97_HEADPHONE) ac97->bus->write(ac97, AC97_RESET, 0); /* reset audio codec */ @@ -398,7 +396,7 @@ static int snd_ac97_ad18xx_update_pcm_bi int change; unsigned short old, new, cfg; - down(&ac97->spec.ad18xx.mutex); + down(&ac97->mutex); spin_lock(&ac97->reg_lock); old = ac97->spec.ad18xx.pcmreg[codec]; new = (old & ~mask) | value; @@ -418,7 +416,7 @@ static int snd_ac97_ad18xx_update_pcm_bi cfg | 0x7000); } else spin_unlock(&ac97->reg_lock); - up(&ac97->spec.ad18xx.mutex); + up(&ac97->mutex); return change; } @@ -545,7 +543,7 @@ int snd_ac97_get_single(snd_kcontrol_t * int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask; if (invert) @@ -559,7 +557,7 @@ int snd_ac97_put_single(snd_kcontrol_t * int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0x01; unsigned short val; val = (ucontrol->value.integer.value[0] & mask); @@ -625,6 +623,40 @@ static int snd_ac97_put_double(snd_kcont (val1 << shift_left) | (val2 << shift_right)); } +int snd_ac97_getput_page(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol, + int (*func)(snd_kcontrol_t *, snd_ctl_elem_value_t *)) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int err; + + if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 && + (reg >= 0x60 && reg < 0x70)) { + unsigned short page_save; + unsigned short page = (kcontrol->private_value >> 25) & 0x0f; + down(&ac97->mutex); /* lock paging */ + page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK; + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page); + err = func(kcontrol, ucontrol); + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save); + up(&ac97->mutex); /* unlock paging */ + } else + err = func(kcontrol, ucontrol); + return err; +} + +/* for rev2.3 paging */ +int snd_ac97_page_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_get_single); +} + +/* for rev2.3 paging */ +int snd_ac97_page_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_put_single); +} + static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = { AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1), AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1) @@ -1009,14 +1041,14 @@ static int snd_ac97_bus_free(ac97_bus_t kfree(bus->pcms); if (bus->private_free) bus->private_free(bus); - snd_magic_kfree(bus); + kfree(bus); } return 0; } static int snd_ac97_bus_dev_free(snd_device_t *device) { - ac97_bus_t *bus = snd_magic_cast(ac97_bus_t, device->device_data, return -ENXIO); + ac97_bus_t *bus = device->device_data; return snd_ac97_bus_free(bus); } @@ -1028,14 +1060,14 @@ static int snd_ac97_free(ac97_t *ac97) ac97->bus->codec[ac97->num] = NULL; if (ac97->private_free) ac97->private_free(ac97); - snd_magic_kfree(ac97); + kfree(ac97); } return 0; } static int snd_ac97_dev_free(snd_device_t *device) { - ac97_t *ac97 = snd_magic_cast(ac97_t, device->device_data, return -ENXIO); + ac97_t *ac97 = device->device_data; snd_ac97_powerdown(ac97); /* for avoiding click noises during shut down */ return snd_ac97_free(ac97); } @@ -1120,6 +1152,7 @@ static void snd_ac97_change_volume_param snd_ac97_write_cache(ac97, reg, 0x8000); } +/* check the volume resolution of center/lfe */ static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max) { unsigned short val, val1; @@ -1135,6 +1168,7 @@ static void snd_ac97_change_volume_param snd_ac97_write_cache(ac97, reg, 0x8080); } +/* check whether the volume resolution is 4 or 5 bits */ static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char *max) { unsigned short val, val1; @@ -1150,6 +1184,18 @@ static void snd_ac97_change_volume_param snd_ac97_write_cache(ac97, reg, 0x8000); } +/* check whether the volume is mono or stereo */ +static int snd_ac97_is_stereo_vol(ac97_t *ac97, int reg) +{ + unsigned short val, val1, val2; + val = snd_ac97_read(ac97, reg); + val1 = val | 0x8000 | (0x01 << 8); + snd_ac97_write(ac97, reg, val1); + val2 = snd_ac97_read(ac97, reg); + snd_ac97_write(ac97, reg, val); /* restore */ + return val1 == val2; +} + static inline int printable(unsigned int x) { x &= 0xff; @@ -1178,6 +1224,9 @@ static int snd_ac97_cmute_new(snd_card_t snd_kcontrol_t *kctl; int stereo = 0; + if (! snd_ac97_valid_reg(ac97, reg)) + return 0; + if (ac97->flags & AC97_STEREO_MUTES) { /* check whether both mute bits work */ unsigned short val, val1; @@ -1208,6 +1257,9 @@ static int snd_ac97_cvol_new(snd_card_t int err; snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 8, 0, (unsigned int)max, 1); tmp.index = ac97->num; + + if (! snd_ac97_valid_reg(ac97, reg)) + return 0; if ((err = snd_ctl_add(card, snd_ctl_new1(&tmp, ac97))) < 0) return err; snd_ac97_write_cache(ac97, reg, @@ -1225,6 +1277,9 @@ static int snd_ac97_cmix_new(snd_card_t char name[44]; unsigned char max; + if (! snd_ac97_valid_reg(ac97, reg)) + return 0; + sprintf(name, "%s Switch", pfx); if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0) return err; @@ -1239,6 +1294,8 @@ static int snd_ac97_cmix_new(snd_card_t } +static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97); + static int snd_ac97_mixer_build(ac97_t * ac97) { snd_card_t *card = ac97->bus->card; @@ -1293,11 +1350,8 @@ static int snd_ac97_mixer_build(ac97_t * } /* build headphone controls */ - if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE) || ac97->id == AC97_ID_STAC9708) { - const char *name = ac97->id == AC97_ID_STAC9708 ? - "Sigmatel Surround Playback" : - "Headphone Playback"; - if ((err = snd_ac97_cmix_new(card, name, AC97_HEADPHONE, 1, ac97)) < 0) + if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { + if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, 1, ac97)) < 0) return err; } @@ -1332,7 +1386,8 @@ static int snd_ac97_mixer_build(ac97_t * for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) return err; - snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); + snd_ac97_write_cache(ac97, AC97_PC_BEEP, + snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); } /* build Phone controls */ @@ -1349,15 +1404,26 @@ static int snd_ac97_mixer_build(ac97_t * /* build MIC controls */ snd_ac97_change_volume_params3(ac97, AC97_MIC, &max); - for (idx = 0; idx < 3; idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0) + if (snd_ac97_is_stereo_vol(ac97, AC97_MIC)) { + /* build stereo mic */ + if ((err = snd_ac97_cmute_new(card, "Mic Playback Switch", AC97_MIC, ac97)) < 0) + return err; + if ((err = snd_ac97_cvol_new(card, "Mic Playback Volume", AC97_MIC, max, ac97)) < 0) + return err; + if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic[2], ac97))) < 0) return err; - if (idx == 1) { // volume - kctl->private_value &= ~(0xff << 16); - kctl->private_value |= (int)max << 16; + } else { + /* build mono mic */ + for (idx = 0; idx < 3; idx++) { + if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0) + return err; + if (idx == 1) { // volume + kctl->private_value &= ~(0xff << 16); + kctl->private_value |= (int)max << 16; + } } + snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max); } - snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max); /* build Line controls */ if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 0, ac97)) < 0) @@ -1410,9 +1476,7 @@ static int snd_ac97_mixer_build(ac97_t * if ((err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97)) < 0) return err; /* FIXME: C-Media chips have no PCM volume!! */ - if (/*ac97->id == 0x434d4941 ||*/ - ac97->id == 0x434d4942 || - ac97->id == 0x434d4961) + if (ac97->id == AC97_ID_CM9739) snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f); else { if ((err = snd_ac97_cvol_new(card, "PCM Playback Volume", AC97_PCM, 31, ac97)) < 0) @@ -1520,6 +1584,7 @@ static int snd_ac97_mixer_build(ac97_t * /* set default PCM S/PDIF params */ /* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20); + ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97); } ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF; } @@ -1675,7 +1740,7 @@ static int ac97_reset_wait(ac97_t *ac97, if (snd_ac97_read(ac97, AC97_REC_GAIN) == 0x8a05) return 0; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); + schedule_timeout(1); } while (time_after_eq(end_time, jiffies)); return -ENODEV; } @@ -1712,7 +1777,7 @@ int snd_ac97_bus(snd_card_t * card, ac97 snd_assert(card != NULL, return -EINVAL); snd_assert(_bus != NULL && rbus != NULL, return -EINVAL); - bus = snd_magic_kmalloc(ac97_bus_t, 0, GFP_KERNEL); + bus = kmalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) return -ENOMEM; *bus = *_bus; @@ -1767,13 +1832,14 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 snd_assert(bus != NULL && _ac97 != NULL, return -EINVAL); snd_assert(_ac97->num < 4 && bus->codec[_ac97->num] == NULL, return -EINVAL); card = bus->card; - ac97 = snd_magic_kmalloc(ac97_t, 0, GFP_KERNEL); + ac97 = kmalloc(sizeof(*ac97), GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; *ac97 = *_ac97; ac97->bus = bus; bus->codec[ac97->num] = ac97; spin_lock_init(&ac97->reg_lock); + init_MUTEX(&ac97->mutex); if (ac97->pci) { pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); @@ -1789,8 +1855,14 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 bus->wait(ac97); else { udelay(50); - if (ac97_reset_wait(ac97, HZ/2, 0) < 0 && - ac97_reset_wait(ac97, HZ/2, 1) < 0) { + if (ac97->scaps & AC97_SCAP_SKIP_AUDIO) + err = ac97_reset_wait(ac97, HZ/2, 1); + else { + err = ac97_reset_wait(ac97, HZ/2, 0); + if (err < 0) + err = ac97_reset_wait(ac97, 0, 1); + } + if (err < 0) { snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); /* proceed anyway - it's often non-critical */ } @@ -1803,20 +1875,6 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 snd_ac97_free(ac97); return -EIO; } - /* AC97 audio codec chip revision detection. */ - /* Currently only Realtek ALC650 detection implemented. */ - switch(ac97->id & 0xfffffff0) { - case 0x414c4720: /* ALC650 */ - reg = snd_ac97_read(ac97, AC97_ALC650_REVISION); - if (((reg & 0x3f) >= 0) && ((reg & 0x3f) < 3)) - ac97->id = 0x414c4720; /* Old version */ - else if (((reg & 0x3f) >= 3) && ((reg & 0x3f) < 0x10)) - ac97->id = 0x414c4721; /* D version */ - else if ((reg&0x30) == 0x10) - ac97->id = 0x414c4722; /* E version */ - else if ((reg&0x30) == 0x20) - ac97->id = 0x414c4723; /* F version */ - } /* test for AC'97 */ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { @@ -1865,9 +1923,9 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + schedule_timeout(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 %d analog subsections not ready\n", ac97->num); + snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num); } /* FIXME: add powerdown control */ @@ -1898,9 +1956,9 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) goto __ready_ok; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + schedule_timeout(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); + snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); } __ready_ok: @@ -1919,12 +1977,7 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 } if (ac97->ext_id & AC97_EI_SPDIF) { /* codec specific code (patch) should override these values */ - if (ac97->flags & AC97_CS_SPDIF) - ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100; - else if (ac97->id == AC97_ID_CM9739) - ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; - else - ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97); + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000; } if (ac97->ext_id & AC97_EI_VRM) { /* MIC VRA support */ snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]); @@ -1942,8 +1995,8 @@ int snd_ac97_mixer(ac97_bus_t * bus, ac9 /* additional initializations */ if (bus->init) bus->init(ac97); - snd_ac97_get_name(ac97, ac97->id, name, 0); - snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code + snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97)); + snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97)); // ac97->id might be changed in the special setup code if (ac97_is_audio(ac97)) { if (card->mixername[0] == '\0') { strcpy(card->mixername, name); @@ -2066,18 +2119,28 @@ void snd_ac97_resume(ac97_t *ac97) snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0); snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]); - ac97->bus->write(ac97, AC97_MASTER, 0x8101); - for (i = 0; i < 10; i++) { - if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) - break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - /* FIXME: extra delay */ - ac97->bus->write(ac97, AC97_MASTER, 0x8000); - if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/4); + if (ac97_is_audio(ac97)) { + ac97->bus->write(ac97, AC97_MASTER, 0x8101); + for (i = HZ/10; i >= 0; i--) { + if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + /* FIXME: extra delay */ + ac97->bus->write(ac97, AC97_MASTER, 0x8000); + if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/4); + } + } else { + for (i = HZ/10; i >= 0; i--) { + unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID); + if (val != 0xffff && (val & 1) != 0) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } } __reset_ready: @@ -2151,42 +2214,57 @@ __reset_ready: /* */ -int snd_ac97_remove_ctl(ac97_t *ac97, const char *name) +static void set_ctl_name(char *dst, const char *src, const char *suffix) +{ + if (suffix) + sprintf(dst, "%s %s", src, suffix); + else + strcpy(dst, src); +} + +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix) { snd_ctl_elem_id_t id; memset(&id, 0, sizeof(id)); - strcpy(id.name, name); + set_ctl_name(id.name, name, suffix); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; return snd_ctl_remove_id(ac97->bus->card, &id); } -static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name) +static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name, const char *suffix) { snd_ctl_elem_id_t sid; memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, name); + set_ctl_name(sid.name, name, suffix); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; return snd_ctl_find_id(ac97->bus->card, &sid); } -int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst) +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix) { - snd_kcontrol_t *kctl = ctl_find(ac97, src); + snd_kcontrol_t *kctl = ctl_find(ac97, src, suffix); if (kctl) { - strcpy(kctl->id.name, dst); + set_ctl_name(kctl->id.name, dst, suffix); return 0; } return -ENOENT; } -int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2) +/* rename both Volume and Switch controls - don't check the return value */ +void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst) +{ + snd_ac97_rename_ctl(ac97, src, dst, "Switch"); + snd_ac97_rename_ctl(ac97, src, dst, "Volume"); +} + +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix) { snd_kcontrol_t *kctl1, *kctl2; - kctl1 = ctl_find(ac97, s1); - kctl2 = ctl_find(ac97, s2); + kctl1 = ctl_find(ac97, s1, suffix); + kctl2 = ctl_find(ac97, s2, suffix); if (kctl1 && kctl2) { - strcpy(kctl1->id.name, s2); - strcpy(kctl2->id.name, s1); + set_ctl_name(kctl1->id.name, s2, suffix); + set_ctl_name(kctl2->id.name, s1, suffix); return 0; } return -ENOENT; @@ -2194,26 +2272,22 @@ int snd_ac97_swap_ctl(ac97_t *ac97, cons static int swap_headphone(ac97_t *ac97, int remove_master) { - /* FIXME: error checks.. */ if (remove_master) { - if (ctl_find(ac97, "Headphone Playback Switch") == NULL) + if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL) return 0; - snd_ac97_remove_ctl(ac97, "Master Playback Switch"); - snd_ac97_remove_ctl(ac97, "Master Playback Volume"); - } else { - snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch"); - snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume"); - } - snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); - snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + snd_ac97_remove_ctl(ac97, "Master Playback", "Switch"); + snd_ac97_remove_ctl(ac97, "Master Playback", "Volume"); + } else + snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Line-Out Playback"); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); return 0; } static int swap_surround(ac97_t *ac97) { /* FIXME: error checks.. */ - snd_ac97_swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); - snd_ac97_swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); + snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Switch"); + snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Volume"); return 0; } --- linux-2.6.8-rc1/sound/pci/ac97/ac97_id.h 2003-06-14 12:18:35.000000000 -0700 +++ 25/sound/pci/ac97/ac97_id.h 2004-07-13 17:09:19.000000000 -0700 @@ -45,7 +45,14 @@ #define AC97_ID_CS4201 0x43525948 #define AC97_ID_CS4205 0x43525958 #define AC97_ID_CS_MASK 0xfffffff8 /* bit 0-2: rev */ +#define AC97_ID_ALC100 0x414c4300 #define AC97_ID_ALC650 0x414c4720 +#define AC97_ID_ALC650D 0x414c4721 +#define AC97_ID_ALC650E 0x414c4722 +#define AC97_ID_ALC650F 0x414c4723 +#define AC97_ID_ALC655 0x414c4760 +#define AC97_ID_ALC658 0x414c4780 +#define AC97_ID_ALC850 0x414c4790 #define AC97_ID_YMF753 0x594d4803 #define AC97_ID_VT1616 0x49434551 #define AC97_ID_CM9738 0x434d4941 --- linux-2.6.8-rc1/sound/pci/ac97/ac97_local.h 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ac97/ac97_local.h 2004-07-13 17:09:19.000000000 -0700 @@ -23,10 +23,15 @@ */ #define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24)) +#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) | ((page) << 25)) #define AC97_SINGLE(xname, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \ .get = snd_ac97_get_single, .put = snd_ac97_put_single, \ .private_value = AC97_SINGLE_VALUE(reg, shift, mask, invert) } +#define AC97_PAGE_SINGLE(xname, reg, shift, mask, invert, page) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \ + .get = snd_ac97_page_get_single, .put = snd_ac97_page_put_single, \ + .private_value = AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) } /* ac97_codec.c */ extern const char *snd_ac97_stereo_enhancements[]; @@ -37,10 +42,13 @@ void snd_ac97_get_name(ac97_t *ac97, uns int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo); int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); +int snd_ac97_page_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); +int snd_ac97_page_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit); -int snd_ac97_remove_ctl(ac97_t *ac97, const char *name); -int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst); -int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2); +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix); +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix); +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix); +void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst); /* ac97_proc.c */ void snd_ac97_bus_proc_init(ac97_bus_t * ac97); --- linux-2.6.8-rc1/sound/pci/ac97/ac97_patch.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ac97/ac97_patch.c 2004-07-13 17:09:19.000000000 -0700 @@ -35,8 +35,6 @@ #include "ac97_id.h" #include "ac97_local.h" -#define chip_t ac97_t - /* * Chip specific initialization */ @@ -51,6 +49,21 @@ static int patch_build_controls(ac97_t * return 0; } +/* set to the page, update bits and restore the page */ +static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) +{ + unsigned short page_save; + int ret; + + down(&ac97->mutex); + page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK; + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page); + ret = snd_ac97_update_bits(ac97, reg, mask, value); + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save); + up(&ac97->mutex); /* unlock paging */ + return ret; +} + /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ @@ -204,7 +217,7 @@ static int patch_yamaha_ymf753_3d(ac97_t if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control - Wide"); - kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) return err; @@ -315,7 +328,7 @@ static int patch_sigmatel_stac9700_3d(ac if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); - kctl->private_value = AC97_3D_CONTROL | (3 << 16); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); return 0; } @@ -328,11 +341,11 @@ static int patch_sigmatel_stac9708_3d(ac if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); - kctl->private_value = AC97_3D_CONTROL | (3 << 16); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0); if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); - kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); return 0; } @@ -373,22 +386,29 @@ static struct snd_ac97_build_ops patch_s .build_specific = patch_sigmatel_stac97xx_specific }; -static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { - .build_3d = patch_sigmatel_stac9708_3d, - .build_specific = patch_sigmatel_stac97xx_specific -}; - int patch_sigmatel_stac9700(ac97_t * ac97) { ac97->build_ops = &patch_sigmatel_stac9700_ops; return 0; } +static int patch_sigmatel_stac9708_specific(ac97_t *ac97) +{ + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback"); + return patch_sigmatel_stac97xx_specific(ac97); +} + +static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { + .build_3d = patch_sigmatel_stac9708_3d, + .build_specific = patch_sigmatel_stac9708_specific +}; + int patch_sigmatel_stac9708(ac97_t * ac97) { unsigned int codec72, codec6c; ac97->build_ops = &patch_sigmatel_stac9708_ops; + ac97->caps |= 0x10; /* HP (sigmatel surround) support */ codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000; codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG); @@ -467,11 +487,11 @@ static int snd_ac97_stac9758_output_jack int shift = kcontrol->private_value; unsigned short val; - val = ac97->regs[AC97_SIGMATEL_OUTSEL]; - if (!((val >> shift) & 4)) + val = ac97->regs[AC97_SIGMATEL_OUTSEL] >> shift; + if (!(val & 4)) ucontrol->value.enumerated.item[0] = 0; else - ucontrol->value.enumerated.item[0] = 1 + ((val >> shift) & 3); + ucontrol->value.enumerated.item[0] = 1 + (val & 3); return 0; } @@ -487,8 +507,8 @@ static int snd_ac97_stac9758_output_jack val = 0; else val = 4 | (ucontrol->value.enumerated.item[0] - 1); - return snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL, - 7 << shift, val << shift); + return ac97_update_bits_page(ac97, AC97_SIGMATEL_OUTSEL, + 7 << shift, val << shift, 0); } static int snd_ac97_stac9758_input_jack_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -521,8 +541,8 @@ static int snd_ac97_stac9758_input_jack_ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int shift = kcontrol->private_value; - return snd_ac97_update_bits(ac97, AC97_SIGMATEL_INSEL, 7 << shift, - ucontrol->value.enumerated.item[0] << shift); + return ac97_update_bits_page(ac97, AC97_SIGMATEL_INSEL, 7 << shift, + ucontrol->value.enumerated.item[0] << shift, 0); } static int snd_ac97_stac9758_phonesel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -550,8 +570,8 @@ static int snd_ac97_stac9758_phonesel_pu { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - return snd_ac97_update_bits(ac97, AC97_SIGMATEL_IOMISC, 3, - ucontrol->value.enumerated.item[0]); + return ac97_update_bits_page(ac97, AC97_SIGMATEL_IOMISC, 3, + ucontrol->value.enumerated.item[0], 0); } #define STAC9758_OUTPUT_JACK(xname, shift) \ @@ -596,6 +616,14 @@ static int patch_sigmatel_stac9758_speci ARRAY_SIZE(snd_ac97_sigmatel_stac9758_controls)); if (err < 0) return err; + /* DAC-A direct */ + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Front Playback"); + /* DAC-A to Mix = PCM */ + /* DAC-B direct = Surround */ + /* DAC-B to Mix */ + snd_ac97_rename_vol_ctl(ac97, "Video Playback", "Surround Mix Playback"); + /* DAC-C direct = Center/LFE */ + return 0; } @@ -613,16 +641,16 @@ int patch_sigmatel_stac9758(ac97_t * ac9 AC97_SIGMATEL_VARIOUS }; static unsigned short def_regs[4] = { - /* OUTSEL */ 0xd794, + /* OUTSEL */ 0xd794, /* CL:CL, SR:SR, LO:MX, LI:DS, MI:DS */ /* IOMISC */ 0x2001, - /* INSEL */ 0x0201, + /* INSEL */ 0x0201, /* LI:LI, MI:M1 */ /* VARIOUS */ 0x0040 }; static unsigned short m675_regs[4] = { - /* OUTSEL */ 0x9040, - /* IOMISC */ 0x2102, - /* INSEL */ 0x0203, - /* VARIOUS */ 0x0041 + /* OUTSEL */ 0xfc70, /* CL:MX, SR:MX, LO:DS, LI:MX, MI:DS */ + /* IOMISC */ 0x2102, /* HP amp on */ + /* INSEL */ 0x0203, /* LI:LI, MI:FR */ + /* VARIOUS */ 0x0041 /* stereo mic */ }; unsigned short *pregs = def_regs; int i; @@ -635,6 +663,8 @@ int patch_sigmatel_stac9758(ac97_t * ac9 // patch for SigmaTel ac97->build_ops = &patch_sigmatel_stac9758_ops; + /* FIXME: assume only page 0 for writing cache */ + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); for (i = 0; i < 4; i++) snd_ac97_write_cache(ac97, regs[i], pregs[i]); @@ -654,8 +684,10 @@ static int patch_cirrus_build_spdif(ac97 { int err; + /* con mask, pro mask, default */ if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) return err; + /* switch, spsa */ if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0) return err; switch (ac97->id & AC97_ID_CS_MASK) { @@ -714,8 +746,10 @@ static int patch_conexant_build_spdif(ac { int err; + /* con mask, pro mask, default */ if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) return err; + /* switch */ if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0) return err; /* set default PCM S/PDIF params */ @@ -734,6 +768,7 @@ int patch_conexant(ac97_t * ac97) ac97->build_ops = &patch_conexant_ops; ac97->flags |= AC97_CX_SPDIF; ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ return 0; } @@ -821,8 +856,6 @@ int patch_ad1881(ac97_t * ac97) unsigned short val; int idx, num; - init_MUTEX(&ac97->spec.ad18xx.mutex); - val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val); codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12)); @@ -1114,10 +1147,8 @@ static const snd_kcontrol_new_t snd_ac97 static int patch_ad1888_specific(ac97_t *ac97) { /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ - snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch"); - snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume"); - snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); - snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Master Surround Playback"); + snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls)); } @@ -1213,7 +1244,7 @@ int patch_ad1985(ac97_t * ac97) } /* - * realtek ALC65x codecs + * realtek ALC65x/850 codecs */ static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) { @@ -1303,6 +1334,17 @@ int patch_alc650(ac97_t * ac97) ac97->build_ops = &patch_alc650_ops; + /* determine the revision */ + val = snd_ac97_read(ac97, AC97_ALC650_REVISION) & 0x3f; + if (val < 3) + ac97->id = 0x414c4720; /* Old version */ + else if (val < 0x10) + ac97->id = 0x414c4721; /* D version */ + else if (val < 0x20) + ac97->id = 0x414c4722; /* E version */ + else if (val < 0x30) + ac97->id = 0x414c4723; /* F version */ + /* revision E or F */ /* FIXME: what about revision D ? */ ac97->spec.dev_flags = (ac97->id == 0x414c4722 || @@ -1351,20 +1393,19 @@ static int snd_ac97_alc655_mic_get(snd_k static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - int change; /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, ucontrol->value.integer.value[0] ? (1 << 12) : 0); - change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0); - return change; + return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, + ucontrol->value.integer.value[0] ? (1 << 10) : 0, + 0); } static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { - AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), - AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), + AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic As Center/LFE", @@ -1391,7 +1432,6 @@ static int alc655_iec958_route_info(snd_ texts_658[uinfo->value.enumerated.item] : texts_655[uinfo->value.enumerated.item]); return 0; - } static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) @@ -1410,13 +1450,15 @@ static int alc655_iec958_route_get(snd_k static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12, - (unsigned short)ucontrol->value.enumerated.item[0]); + + return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12, + (unsigned short)ucontrol->value.enumerated.item[0], + 0); } static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = { - AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), - AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0), + AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0), + AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC958 Playback Route", @@ -1451,6 +1493,9 @@ int patch_alc655(ac97_t * ac97) ac97->build_ops = &patch_alc655_ops; + /* assume only page 0 for writing cache */ + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); + /* adjust default values */ val = snd_ac97_read(ac97, 0x7a); /* misc control */ val |= (1 << 1); /* spdif input pin */ @@ -1469,6 +1514,120 @@ int patch_alc655(ac97_t * ac97) return 0; } + +#define AC97_ALC850_JACK_SELECT 0x76 +#define AC97_ALC850_MISC1 0x7a + +static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; + return 0; +} + +static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + /* SURR 1kOhm (bit4), Amp (bit5) */ + snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), + ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); + /* LINE-IN = 0, SURROUND = 2 */ + return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, + ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); +} + +static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; + return 0; +} + +static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + /* Vref disable (bit12), 1kOhm (bit13) */ + snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), + ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); + /* MIC-IN = 1, CENTER-LFE = 2 */ + return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, + ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); +} + +static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { + AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line-In As Surround", + .info = snd_ac97_info_single, + .get = ac97_alc850_surround_get, + .put = ac97_alc850_surround_put, + .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic As Center/LFE", + .info = snd_ac97_info_single, + .get = ac97_alc850_mic_get, + .put = ac97_alc850_mic_put, + .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ + }, + +}; + +static int patch_alc850_specific(ac97_t *ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850))) < 0) + return err; + if (ac97->ext_id & AC97_EI_SPDIF) { + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) + return err; + } + return 0; +} + +static struct snd_ac97_build_ops patch_alc850_ops = { + .build_specific = patch_alc850_specific +}; + +int patch_alc850(ac97_t *ac97) +{ + ac97->build_ops = &patch_alc850_ops; + + ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */ + + /* assume only page 0 for writing cache */ + snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); + + /* adjust default values */ + /* set default: spdif-in enabled, + spdif-in monitor off, spdif-in PCM off + center on mic off, surround on line-in off + duplicate front off + */ + snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15); + /* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off + * Front Amp: on, Vref: enable, Center 1kOhm: on, Mix: on + */ + snd_ac97_write_cache(ac97, 0x7a, (1<<1)|(1<<4)|(0<<5)|(1<<6)| + (1<<7)|(0<<12)|(1<<13)|(0<<14)); + /* detection UIO2,3: all path floating, UIO3: MIC, Vref2: disable, + * UIO1: FRONT, Vref3: disable, UIO3: LINE, Front-Mic: mute + */ + snd_ac97_write_cache(ac97, 0x76, (0<<0)|(0<<2)|(1<<4)|(1<<7)|(2<<8)| + (1<<11)|(0<<12)|(1<<15)); + + /* full DAC volume */ + snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); + snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); + return 0; +} + + /* * C-Media CM97xx codecs */ @@ -1599,8 +1758,10 @@ int patch_cm9739(ac97_t * ac97) /* enable spdif in */ snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL, snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) | 0x01); + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ } else { ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */ + ac97->rates[AC97_RATES_SPDIF] = 0; } /* set-up multi channel */ --- linux-2.6.8-rc1/sound/pci/ac97/ac97_patch.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/ac97/ac97_patch.h 2004-07-13 17:09:19.000000000 -0700 @@ -49,6 +49,7 @@ int patch_ad1981b(ac97_t * ac97); int patch_ad1985(ac97_t * ac97); int patch_alc650(ac97_t * ac97); int patch_alc655(ac97_t * ac97); +int patch_alc850(ac97_t * ac97); int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); int patch_vt1616(ac97_t * ac97); --- linux-2.6.8-rc1/sound/pci/ac97/ac97_pcm.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ac97/ac97_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,8 +36,6 @@ #include "ac97_id.h" #include "ac97_local.h" -#define chip_t ac97_t - /* * PCM support */ @@ -430,7 +428,7 @@ int snd_ac97_pcm_assign(ac97_bus_t *bus, unsigned int rates; ac97_t *codec; - rpcms = snd_kcalloc(sizeof(struct ac97_pcm) * pcms_count, GFP_KERNEL); + rpcms = kcalloc(pcms_count, sizeof(struct ac97_pcm), GFP_KERNEL); if (rpcms == NULL) return -ENOMEM; memset(avail_slots, 0, sizeof(avail_slots)); --- linux-2.6.8-rc1/sound/pci/ac97/ac97_proc.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ac97/ac97_proc.c 2004-07-13 17:09:19.000000000 -0700 @@ -290,11 +290,11 @@ static void snd_ac97_proc_read_main(ac97 static void snd_ac97_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); + ac97_t *ac97 = entry->private_data; + down(&ac97->mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; - down(&ac97->spec.ad18xx.mutex); for (idx = 0; idx < 3; idx++) if (ac97->spec.ad18xx.id[idx]) { /* select single codec */ @@ -305,7 +305,6 @@ static void snd_ac97_proc_read(snd_info_ } /* select all codecs */ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000); - up(&ac97->spec.ad18xx.mutex); snd_iprintf(buffer, "\nAD18XX configuration\n"); snd_iprintf(buffer, "Unchained : 0x%04x,0x%04x,0x%04x\n", @@ -319,15 +318,17 @@ static void snd_ac97_proc_read(snd_info_ } else { snd_ac97_proc_read_main(ac97, buffer, 0); } + up(&ac97->mutex); } #ifdef CONFIG_SND_DEBUG /* direct register write for debugging */ static void snd_ac97_proc_regs_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); + ac97_t *ac97 = entry->private_data; char line[64]; unsigned int reg, val; + down(&ac97->mutex); while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; @@ -335,6 +336,7 @@ static void snd_ac97_proc_regs_write(snd if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff) snd_ac97_write_cache(ac97, reg, val); } + up(&ac97->mutex); } #endif @@ -351,12 +353,12 @@ static void snd_ac97_proc_regs_read_main static void snd_ac97_proc_regs_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return); + ac97_t *ac97 = entry->private_data; + down(&ac97->mutex); if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) { // Analog Devices AD1881/85/86 int idx; - down(&ac97->spec.ad18xx.mutex); for (idx = 0; idx < 3; idx++) if (ac97->spec.ad18xx.id[idx]) { /* select single codec */ @@ -366,10 +368,10 @@ static void snd_ac97_proc_regs_read(snd_ } /* select all codecs */ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000); - up(&ac97->spec.ad18xx.mutex); } else { snd_ac97_proc_regs_read_main(ac97, buffer, 0); } + up(&ac97->mutex); } void snd_ac97_proc_init(ac97_t * ac97) --- linux-2.6.8-rc1/sound/pci/ac97/ak4531_codec.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/ac97/ak4531_codec.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,6 @@ MODULE_AUTHOR("Jaroslav Kysela private_free) ak4531->private_free(ak4531); - snd_magic_kfree(ak4531); + kfree(ak4531); } return 0; } static int snd_ak4531_dev_free(snd_device_t *device) { - ak4531_t *ak4531 = snd_magic_cast(ak4531_t, device->device_data, return -ENXIO); + ak4531_t *ak4531 = device->device_data; return snd_ak4531_free(ak4531); } @@ -367,7 +365,7 @@ int snd_ak4531_mixer(snd_card_t * card, snd_assert(rak4531 != NULL, return -EINVAL); *rak4531 = NULL; snd_assert(card != NULL && _ak4531 != NULL, return -EINVAL); - ak4531 = snd_magic_kcalloc(ak4531_t, 0, GFP_KERNEL); + ak4531 = kcalloc(1, sizeof(*ak4531), GFP_KERNEL); if (ak4531 == NULL) return -ENOMEM; *ak4531 = *_ak4531; @@ -411,7 +409,7 @@ int snd_ak4531_mixer(snd_card_t * card, static void snd_ak4531_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ak4531_t *ak4531 = snd_magic_cast(ak4531_t, entry->private_data, return); + ak4531_t *ak4531 = entry->private_data; snd_iprintf(buffer, "Asahi Kasei AK4531\n\n"); snd_iprintf(buffer, "Recording source : %s\n" --- linux-2.6.8-rc1/sound/pci/ali5451/ali5451.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ali5451/ali5451.c 2004-07-13 17:09:19.000000000 -0700 @@ -43,8 +43,7 @@ MODULE_AUTHOR("Matt Wu "); MODULE_DESCRIPTION("ALI M5451"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ALI,M5451,pci},{ALI,M5451}}"); +MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -55,19 +54,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ALI 5451 PCI Audio."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "PCM Channels"); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",default:32,allows:{{1,32}}"); module_param_array(spdif, bool, boot_devs, 0444); MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); -MODULE_PARM_SYNTAX(spdif, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); /* * Debug part definitions @@ -171,7 +165,6 @@ MODULE_PARM_SYNTAX(spdif, SNDRV_ENABLED typedef struct snd_stru_ali ali_t; typedef struct snd_ali_stru_voice snd_ali_voice_t; -#define chip_t ali_t typedef struct snd_ali_channel_control { // register data @@ -495,7 +488,7 @@ static void snd_ali_codec_write(ac97_t * unsigned short reg, unsigned short val ) { - ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return); + ali_t *codec = ac97->private_data; snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); snd_ali_codec_poke(codec, 0, reg, val); @@ -505,7 +498,7 @@ static void snd_ali_codec_write(ac97_t * static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg) { - ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return -ENXIO); + ali_t *codec = ac97->private_data; snd_ali_printk("codec_read reg=%xh.\n", reg); return (snd_ali_codec_peek(codec, 0, reg)); @@ -1051,7 +1044,7 @@ static irqreturn_t snd_ali_card_interrup void *dev_id, struct pt_regs *regs) { - ali_t *codec = snd_magic_cast(ali_t, dev_id, return IRQ_NONE); + ali_t *codec = dev_id; if (codec == NULL) return IRQ_NONE; @@ -1247,7 +1240,7 @@ static int snd_ali_trigger(snd_pcm_subst what = whati = capture_flag = 0; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); - if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) { + if ((ali_t *) snd_pcm_substream_chip(s) == codec) { pvoice = (snd_ali_voice_t *) s->runtime->private_data; evoice = pvoice->extra; what |= 1 << (pvoice->number & 0x1f); @@ -1720,7 +1713,7 @@ static snd_pcm_ops_t snd_ali_capture_ops static void snd_ali_pcm_free(snd_pcm_t *pcm) { - ali_t *codec = snd_magic_cast(ali_t, pcm->private_data, return); + ali_t *codec = pcm->private_data; codec->pcm = NULL; } @@ -1769,7 +1762,7 @@ static int snd_ali5451_spdif_info(snd_kc static int snd_ali5451_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { unsigned long flags; - ali_t *codec = snd_magic_cast(ali_t, kcontrol->private_data, -ENXIO); + ali_t *codec = kcontrol->private_data; unsigned int enable; enable = ucontrol->value.integer.value[0] ? 1 : 0; @@ -1796,7 +1789,7 @@ static int snd_ali5451_spdif_get(snd_kco static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { unsigned long flags; - ali_t *codec = snd_magic_cast(ali_t, kcontrol->private_data, -ENXIO); + ali_t *codec = kcontrol->private_data; unsigned int change = 0, enable = 0; enable = ucontrol->value.integer.value[0] ? 1 : 0; @@ -1863,13 +1856,13 @@ static snd_kcontrol_new_t snd_ali5451_mi static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) { - ali_t *codec = snd_magic_cast(ali_t, bus->private_data, return); + ali_t *codec = bus->private_data; codec->ac97_bus = NULL; } static void snd_ali_mixer_free_ac97(ac97_t *ac97) { - ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return); + ali_t *codec = ac97->private_data; codec->ac97 = NULL; } @@ -1907,7 +1900,7 @@ static int __devinit snd_ali_mixer(ali_t #ifdef CONFIG_PM static int ali_suspend(snd_card_t *card, unsigned int state) { - ali_t *chip = snd_magic_cast(ali_t, card->pm_private_data, return -EINVAL); + ali_t *chip = card->pm_private_data; ali_image_t *im; int i, j; @@ -1948,7 +1941,7 @@ static int ali_suspend(snd_card_t *card, static int ali_resume(snd_card_t *card, unsigned int state) { - ali_t *chip = snd_magic_cast(ali_t, card->pm_private_data, return -EINVAL); + ali_t *chip = card->pm_private_data; ali_image_t *im; int i, j; @@ -2001,7 +1994,7 @@ static int snd_ali_free(ali_t * codec) if (codec->image) kfree(codec->image); #endif - snd_magic_kfree(codec); + kfree(codec); return 0; } @@ -2071,7 +2064,7 @@ static int __devinit snd_ali_resources(a } static int snd_ali_dev_free(snd_device_t *device) { - ali_t *codec=snd_magic_cast(ali_t, device->device_data, return -ENXIO); + ali_t *codec=device->device_data; snd_ali_free(codec); return 0; } @@ -2106,7 +2099,7 @@ static int __devinit snd_ali_create(snd_ return -ENXIO; } - if ((codec = snd_magic_kcalloc(ali_t, 0, GFP_KERNEL)) == NULL) + if ((codec = kcalloc(1, sizeof(*codec), GFP_KERNEL)) == NULL) return -ENOMEM; spin_lock_init(&codec->reg_lock); --- linux-2.6.8-rc1/sound/pci/als4000.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/als4000.c 2004-07-13 17:09:19.000000000 -0700 @@ -76,8 +76,7 @@ MODULE_AUTHOR("Bart Hartgers "); MODULE_DESCRIPTION("Avance Logic ALS4000"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Avance Logic,ALS4000}}"); +MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}"); #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) #define SUPPORT_JOYSTICK 1 @@ -93,21 +92,15 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ALS4000 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ALS4000 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); #ifdef SUPPORT_JOYSTICK module_param_array(joystick_port, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)"); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED); #endif -#define chip_t sb_t - typedef struct { unsigned long gcr; struct resource *res_gcr; @@ -368,7 +361,7 @@ static snd_pcm_uframes_t snd_als4000_pla static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); + sb_t *chip = dev_id; unsigned long flags; unsigned gcr_status; unsigned sb_status; @@ -506,7 +499,7 @@ static snd_pcm_ops_t snd_als4000_capture static void snd_als4000_pcm_free(snd_pcm_t *pcm) { - sb_t *chip = snd_magic_cast(sb_t, pcm->private_data, return); + sb_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } --- linux-2.6.8-rc1/sound/pci/atiixp.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/atiixp.c 2004-07-13 17:09:19.000000000 -0700 @@ -1,5 +1,5 @@ /* - * ALSA driver for ATI IXP 150/200/250 AC97 controllers + * ALSA driver for ATI IXP 150/200/250/300 AC97 controllers * * Copyright (c) 2004 Takashi Iwai * @@ -37,8 +37,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("ATI IXP AC97 controller"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ATI,IXP150/200/250/300}}"); +MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -49,19 +48,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ATI IXP controller."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(ac97_clock, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); -MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); module_param_array(spdif_aclink, bool, boot_devs, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); -MODULE_PARM_SYNTAX(spdif_aclink, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); /* @@ -207,7 +201,6 @@ MODULE_PARM_SYNTAX(spdif_aclink, SNDRV_E typedef struct snd_atiixp atiixp_t; typedef struct snd_atiixp_dma atiixp_dma_t; typedef struct snd_atiixp_dma_ops atiixp_dma_ops_t; -#define chip_t atiixp_t /* @@ -491,7 +484,7 @@ static void snd_atiixp_codec_write(atiix static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg) { - atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return 0xffff); + atiixp_t *chip = ac97->private_data; unsigned short data; spin_lock(&chip->ac97_lock); data = snd_atiixp_codec_read(chip, ac97->num, reg); @@ -502,7 +495,7 @@ static unsigned short snd_atiixp_ac97_re static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return); + atiixp_t *chip = ac97->private_data; spin_lock(&chip->ac97_lock); snd_atiixp_codec_write(chip, ac97->num, reg, val); spin_unlock(&chip->ac97_lock); @@ -996,6 +989,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_48000, @@ -1308,7 +1302,7 @@ static int __devinit snd_atiixp_pcm_new( */ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - atiixp_t *chip = snd_magic_cast(atiixp_t, dev_id, return IRQ_NONE); + atiixp_t *chip = dev_id; unsigned int status; status = atiixp_read(chip, ISR); @@ -1387,17 +1381,9 @@ static int __devinit snd_atiixp_mixer_ne ac97.num = i; ac97.scaps = AC97_SCAP_SKIP_MODEM; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { - if (chip->codec_not_ready_bits) - /* codec(s) was detected but not available. - * return the error - */ - return err; - else { - /* codec(s) was NOT detected, so just ignore here */ - chip->ac97[i] = NULL; /* to be sure */ - snd_printd("atiixp: codec %d not found\n", i); - continue; - } + chip->ac97[i] = NULL; /* to be sure */ + snd_printdd("atiixp: codec %d not available for audio\n", i); + continue; } codec_count++; } @@ -1419,7 +1405,7 @@ static int __devinit snd_atiixp_mixer_ne */ static int snd_atiixp_suspend(snd_card_t *card, unsigned int state) { - atiixp_t *chip = snd_magic_cast(atiixp_t, card->pm_private_data, return -EINVAL); + atiixp_t *chip = card->pm_private_data; int i; for (i = 0; i < NUM_ATI_PCMDEVS; i++) @@ -1440,7 +1426,7 @@ static int snd_atiixp_suspend(snd_card_t static int snd_atiixp_resume(snd_card_t *card, unsigned int state) { - atiixp_t *chip = snd_magic_cast(atiixp_t, card->pm_private_data, return -EINVAL); + atiixp_t *chip = card->pm_private_data; int i; pci_enable_device(chip->pci); @@ -1466,7 +1452,7 @@ static int snd_atiixp_resume(snd_card_t static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - atiixp_t *chip = snd_magic_cast(atiixp_t, entry->private_data, return); + atiixp_t *chip = entry->private_data; int i; for (i = 0; i < 256; i += 4) @@ -1502,13 +1488,13 @@ static int snd_atiixp_free(atiixp_t *chi } if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_atiixp_dev_free(snd_device_t *device) { - atiixp_t *chip = snd_magic_cast(atiixp_t, device->device_data, return -ENXIO); + atiixp_t *chip = device->device_data; return snd_atiixp_free(chip); } @@ -1528,7 +1514,7 @@ static int __devinit snd_atiixp_create(s if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(atiixp_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_a3d.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0_a3d.c 2004-07-13 17:09:19.000000000 -0700 @@ -567,7 +567,7 @@ static int Vort3DRend_Initialize(vortex_ v->xt_mode = mode; /* this_14 */ vortex_XtalkHw_init(v); - vortex_XtalkHw_SetGains(v, asXtalkGainsAllChan); + vortex_XtalkHw_SetGains(v, vortex_asXtalkGainsAllChan); switch (v->xt_mode) { case XT_SPEAKER0: vortex_XtalkHw_ProgramXtalkNarrow(v); @@ -864,7 +864,7 @@ static int vortex_a3d_register_controls( if ((kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) return -ENOMEM; - kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->private_value = (long)&(vortex->a3d[i]); kcontrol->id.numid = CTRLID_HRTF; kcontrol->info = snd_vortex_a3d_hrtf_info; kcontrol->put = snd_vortex_a3d_hrtf_put; @@ -876,7 +876,7 @@ static int vortex_a3d_register_controls( if ((kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) return -ENOMEM; - kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->private_value = (long)&(vortex->a3d[i]); kcontrol->id.numid = CTRLID_ITD; kcontrol->info = snd_vortex_a3d_itd_info; kcontrol->put = snd_vortex_a3d_itd_put; @@ -888,7 +888,7 @@ static int vortex_a3d_register_controls( if ((kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) return -ENOMEM; - kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->private_value = (long)&(vortex->a3d[i]); kcontrol->id.numid = CTRLID_GAINS; kcontrol->info = snd_vortex_a3d_ild_info; kcontrol->put = snd_vortex_a3d_ild_put; @@ -900,7 +900,7 @@ static int vortex_a3d_register_controls( if ((kcontrol = snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) return -ENOMEM; - kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->private_value = (long)&(vortex->a3d[i]); kcontrol->id.numid = CTRLID_FILTER; kcontrol->info = snd_vortex_a3d_filter_info; kcontrol->put = snd_vortex_a3d_filter_put; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0.c 2004-07-13 17:09:19.000000000 -0700 @@ -31,23 +31,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(pcifix, int, boot_devs, 0444); MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(pcifix, - SNDRV_ENABLED - ",allows:{{0,Disabled},{1,Latency},{2,Bridge},{3,Both},{255,Auto}},default:4,dialog:check"); MODULE_DESCRIPTION("Aureal vortex"); -MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); -MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); +MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); MODULE_DEVICE_TABLE(pci, snd_vortex_ids); @@ -122,8 +115,7 @@ static void __devinit snd_vortex_workaro // (see "Management of Cards and Components") static int snd_vortex_dev_free(snd_device_t * device) { - vortex_t *vortex = snd_magic_cast(vortex_t, device->device_data, - return -ENXIO); + vortex_t *vortex = device->device_data; vortex_gameport_unregister(vortex); vortex_core_shutdown(vortex); @@ -132,7 +124,7 @@ static int snd_vortex_dev_free(snd_devic free_irq(vortex->irq, vortex); pci_release_regions(vortex->pci_dev); pci_disable_device(vortex->pci_dev); - snd_magic_kfree(vortex); + kfree(vortex); return 0; } @@ -159,7 +151,7 @@ snd_vortex_create(snd_card_t * card, str } pci_set_dma_mask(pci, VORTEX_DMA_MASK); - chip = snd_magic_kcalloc(vortex_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_core.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0_core.c 2004-07-13 17:09:19.000000000 -0700 @@ -2362,7 +2362,7 @@ static void vortex_disable_int(vortex_t static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - vortex_t *vortex = snd_magic_cast(vortex_t, dev_id, return IRQ_NONE); + vortex_t *vortex = dev_id; int i, handled; u32 source; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_game.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0_game.c 2004-07-13 17:09:19.000000000 -0700 @@ -96,7 +96,7 @@ static int vortex_game_open(struct gamep static int vortex_gameport_register(vortex_t * vortex) { - if ((vortex->gameport = snd_kcalloc(sizeof(struct gameport), GFP_KERNEL)) == NULL) { + if ((vortex->gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL)) == NULL) { return -1; }; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0.h 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0.h 2004-07-13 17:09:19.000000000 -0700 @@ -180,8 +180,6 @@ struct snd_vortex { u8 rev; }; -#define chip_t vortex_t - /* Functions. */ /* SRC */ --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_mpu401.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/au88x0/au88x0_mpu401.c 2004-07-13 17:09:19.000000000 -0700 @@ -104,7 +104,7 @@ static int __devinit snd_vortex_midi(vor ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); return temp; } - mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return -ENOMEM); + mpu = rmidi->private_data; mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2)); #endif vortex->rmidi = rmidi; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_pcm.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/au88x0/au88x0_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,7 +28,6 @@ #include #include "au88x0.h" -#define chip_t vortex_t #define VORTEX_PCM_TYPE(x) (x->name[40]) /* hardware definition */ @@ -189,7 +188,7 @@ static int snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { - chip_t *chip = snd_pcm_substream_chip(substream); + vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) (substream->runtime->private_data); snd_pcm_sgbuf_t *sgbuf; int err; @@ -250,7 +249,7 @@ snd_vortex_pcm_hw_params(snd_pcm_substre /* hw_free callback */ static int snd_vortex_pcm_hw_free(snd_pcm_substream_t * substream) { - chip_t *chip = snd_pcm_substream_chip(substream); + vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) (substream->runtime->private_data); // Delete audio routes. @@ -305,7 +304,7 @@ static int snd_vortex_pcm_prepare(snd_pc /* trigger callback */ static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd) { - chip_t *chip = snd_pcm_substream_chip(substream); + vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) substream->runtime->private_data; int dma = stream->dma; --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_xtalk.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/au88x0/au88x0_xtalk.c 2004-07-13 17:09:19.000000000 -0700 @@ -61,7 +61,7 @@ static xtalk_gains_t const asXtalkGains1 }; // Input gain for 4 A3D slices. One possible input pair is left zero. -static xtalk_gains_t const asXtalkGainsAllChan = { +xtalk_gains_t const vortex_asXtalkGainsAllChan = { 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0 //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff --- linux-2.6.8-rc1/sound/pci/au88x0/au88x0_xtalk.h 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/au88x0/au88x0_xtalk.h 2004-07-13 17:09:19.000000000 -0700 @@ -45,7 +45,7 @@ typedef short xtalk_instate_t[XTINST_SZ] typedef short xtalk_coefs_t[5][5]; typedef short xtalk_state_t[5][4]; -extern xtalk_gains_t const asXtalkGainsAllChan; +extern xtalk_gains_t const vortex_asXtalkGainsAllChan; static void vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains); --- linux-2.6.8-rc1/sound/pci/azt3328.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/azt3328.c 2004-07-13 17:09:19.000000000 -0700 @@ -111,8 +111,7 @@ MODULE_AUTHOR("Andreas Mohr "); MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Aztech,AZF3328}}"); +MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) #define SUPPORT_JOYSTICK 1 @@ -170,21 +169,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); #ifdef SUPPORT_JOYSTICK module_param_array(joystick, bool, boot_devs, 0444); MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); -MODULE_PARM_SYNTAX(joystick, SNDRV_BOOLEAN_FALSE_DESC); #endif typedef struct _snd_azf3328 azf3328_t; -#define chip_t azf3328_t struct _snd_azf3328 { int irq; @@ -1032,7 +1026,7 @@ static snd_pcm_uframes_t snd_azf3328_cap static irqreturn_t snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - azf3328_t *chip = snd_magic_cast(azf3328_t, dev_id, return IRQ_NONE); + azf3328_t *chip = dev_id; unsigned int status, which; static unsigned long count; @@ -1232,7 +1226,7 @@ static snd_pcm_ops_t snd_azf3328_capture static void snd_azf3328_pcm_free(snd_pcm_t *pcm) { - azf3328_t *chip = snd_magic_cast(azf3328_t, pcm->private_data, return); + azf3328_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1310,13 +1304,13 @@ static int snd_azf3328_free(azf3328_t *c if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_azf3328_dev_free(snd_device_t *device) { - azf3328_t *chip = snd_magic_cast(azf3328_t, device->device_data, return -ENXIO); + azf3328_t *chip = device->device_data; return snd_azf3328_free(chip); } @@ -1358,7 +1352,7 @@ static int __devinit snd_azf3328_create( if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(azf3328_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); --- linux-2.6.8-rc1/sound/pci/bt87x.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/bt87x.c 2004-07-13 17:09:19.000000000 -0700 @@ -38,8 +38,7 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("Brooktree Bt87x audio driver"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Brooktree,Bt878}," +MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878}," "{Brooktree,Bt879}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -50,16 +49,12 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Bt87x soundcard"); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Bt87x soundcard"); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Bt87x soundcard"); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(digital_rate, int, boot_devs, 0444); MODULE_PARM_DESC(digital_rate, "Digital input rate for Bt87x soundcard"); -MODULE_PARM_SYNTAX(digital_rate, SNDRV_ENABLED); #ifndef PCI_VENDOR_ID_BROOKTREE @@ -152,7 +147,6 @@ MODULE_PARM_SYNTAX(digital_rate, SNDRV_E /* SYNC, one WRITE per line, one extra WRITE per page boundary, SYNC, JUMP */ #define MAX_RISC_SIZE ((1 + 255 + (PAGE_ALIGN(255 * 4092) / PAGE_SIZE - 1) + 1 + 1) * 8) -#define chip_t bt87x_t typedef struct snd_bt87x bt87x_t; struct snd_bt87x { snd_card_t *card; @@ -251,7 +245,7 @@ static void snd_bt87x_free_risc(bt87x_t static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - bt87x_t *chip = snd_magic_cast(bt87x_t, dev_id, return IRQ_NONE); + bt87x_t *chip = dev_id; unsigned int status; status = snd_bt87x_readl(chip, REG_INT_STAT); @@ -661,13 +655,13 @@ static int snd_bt87x_free(bt87x_t *chip) } if (chip->irq >= 0) free_irq(chip->irq, chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_bt87x_dev_free(snd_device_t *device) { - bt87x_t *chip = snd_magic_cast(bt87x_t, device->device_data, return -ENXIO); + bt87x_t *chip = device->device_data; return snd_bt87x_free(chip); } @@ -705,7 +699,7 @@ static int __devinit snd_bt87x_create(sn if (err < 0) return err; - chip = snd_magic_kcalloc(bt87x_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->card = card; --- linux-2.6.8-rc1/sound/pci/cmipci.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/cmipci.c 2004-07-13 17:09:19.000000000 -0700 @@ -43,8 +43,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("C-Media CMI8x38 PCI"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{C-Media,CMI8738}," +MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8738}," "{C-Media,CMI8738B}," "{C-Media,CMI8338A}," "{C-Media,CMI8338B}}"); @@ -66,25 +65,19 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for C-Media PCI soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for C-Media PCI soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable C-Media PCI soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x320},{0x310},{0x300}},dialog:list"); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM port."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list"); module_param_array(soft_ac3, bool, boot_devs, 0444); MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only)."); #ifdef SUPPORT_JOYSTICK module_param_array(joystick_port, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address."); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x201}},dialog:list"); #endif #ifndef PCI_DEVICE_ID_CMEDIA_CM8738 @@ -405,8 +398,6 @@ MODULE_PARM_SYNTAX(joystick_port, SNDRV_ typedef struct snd_stru_cmipci cmipci_t; typedef struct snd_stru_cmipci_pcm cmipci_pcm_t; -#define chip_t cmipci_t - struct snd_stru_cmipci_pcm { snd_pcm_substream_t *substream; int running; /* dac/adc running? */ @@ -1072,30 +1063,36 @@ static snd_kcontrol_new_t snd_cmipci_spd */ /* save mixer setting and mute for AC3 playback */ -static void save_mixer_state(cmipci_t *cm) +static int save_mixer_state(cmipci_t *cm) { if (! cm->mixer_insensitive) { + snd_ctl_elem_value_t *val; unsigned int i; + + val = kmalloc(sizeof(*val), GFP_ATOMIC); + if (!val) + return -ENOMEM; for (i = 0; i < CM_SAVED_MIXERS; i++) { snd_kcontrol_t *ctl = cm->mixer_res_ctl[i]; if (ctl) { - snd_ctl_elem_value_t val; int event; - memset(&val, 0, sizeof(val)); - ctl->get(ctl, &val); - cm->mixer_res_status[i] = val.value.integer.value[0]; - val.value.integer.value[0] = cm_saved_mixer[i].toggle_on; + memset(val, 0, sizeof(*val)); + ctl->get(ctl, val); + cm->mixer_res_status[i] = val->value.integer.value[0]; + val->value.integer.value[0] = cm_saved_mixer[i].toggle_on; event = SNDRV_CTL_EVENT_MASK_INFO; - if (cm->mixer_res_status[i] != val.value.integer.value[0]) { - ctl->put(ctl, &val); /* toggle */ + if (cm->mixer_res_status[i] != val->value.integer.value[0]) { + ctl->put(ctl, val); /* toggle */ event |= SNDRV_CTL_EVENT_MASK_VALUE; } ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(cm->card, event, &ctl->id); } } + kfree(val); cm->mixer_insensitive = 1; } + return 0; } @@ -1103,27 +1100,32 @@ static void save_mixer_state(cmipci_t *c static void restore_mixer_state(cmipci_t *cm) { if (cm->mixer_insensitive) { + snd_ctl_elem_value_t *val; unsigned int i; + + val = kmalloc(sizeof(*val), GFP_KERNEL); + if (!val) + return; cm->mixer_insensitive = 0; /* at first clear this; otherwise the changes will be ignored */ for (i = 0; i < CM_SAVED_MIXERS; i++) { snd_kcontrol_t *ctl = cm->mixer_res_ctl[i]; if (ctl) { - snd_ctl_elem_value_t val; int event; - memset(&val, 0, sizeof(val)); + memset(val, 0, sizeof(*val)); ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->get(ctl, &val); + ctl->get(ctl, val); event = SNDRV_CTL_EVENT_MASK_INFO; - if (val.value.integer.value[0] != cm->mixer_res_status[i]) { - val.value.integer.value[0] = cm->mixer_res_status[i]; - ctl->put(ctl, &val); + if (val->value.integer.value[0] != cm->mixer_res_status[i]) { + val->value.integer.value[0] = cm->mixer_res_status[i]; + ctl->put(ctl, val); event |= SNDRV_CTL_EVENT_MASK_VALUE; } snd_ctl_notify(cm->card, event, &ctl->id); } } + kfree(val); } } @@ -1175,15 +1177,16 @@ static void setup_ac3(cmipci_t *cm, snd_ } } -static void setup_spdif_playback(cmipci_t *cm, snd_pcm_substream_t *subs, int up, int do_ac3) +static int setup_spdif_playback(cmipci_t *cm, snd_pcm_substream_t *subs, int up, int do_ac3) { - int rate; + int rate, err; unsigned long flags; rate = subs->runtime->rate; if (up && do_ac3) - save_mixer_state(cm); + if ((err = save_mixer_state(cm)) < 0) + return err; spin_lock_irqsave(&cm->reg_lock, flags); cm->spdif_playback_avail = up; @@ -1208,6 +1211,7 @@ static void setup_spdif_playback(cmipci_ setup_ac3(cm, subs, 0, 0); } spin_unlock_irqrestore(&cm->reg_lock, flags); + return 0; } @@ -1220,13 +1224,15 @@ static int snd_cmipci_playback_prepare(s { cmipci_t *cm = snd_pcm_substream_chip(substream); int rate = substream->runtime->rate; - int do_spdif, do_ac3 = 0; + int err, do_spdif, do_ac3 = 0; + do_spdif = ((rate == 44100 || rate == 48000) && substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && substream->runtime->channels == 2); if (do_spdif && cm->can_ac3_hw) do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO; - setup_spdif_playback(cm, substream, do_spdif, do_ac3); + if ((err = setup_spdif_playback(cm, substream, do_spdif, do_ac3)) < 0) + return err; return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } @@ -1234,12 +1240,14 @@ static int snd_cmipci_playback_prepare(s static int snd_cmipci_playback_spdif_prepare(snd_pcm_substream_t *substream) { cmipci_t *cm = snd_pcm_substream_chip(substream); - int do_ac3; + int err, do_ac3; + if (cm->can_ac3_hw) do_ac3 = cm->dig_pcm_status & IEC958_AES0_NONAUDIO; else do_ac3 = 1; /* doesn't matter */ - setup_spdif_playback(cm, substream, 1, do_ac3); + if ((err = setup_spdif_playback(cm, substream, 1, do_ac3)) < 0) + return err; return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } @@ -1289,7 +1297,7 @@ static int snd_cmipci_capture_spdif_hw_f */ static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - cmipci_t *cm = snd_magic_cast(cmipci_t, dev_id, return IRQ_NONE); + cmipci_t *cm = dev_id; unsigned int status, mask = 0; /* fastpath out, to ease interrupt sharing */ @@ -2446,7 +2454,7 @@ static int __devinit snd_cmipci_mixer_ne static void snd_cmipci_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - cmipci_t *cm = snd_magic_cast(cmipci_t, entry->private_data, return); + cmipci_t *cm = entry->private_data; int i; snd_iprintf(buffer, "%s\n\n", cm->card->longname); @@ -2570,13 +2578,13 @@ static int snd_cmipci_free(cmipci_t *cm) release_resource(cm->res_iobase); kfree_nocheck(cm->res_iobase); } - snd_magic_kfree(cm); + kfree(cm); return 0; } static int snd_cmipci_dev_free(snd_device_t *device) { - cmipci_t *cm = snd_magic_cast(cmipci_t, device->device_data, return -ENXIO); + cmipci_t *cm = device->device_data; return snd_cmipci_free(cm); } @@ -2598,7 +2606,7 @@ static int __devinit snd_cmipci_create(s if ((err = pci_enable_device(pci)) < 0) return err; - cm = snd_magic_kcalloc(cmipci_t, 0, GFP_KERNEL); + cm = kcalloc(1, sizeof(*cm), GFP_KERNEL); if (cm == NULL) return -ENOMEM; @@ -2776,12 +2784,12 @@ static int __devinit snd_cmipci_create(s int i; for (i = 0; ports[i]; i++) { joystick_port[dev] = ports[i]; - cm->res_joystick = request_region(ports[i], 8, "CMIPCI gameport"); + cm->res_joystick = request_region(ports[i], 1, "CMIPCI gameport"); if (cm->res_joystick) break; } } else { - cm->res_joystick = request_region(joystick_port[dev], 8, "CMIPCI gameport"); + cm->res_joystick = request_region(joystick_port[dev], 1, "CMIPCI gameport"); } } if (cm->res_joystick) { --- linux-2.6.8-rc1/sound/pci/cs4281.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/cs4281.c 2004-07-13 17:09:19.000000000 -0700 @@ -40,8 +40,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Cirrus Logic CS4281"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Cirrus Logic,CS4281}}"); +MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -51,16 +50,12 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for CS4281 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for CS4281 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable CS4281 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(dual_codec, bool, boot_devs, 0444); MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled)."); -MODULE_PARM_SYNTAX(dual_codec, SNDRV_ENABLED ",allows:{{0,3}}"); /* * @@ -441,8 +436,6 @@ MODULE_PARM_SYNTAX(dual_codec, SNDRV_ENA * */ -#define chip_t cs4281_t - typedef struct snd_cs4281 cs4281_t; typedef struct snd_cs4281_dma cs4281_dma_t; @@ -575,7 +568,7 @@ static void snd_cs4281_ac97_write(ac97_t * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h * 5. if DCV not cleared, break and return error */ - cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return); + cs4281_t *chip = ac97->private_data; int count; /* @@ -613,7 +606,7 @@ static void snd_cs4281_ac97_write(ac97_t static unsigned short snd_cs4281_ac97_read(ac97_t *ac97, unsigned short reg) { - cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return -ENXIO); + cs4281_t *chip = ac97->private_data; int count; unsigned short result; // FIXME: volatile is necessary in the following due to a bug of @@ -1015,7 +1008,7 @@ static snd_pcm_ops_t snd_cs4281_capture_ static void snd_cs4281_pcm_free(snd_pcm_t *pcm) { - cs4281_t *chip = snd_magic_cast(cs4281_t, pcm->private_data, return); + cs4281_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1124,13 +1117,13 @@ static snd_kcontrol_new_t snd_cs4281_pcm static void snd_cs4281_mixer_free_ac97_bus(ac97_bus_t *bus) { - cs4281_t *chip = snd_magic_cast(cs4281_t, bus->private_data, return); + cs4281_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_cs4281_mixer_free_ac97(ac97_t *ac97) { - cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return); + cs4281_t *chip = ac97->private_data; if (ac97->num) chip->ac97_secondary = NULL; else @@ -1177,7 +1170,7 @@ static int __devinit snd_cs4281_mixer(cs static void snd_cs4281_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs4281_t *chip = snd_magic_cast(cs4281_t, entry->private_data, return); + cs4281_t *chip = entry->private_data; snd_iprintf(buffer, "Cirrus Logic CS4281\n\n"); snd_iprintf(buffer, "Spurious half IRQs : %u\n", chip->spurious_dhtc_irq); @@ -1188,7 +1181,7 @@ static long snd_cs4281_BA0_read(snd_info struct file *file, char __user *buf, long count) { long size; - cs4281_t *chip = snd_magic_cast(cs4281_t, entry->private_data, return -ENXIO); + cs4281_t *chip = entry->private_data; size = count; if (file->f_pos + size > CS4281_BA0_SIZE) @@ -1205,7 +1198,7 @@ static long snd_cs4281_BA1_read(snd_info struct file *file, char __user *buf, long count) { long size; - cs4281_t *chip = snd_magic_cast(cs4281_t, entry->private_data, return -ENXIO); + cs4281_t *chip = entry->private_data; size = count; if (file->f_pos + size > CS4281_BA1_SIZE) @@ -1262,7 +1255,7 @@ static void snd_cs4281_gameport_trigger( cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport; cs4281_t *chip; snd_assert(gp, return); - chip = snd_magic_cast(cs4281_t, gp->chip, return); + chip = gp->chip; snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff); } @@ -1271,7 +1264,7 @@ static unsigned char snd_cs4281_gameport cs4281_gameport_t *gp = (cs4281_gameport_t *)gameport; cs4281_t *chip; snd_assert(gp, return 0); - chip = snd_magic_cast(cs4281_t, gp->chip, return 0); + chip = gp->chip; return snd_cs4281_peekBA0(chip, BA0_JSPT); } @@ -1283,7 +1276,7 @@ static int snd_cs4281_gameport_cooked_re unsigned js1, js2, jst; snd_assert(gp, return 0); - chip = snd_magic_cast(cs4281_t, gp->chip, return 0); + chip = gp->chip; js1 = snd_cs4281_peekBA0(chip, BA0_JSC1); js2 = snd_cs4281_peekBA0(chip, BA0_JSC2); @@ -1384,13 +1377,13 @@ static int snd_cs4281_free(cs4281_t *chi if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_cs4281_dev_free(snd_device_t *device) { - cs4281_t *chip = snd_magic_cast(cs4281_t, device->device_data, return -ENXIO); + cs4281_t *chip = device->device_data; return snd_cs4281_free(chip); } @@ -1415,7 +1408,7 @@ static int __devinit snd_cs4281_create(s *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(cs4281_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -1714,7 +1707,7 @@ static void snd_cs4281_midi_reset(cs4281 static int snd_cs4281_midi_input_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return -ENXIO); + cs4281_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr |= BA0_MIDCR_RXE; @@ -1731,7 +1724,7 @@ static int snd_cs4281_midi_input_open(sn static int snd_cs4281_midi_input_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return -ENXIO); + cs4281_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(BA0_MIDCR_RXE | BA0_MIDCR_RIE); @@ -1749,7 +1742,7 @@ static int snd_cs4281_midi_input_close(s static int snd_cs4281_midi_output_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return -ENXIO); + cs4281_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->uartm |= CS4281_MODE_OUTPUT; @@ -1767,7 +1760,7 @@ static int snd_cs4281_midi_output_open(s static int snd_cs4281_midi_output_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return -ENXIO); + cs4281_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(BA0_MIDCR_TXE | BA0_MIDCR_TIE); @@ -1785,7 +1778,7 @@ static int snd_cs4281_midi_output_close( static void snd_cs4281_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return); + cs4281_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); if (up) { @@ -1805,7 +1798,7 @@ static void snd_cs4281_midi_input_trigge static void snd_cs4281_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - cs4281_t *chip = snd_magic_cast(cs4281_t, substream->rmidi->private_data, return); + cs4281_t *chip = substream->rmidi->private_data; unsigned char byte; spin_lock_irqsave(&chip->reg_lock, flags); @@ -1872,7 +1865,7 @@ static int __devinit snd_cs4281_midi(cs4 static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - cs4281_t *chip = snd_magic_cast(cs4281_t, dev_id, return IRQ_NONE); + cs4281_t *chip = dev_id; unsigned int status, dma, val; cs4281_dma_t *cdma; @@ -2040,7 +2033,7 @@ static int saved_regs[SUSPEND_REGISTERS] static int cs4281_suspend(snd_card_t *card, unsigned int state) { - cs4281_t *chip = snd_magic_cast(cs4281_t, card->pm_private_data, return -EINVAL); + cs4281_t *chip = card->pm_private_data; u32 ulCLK; unsigned int i; @@ -2085,7 +2078,7 @@ static int cs4281_suspend(snd_card_t *ca static int cs4281_resume(snd_card_t *card, unsigned int state) { - cs4281_t *chip = snd_magic_cast(cs4281_t, card->pm_private_data, return -EINVAL); + cs4281_t *chip = card->pm_private_data; unsigned int i; u32 ulCLK; --- linux-2.6.8-rc1/sound/pci/cs46xx/cs46xx.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/cs46xx/cs46xx.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,8 +37,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Cirrus Logic Sound Fusion CS46XX"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Cirrus Logic,Sound Fusion (CS4280)}," +MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)}," "{Cirrus Logic,Sound Fusion (CS4610)}," "{Cirrus Logic,Sound Fusion (CS4612)}," "{Cirrus Logic,Sound Fusion (CS4615)}," @@ -56,22 +55,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for the CS46xx soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable CS46xx soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(external_amp, bool, boot_devs, 0444); MODULE_PARM_DESC(external_amp, "Force to enable external amplifer."); -MODULE_PARM_SYNTAX(external_amp, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(thinkpad, bool, boot_devs, 0444); MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); -MODULE_PARM_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(mmap_valid, bool, boot_devs, 0444); MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); -MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); static struct pci_device_id snd_cs46xx_ids[] = { { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4280 */ --- linux-2.6.8-rc1/sound/pci/cs46xx/cs46xx_lib.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/cs46xx/cs46xx_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -190,7 +190,7 @@ static unsigned short snd_cs46xx_codec_r static unsigned short snd_cs46xx_ac97_read(ac97_t * ac97, unsigned short reg) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return -ENXIO); + cs46xx_t *chip = ac97->private_data; unsigned short val; int codec_index = -1; @@ -281,7 +281,7 @@ static void snd_cs46xx_ac97_write(ac97_t unsigned short reg, unsigned short val) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); + cs46xx_t *chip = ac97->private_data; int codec_index = -1; /* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */ @@ -688,84 +688,35 @@ static void snd_cs46xx_set_capture_sampl * PCM part */ +static void snd_cs46xx_pb_trans_copy(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + cs46xx_pcm_t * cpcm = runtime->private_data; + memcpy(cpcm->hw_buf.area + rec->hw_data, runtime->dma_area + rec->sw_data, bytes); +} + static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream) { - /* cs46xx_t *chip = snd_pcm_substream_chip(substream); */ snd_pcm_runtime_t *runtime = substream->runtime; - cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); - snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; - snd_pcm_sframes_t diff = appl_ptr - cpcm->appl_ptr; - int buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift; - - if (diff) { - if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) - diff += runtime->boundary; - cpcm->sw_ready += diff * (1 << cpcm->shift); - cpcm->appl_ptr = appl_ptr; - } - while (cpcm->hw_ready < buffer_size && - cpcm->sw_ready > 0) { - size_t hw_to_end = buffer_size - cpcm->hw_data; - size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data; - size_t bytes = buffer_size - cpcm->hw_ready; - if (cpcm->sw_ready < (int)bytes) - bytes = cpcm->sw_ready; - if (hw_to_end < bytes) - bytes = hw_to_end; - if (sw_to_end < bytes) - bytes = sw_to_end; - memcpy(cpcm->hw_buf.area + cpcm->hw_data, - runtime->dma_area + cpcm->sw_data, - bytes); - cpcm->hw_data += bytes; - if ((int)cpcm->hw_data == buffer_size) - cpcm->hw_data = 0; - cpcm->sw_data += bytes; - if (cpcm->sw_data == cpcm->sw_bufsize) - cpcm->sw_data = 0; - cpcm->hw_ready += bytes; - cpcm->sw_ready -= bytes; - } + cs46xx_pcm_t * cpcm = runtime->private_data; + snd_pcm_indirect_playback_transfer(substream, &cpcm->pcm_rec, snd_cs46xx_pb_trans_copy); return 0; } -static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream) +static void snd_cs46xx_cp_trans_copy(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes) { cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; - snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr; - int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift; - - if (diff) { - if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) - diff += runtime->boundary; - chip->capt.sw_ready -= diff * (1 << chip->capt.shift); - chip->capt.appl_ptr = appl_ptr; - } - while (chip->capt.hw_ready > 0 && - chip->capt.sw_ready < (int)chip->capt.sw_bufsize) { - size_t hw_to_end = buffer_size - chip->capt.hw_data; - size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data; - size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready; - if (chip->capt.hw_ready < (int)bytes) - bytes = chip->capt.hw_ready; - if (hw_to_end < bytes) - bytes = hw_to_end; - if (sw_to_end < bytes) - bytes = sw_to_end; - memcpy(runtime->dma_area + chip->capt.sw_data, - chip->capt.hw_buf.area + chip->capt.hw_data, - bytes); - chip->capt.hw_data += bytes; - if ((int)chip->capt.hw_data == buffer_size) - chip->capt.hw_data = 0; - chip->capt.sw_data += bytes; - if (chip->capt.sw_data == chip->capt.sw_bufsize) - chip->capt.sw_data = 0; - chip->capt.hw_ready -= bytes; - chip->capt.sw_ready += bytes; - } + memcpy(runtime->dma_area + rec->sw_data, + chip->capt.hw_buf.area + rec->hw_data, bytes); +} + +static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream) +{ + cs46xx_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_indirect_capture_transfer(substream, &chip->capt.pcm_rec, snd_cs46xx_cp_trans_copy); return 0; } @@ -773,7 +724,7 @@ static snd_pcm_uframes_t snd_cs46xx_play { cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr; - cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); + cs46xx_pcm_t *cpcm = substream->runtime->private_data; snd_assert (cpcm->pcm_channel,return -ENXIO); #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -789,9 +740,7 @@ static snd_pcm_uframes_t snd_cs46xx_play { cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr; - cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); - ssize_t bytes; - int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << cpcm->shift; + cs46xx_pcm_t *cpcm = substream->runtime->private_data; #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (cpcm->pcm_channel,return -ENXIO); @@ -800,18 +749,7 @@ static snd_pcm_uframes_t snd_cs46xx_play ptr = snd_cs46xx_peek(chip, BA1_PBA); #endif ptr -= cpcm->hw_buf.addr; - - bytes = ptr - cpcm->hw_io; - - if (bytes < 0) - bytes += buffer_size; - cpcm->hw_io = ptr; - cpcm->hw_ready -= bytes; - cpcm->sw_io += bytes; - if (cpcm->sw_io >= cpcm->sw_bufsize) - cpcm->sw_io -= cpcm->sw_bufsize; - snd_cs46xx_playback_transfer(substream); - return cpcm->sw_io >> cpcm->shift; + return snd_pcm_indirect_playback_pointer(substream, &cpcm->pcm_rec, ptr); } static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream) @@ -825,18 +763,7 @@ static snd_pcm_uframes_t snd_cs46xx_capt { cs46xx_t *chip = snd_pcm_substream_chip(substream); size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr; - ssize_t bytes = ptr - chip->capt.hw_io; - int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << chip->capt.shift; - - if (bytes < 0) - bytes += buffer_size; - chip->capt.hw_io = ptr; - chip->capt.hw_ready += bytes; - chip->capt.sw_io += bytes; - if (chip->capt.sw_io >= chip->capt.sw_bufsize) - chip->capt.sw_io -= chip->capt.sw_bufsize; - snd_cs46xx_capture_transfer(substream); - return chip->capt.sw_io >> chip->capt.shift; + return snd_pcm_indirect_capture_pointer(substream, &chip->capt.pcm_rec, ptr); } static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, @@ -847,7 +774,7 @@ static int snd_cs46xx_playback_trigger(s int result = 0; #ifdef CONFIG_SND_CS46XX_NEW_DSP - cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO); + cs46xx_pcm_t *cpcm = substream->runtime->private_data; #else spin_lock(&chip->reg_lock); #endif @@ -987,7 +914,7 @@ static int snd_cs46xx_playback_hw_params int sample_rate = params_rate(hw_params); int period_size = params_period_bytes(hw_params); #endif - cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); + cpcm = runtime->private_data; #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (sample_rate != 0, return -ENXIO); @@ -1084,7 +1011,7 @@ static int snd_cs46xx_playback_hw_free(s snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; - cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); + cpcm = runtime->private_data; /* if play_back open fails, then this function is called and cpcm can actually be NULL here */ @@ -1108,7 +1035,7 @@ static int snd_cs46xx_playback_prepare(s snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t *cpcm; - cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); + cpcm = runtime->private_data; #ifdef CONFIG_SND_CS46XX_NEW_DSP snd_assert (cpcm->pcm_channel != NULL, return -ENXIO); @@ -1143,10 +1070,9 @@ static int snd_cs46xx_playback_prepare(s pfie |= 0x00004000; } - cpcm->sw_bufsize = snd_pcm_lib_buffer_bytes(substream); - cpcm->sw_data = cpcm->sw_io = cpcm->sw_ready = 0; - cpcm->hw_data = cpcm->hw_io = cpcm->hw_ready = 0; - cpcm->appl_ptr = 0; + memset(&cpcm->pcm_rec, 0, sizeof(cpcm->pcm_rec)); + cpcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + cpcm->pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift; #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -1223,10 +1149,9 @@ static int snd_cs46xx_capture_prepare(sn snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr); chip->capt.shift = 2; - chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream); - chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0; - chip->capt.hw_data = chip->capt.hw_io = chip->capt.hw_ready = 0; - chip->capt.appl_ptr = 0; + memset(&chip->capt.pcm_rec, 0, sizeof(chip->capt.pcm_rec)); + chip->capt.pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + chip->capt.pcm_rec.hw_buffer_size = runtime->period_size * CS46XX_FRAGS << 2; snd_cs46xx_set_capture_sample_rate(chip, runtime->rate); return 0; @@ -1234,7 +1159,7 @@ static int snd_cs46xx_capture_prepare(sn static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, dev_id, return IRQ_NONE); + cs46xx_t *chip = dev_id; u32 status1; #ifdef CONFIG_SND_CS46XX_NEW_DSP dsp_spos_instance_t * ins = chip->dsp_spos_instance; @@ -1265,7 +1190,7 @@ static irqreturn_t snd_cs46xx_interrupt( if (ins->pcm_channels[i].active && ins->pcm_channels[i].private_data && !ins->pcm_channels[i].unlinked) { - cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue); + cpcm = ins->pcm_channels[i].private_data; snd_pcm_period_elapsed(cpcm->substream); } } @@ -1275,7 +1200,7 @@ static irqreturn_t snd_cs46xx_interrupt( if (ins->pcm_channels[i].active && ins->pcm_channels[i].private_data && !ins->pcm_channels[i].unlinked) { - cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue); + cpcm = ins->pcm_channels[i].private_data; snd_pcm_period_elapsed(cpcm->substream); } } @@ -1382,10 +1307,8 @@ static snd_pcm_hw_constraint_list_t hw_c static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime) { - cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return); - - if (cpcm) - snd_magic_kfree(cpcm); + cs46xx_pcm_t * cpcm = runtime->private_data; + kfree(cpcm); } static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id) @@ -1394,11 +1317,11 @@ static int _cs46xx_playback_open_channel cs46xx_pcm_t * cpcm; snd_pcm_runtime_t *runtime = substream->runtime; - cpcm = snd_magic_kcalloc(cs46xx_pcm_t, 0, GFP_KERNEL); + cpcm = kcalloc(1, sizeof(*cpcm), GFP_KERNEL); if (cpcm == NULL) return -ENOMEM; if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_SIZE, &cpcm->hw_buf) < 0) { - snd_magic_kfree(cpcm); + kfree(cpcm); return -ENOMEM; } @@ -1510,7 +1433,7 @@ static int snd_cs46xx_playback_close(snd snd_pcm_runtime_t *runtime = substream->runtime; cs46xx_pcm_t * cpcm; - cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO); + cpcm = runtime->private_data; /* when playback_open fails, then cpcm can be NULL */ if (!cpcm) return -ENXIO; @@ -1664,7 +1587,7 @@ snd_pcm_ops_t snd_cs46xx_capture_indirec static void snd_cs46xx_pcm_free(snd_pcm_t *pcm) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + cs46xx_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1672,21 +1595,21 @@ static void snd_cs46xx_pcm_free(snd_pcm_ #ifdef CONFIG_SND_CS46XX_NEW_DSP static void snd_cs46xx_pcm_rear_free(snd_pcm_t *pcm) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + cs46xx_t *chip = pcm->private_data; chip->pcm_rear = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } static void snd_cs46xx_pcm_center_lfe_free(snd_pcm_t *pcm) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + cs46xx_t *chip = pcm->private_data; chip->pcm_center_lfe = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } static void snd_cs46xx_pcm_iec958_free(snd_pcm_t *pcm) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); + cs46xx_t *chip = pcm->private_data; chip->pcm_iec958 = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1824,14 +1747,14 @@ int __devinit snd_cs46xx_pcm_iec958(cs46 */ static void snd_cs46xx_mixer_free_ac97_bus(ac97_bus_t *bus) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, bus->private_data, return); + cs46xx_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); + cs46xx_t *chip = ac97->private_data; snd_assert ((ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) || (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]), @@ -2420,7 +2343,7 @@ static void snd_cs46xx_codec_reset (ac97 { unsigned long end_time; int err; - cs46xx_t * chip = snd_magic_cast(cs46xx_t,ac97->private_data,return /* -ENXIO */); + cs46xx_t * chip = ac97->private_data; /* reset to defaults */ snd_ac97_write(ac97, AC97_RESET, 0); @@ -2606,7 +2529,7 @@ static void snd_cs46xx_midi_reset(cs46xx static int snd_cs46xx_midi_input_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); + cs46xx_t *chip = substream->rmidi->private_data; chip->active_ctrl(chip, 1); spin_lock_irqsave(&chip->reg_lock, flags); @@ -2625,7 +2548,7 @@ static int snd_cs46xx_midi_input_open(sn static int snd_cs46xx_midi_input_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); + cs46xx_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE); @@ -2644,7 +2567,7 @@ static int snd_cs46xx_midi_input_close(s static int snd_cs46xx_midi_output_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); + cs46xx_t *chip = substream->rmidi->private_data; chip->active_ctrl(chip, 1); @@ -2664,7 +2587,7 @@ static int snd_cs46xx_midi_output_open(s static int snd_cs46xx_midi_output_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); + cs46xx_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE); @@ -2683,7 +2606,7 @@ static int snd_cs46xx_midi_output_close( static void snd_cs46xx_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return); + cs46xx_t *chip = substream->rmidi->private_data; spin_lock_irqsave(&chip->reg_lock, flags); if (up) { @@ -2703,7 +2626,7 @@ static void snd_cs46xx_midi_input_trigge static void snd_cs46xx_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return); + cs46xx_t *chip = substream->rmidi->private_data; unsigned char byte; spin_lock_irqsave(&chip->reg_lock, flags); @@ -2781,7 +2704,7 @@ static void snd_cs46xx_gameport_trigger( cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport; cs46xx_t *chip; snd_assert(gp, return); - chip = snd_magic_cast(cs46xx_t, gp->chip, return); + chip = gp->chip; snd_cs46xx_pokeBA0(chip, BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF); } @@ -2790,7 +2713,7 @@ static unsigned char snd_cs46xx_gameport cs46xx_gameport_t *gp = (cs46xx_gameport_t *)gameport; cs46xx_t *chip; snd_assert(gp, return 0); - chip = snd_magic_cast(cs46xx_t, gp->chip, return 0); + chip = gp->chip; return snd_cs46xx_peekBA0(chip, BA0_JSPT); //inb(gameport->io); } @@ -2801,7 +2724,7 @@ static int snd_cs46xx_gameport_cooked_re unsigned js1, js2, jst; snd_assert(gp, return 0); - chip = snd_magic_cast(cs46xx_t, gp->chip, return 0); + chip = gp->chip; js1 = snd_cs46xx_peekBA0(chip, BA0_JSC1); js2 = snd_cs46xx_peekBA0(chip, BA0_JSC2); @@ -3011,13 +2934,13 @@ static int snd_cs46xx_free(cs46xx_t *chi } #endif - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_cs46xx_dev_free(snd_device_t *device) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, device->device_data, return -ENXIO); + cs46xx_t *chip = device->device_data; return snd_cs46xx_free(chip); } @@ -3786,7 +3709,7 @@ static struct cs_card_type __devinitdata #ifdef CONFIG_PM static int snd_cs46xx_suspend(snd_card_t *card, unsigned int state) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->pm_private_data, return -EINVAL); + cs46xx_t *chip = card->pm_private_data; int amp_saved; snd_pcm_suspend_all(chip->pcm); @@ -3810,7 +3733,7 @@ static int snd_cs46xx_suspend(snd_card_t static int snd_cs46xx_resume(snd_card_t *card, unsigned int state) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->pm_private_data, return -EINVAL); + cs46xx_t *chip = card->pm_private_data; int amp_saved; pci_enable_device(chip->pci); @@ -3869,7 +3792,7 @@ int __devinit snd_cs46xx_create(snd_card if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(cs46xx_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); --- linux-2.6.8-rc1/sound/pci/cs46xx/cs46xx_lib.h 2003-06-14 12:17:58.000000000 -0700 +++ 25/sound/pci/cs46xx/cs46xx_lib.h 2004-07-13 17:09:19.000000000 -0700 @@ -22,8 +22,6 @@ #ifndef __CS46XX_LIB_H__ #define __CS46XX_LIB_H__ -#define chip_t cs46xx_t - /* * constants */ --- linux-2.6.8-rc1/sound/pci/cs46xx/dsp_spos.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/cs46xx/dsp_spos.c 2004-07-13 17:09:19.000000000 -0700 @@ -462,7 +462,7 @@ symbol_entry_t * cs46xx_dsp_lookup_symbo static void cs46xx_dsp_proc_symbol_table_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; dsp_spos_instance_t * ins = chip->dsp_spos_instance; int i; @@ -489,7 +489,7 @@ static void cs46xx_dsp_proc_symbol_table static void cs46xx_dsp_proc_modules_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; dsp_spos_instance_t * ins = chip->dsp_spos_instance; int i,j; @@ -511,7 +511,7 @@ static void cs46xx_dsp_proc_modules_read static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; dsp_spos_instance_t * ins = chip->dsp_spos_instance; int i,j,col; unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; @@ -538,7 +538,7 @@ static void cs46xx_dsp_proc_task_tree_re static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; dsp_spos_instance_t * ins = chip->dsp_spos_instance; int i; @@ -570,7 +570,7 @@ static void cs46xx_dsp_proc_scb_read (sn static void cs46xx_dsp_proc_parameter_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; /*dsp_spos_instance_t * ins = chip->dsp_spos_instance; */ unsigned int i,col = 0; unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; @@ -597,7 +597,7 @@ static void cs46xx_dsp_proc_parameter_du static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return); + cs46xx_t *chip = entry->private_data; int i,col = 0; unsigned long dst = chip->region.idx[2].remap_addr; @@ -1057,7 +1057,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx int fifo_addr,fifo_span,valid_slots; - spos_control_block_t sposcb = { + static spos_control_block_t sposcb = { /* 0 */ HFG_TREE_SCB,HFG_STACK, /* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR, /* 2 */ DSP_SPOS_DC,0, @@ -1110,18 +1110,18 @@ int cs46xx_dsp_scb_and_task_init (cs46xx { /* create the null SCB */ - generic_scb_t null_scb = { + static generic_scb_t null_scb = { { 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, NULL_SCB_ADDR, NULL_SCB_ADDR, - null_algorithm->address, 0, - 0,0,0, + 0, 0, 0, 0, 0, { 0,0, 0,0, } }; + null_scb.entry_point = null_algorithm->address; ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR); ins->the_null_scb->task_entry = null_algorithm; ins->the_null_scb->sub_list_ptr = ins->the_null_scb; @@ -1132,7 +1132,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx { /* setup foreground task tree */ - task_tree_control_block_t fg_task_tree_hdr = { + static task_tree_control_block_t fg_task_tree_hdr = { { FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10), DSP_SPOS_DC_DC, DSP_SPOS_DC_DC, @@ -1145,7 +1145,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx { BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR, - fg_task_tree_header_code->address, + 0, FG_TASK_HEADER_ADDR + TCBData, }, @@ -1158,7 +1158,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx }, { - DSP_SPOS_DC,task_tree_thread->address, + DSP_SPOS_DC,0, DSP_SPOS_DC,DSP_SPOS_DC, DSP_SPOS_DC,DSP_SPOS_DC, DSP_SPOS_DC,DSP_SPOS_DC, @@ -1200,13 +1200,15 @@ int cs46xx_dsp_scb_and_task_init (cs46xx } }; + fg_task_tree_hdr.links.entry_point = fg_task_tree_header_code->address; + fg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address; cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35); } { /* setup foreground task tree */ - task_tree_control_block_t bg_task_tree_hdr = { + static task_tree_control_block_t bg_task_tree_hdr = { { DSP_SPOS_DC_DC, DSP_SPOS_DC_DC, DSP_SPOS_DC_DC, @@ -1219,7 +1221,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx { NULL_SCB_ADDR,NULL_SCB_ADDR, /* Set up the background to do nothing */ - task_tree_header_code->address, + 0, BG_TREE_SCB_ADDR + TCBData, }, @@ -1232,7 +1234,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx }, { - DSP_SPOS_DC,task_tree_thread->address, + DSP_SPOS_DC,0, DSP_SPOS_DC,DSP_SPOS_DC, DSP_SPOS_DC,DSP_SPOS_DC, DSP_SPOS_DC,DSP_SPOS_DC, @@ -1273,6 +1275,9 @@ int cs46xx_dsp_scb_and_task_init (cs46xx 0,0 } }; + + bg_task_tree_hdr.links.entry_point = task_tree_header_code->address; + bg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address; cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35); } @@ -1312,7 +1317,7 @@ int cs46xx_dsp_scb_and_task_init (cs46xx if (!write_back_scb) goto _fail_end; { - mix2_ostream_spb_t mix2_ostream_spb = { + static mix2_ostream_spb_t mix2_ostream_spb = { 0x00020000, 0x0000ffff }; --- linux-2.6.8-rc1/sound/pci/cs46xx/dsp_spos_scb_lib.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/pci/cs46xx/dsp_spos_scb_lib.c 2004-07-13 17:09:19.000000000 -0700 @@ -69,7 +69,7 @@ static void cs46xx_dsp_proc_scb_info_rea proc_scb_info_t * scb_info = (proc_scb_info_t *)entry->private_data; dsp_scb_descriptor_t * scb = scb_info->scb_desc; dsp_spos_instance_t * ins; - cs46xx_t *chip = snd_magic_cast(cs46xx_t, scb_info->chip, return); + cs46xx_t *chip = scb_info->chip; int j,col; unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; --- linux-2.6.8-rc1/sound/pci/emu10k1/emu10k1.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/emu10k1/emu10k1.c 2004-07-13 17:09:19.000000000 -0700 @@ -31,8 +31,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("EMU10K1"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Creative Labs,SB Live!/PCI512/E-mu APS}," +MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," "{Creative Labs,SB Audigy}}"); #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) @@ -53,37 +52,25 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for the EMU10K1 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable the EMU10K1 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(extin, int, boot_devs, 0444); MODULE_PARM_DESC(extin, "Available external inputs for FX8010. Zero=default."); -MODULE_PARM_SYNTAX(extin, SNDRV_ENABLED "allows:{{0,0x0ffff}},base:16"); module_param_array(extout, int, boot_devs, 0444); MODULE_PARM_DESC(extout, "Available external outputs for FX8010. Zero=default."); -MODULE_PARM_SYNTAX(extout, SNDRV_ENABLED "allows:{{0,0x0ffff}},base:16"); module_param_array(seq_ports, int, boot_devs, 0444); MODULE_PARM_DESC(seq_ports, "Allocated sequencer ports for internal synthesizer."); -MODULE_PARM_SYNTAX(seq_ports, SNDRV_ENABLED "allows:{{0,32}}"); module_param_array(max_synth_voices, int, boot_devs, 0444); MODULE_PARM_DESC(max_synth_voices, "Maximum number of voices for WaveTable."); -MODULE_PARM_SYNTAX(max_synth_voices, SNDRV_ENABLED); module_param_array(max_buffer_size, int, boot_devs, 0444); MODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB."); -MODULE_PARM_SYNTAX(max_buffer_size, SNDRV_ENABLED); module_param_array(enable_ir, bool, boot_devs, 0444); MODULE_PARM_DESC(enable_ir, "Enable IR."); -MODULE_PARM_SYNTAX(enable_ir, SNDRV_ENABLE_DESC); static struct pci_device_id snd_emu10k1_ids[] = { { 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* EMU10K1 */ -#if 0 /* FIXME: not working! */ - { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */ -#endif { 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, /* Audigy */ { 0, } }; @@ -134,10 +121,6 @@ static int __devinit snd_card_emu10k1_pr snd_card_free(card); return err; } - if ((err = snd_emu10k1_fx8010_pcm(emu, 3, NULL)) < 0) { - snd_card_free(card); - return err; - } if ((err = snd_emu10k1_mixer(emu)) < 0) { snd_card_free(card); return err; --- linux-2.6.8-rc1/sound/pci/emu10k1/emu10k1_callback.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/emu10k1/emu10k1_callback.c 2004-07-13 17:09:19.000000000 -0700 @@ -93,7 +93,7 @@ snd_emu10k1_synth_get_voice(emu10k1_t *h unsigned long flags; int i; - emu = snd_magic_cast(snd_emux_t, hw->synth, return -EINVAL); + emu = hw->synth; spin_lock_irqsave(&emu->voice_lock, flags); lookup_voices(emu, hw, best, 1); /* no OFF voices */ @@ -128,7 +128,7 @@ release_voice(snd_emux_voice_t *vp) int dcysusv; emu10k1_t *hw; - hw = snd_magic_cast(emu10k1_t, vp->hw, return); + hw = vp->hw; dcysusv = 0x8000 | (unsigned char)vp->reg.parm.modrelease; snd_emu10k1_ptr_write(hw, DCYSUSM, vp->ch, dcysusv); dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease | DCYSUSV_CHANNELENABLE_MASK; @@ -145,7 +145,7 @@ terminate_voice(snd_emux_voice_t *vp) emu10k1_t *hw; snd_assert(vp, return); - hw = snd_magic_cast(emu10k1_t, vp->hw, return); + hw = vp->hw; snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); if (vp->block) { emu10k1_memblk_t *emem; @@ -163,7 +163,7 @@ free_voice(snd_emux_voice_t *vp) { emu10k1_t *hw; - hw = snd_magic_cast(emu10k1_t, vp->hw, return); + hw = vp->hw; if (vp->ch >= 0) { snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); @@ -185,7 +185,7 @@ update_voice(snd_emux_voice_t *vp, int u { emu10k1_t *hw; - hw = snd_magic_cast(emu10k1_t, vp->hw, return); + hw = vp->hw; if (update & SNDRV_EMUX_UPDATE_VOLUME) snd_emu10k1_ptr_write(hw, IFATN_ATTENUATION, vp->ch, vp->avol); if (update & SNDRV_EMUX_UPDATE_PITCH) @@ -282,7 +282,7 @@ get_voice(snd_emux_t *emu, snd_emux_port best_voice_t best[V_END]; int i; - hw = snd_magic_cast(emu10k1_t, emu->hw, return NULL); + hw = emu->hw; lookup_voices(emu, hw, best, 0); for (i = 0; i < V_END; i++) { @@ -317,7 +317,7 @@ start_voice(snd_emux_voice_t *vp) emu10k1_t *hw; emu10k1_memblk_t *emem; - hw = snd_magic_cast(emu10k1_t, vp->hw, return -EINVAL); + hw = vp->hw; ch = vp->ch; snd_assert(ch >= 0, return -EINVAL); chan = vp->chan; @@ -469,7 +469,7 @@ trigger_voice(snd_emux_voice_t *vp) emu10k1_t *hw; emu10k1_memblk_t *emem; - hw = snd_magic_cast(emu10k1_t, vp->hw, return); + hw = vp->hw; emem = (emu10k1_memblk_t *)vp->block; if (! emem || emem->mapped_page < 0) --- linux-2.6.8-rc1/sound/pci/emu10k1/emu10k1_main.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/emu10k1/emu10k1_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -561,13 +561,13 @@ static int snd_emu10k1_free(emu10k1_t *e } if (emu->irq >= 0) free_irq(emu->irq, (void *)emu); - snd_magic_kfree(emu); + kfree(emu); return 0; } static int snd_emu10k1_dev_free(snd_device_t *device) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, device->device_data, return -ENXIO); + emu10k1_t *emu = device->device_data; return snd_emu10k1_free(emu); } @@ -595,7 +595,7 @@ int __devinit snd_emu10k1_create(snd_car if ((err = pci_enable_device(pci)) < 0) return err; - emu = snd_magic_kcalloc(emu10k1_t, 0, GFP_KERNEL); + emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); if (emu == NULL) return -ENOMEM; /* set the DMA transfer mask */ @@ -603,7 +603,7 @@ int __devinit snd_emu10k1_create(snd_car if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); - snd_magic_kfree(emu); + kfree(emu); return -ENXIO; } emu->card = card; @@ -683,9 +683,15 @@ int __devinit snd_emu10k1_create(snd_car * (for both input and output), so we skip the AC97 detections */ snd_printdd(KERN_INFO "Audigy2 EX is detected. skpping ac97.\n"); - emu->no_ac97 = 1; + emu->no_ac97 = 1; } + if (emu->revision == 4) { + /* FIXME - Audigy 2 ZS detection */ + emu->spk71 = 1; + } + + emu->fx8010.fxbus_mask = 0x303f; if (extin_mask == 0) extin_mask = 0x3fcf; --- linux-2.6.8-rc1/sound/pci/emu10k1/emu10k1_patch.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/pci/emu10k1/emu10k1_patch.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,7 +44,7 @@ snd_emu10k1_sample_new(snd_emux_t *rec, unsigned int start_addr; emu10k1_t *emu; - emu = snd_magic_cast(emu10k1_t, rec->hw, return -ENXIO); + emu = rec->hw; snd_assert(sp != NULL, return -EINVAL); snd_assert(hdr != NULL, return -EINVAL); @@ -210,7 +210,7 @@ snd_emu10k1_sample_free(snd_emux_t *rec, { emu10k1_t *emu; - emu = snd_magic_cast(emu10k1_t, rec->hw, return -ENXIO); + emu = rec->hw; snd_assert(sp != NULL, return -EINVAL); snd_assert(hdr != NULL, return -EINVAL); --- linux-2.6.8-rc1/sound/pci/emu10k1/emu10k1_synth.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/pci/emu10k1/emu10k1_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -85,9 +85,9 @@ int snd_emu10k1_synth_delete_device(snd_ if (dev->driver_data == NULL) return 0; /* not registered actually */ - emu = snd_magic_cast(snd_emux_t, dev->driver_data, return -EINVAL); + emu = dev->driver_data; - hw = snd_magic_cast(emu10k1_t, emu->hw, return -EINVAL); + hw = emu->hw; spin_lock_irqsave(&hw->voice_lock, flags); hw->synth = NULL; hw->get_synth_voice = NULL; --- linux-2.6.8-rc1/sound/pci/emu10k1/emufx.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/emu10k1/emufx.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,8 +33,6 @@ #include #include -#define chip_t emu10k1_t - #if 0 /* for testing purposes - digital out -> capture */ #define EMU10K1_CAPTURE_DIGITAL_OUT #endif @@ -405,7 +403,7 @@ static void snd_emu10k1_fx8010_interrupt } } -static int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, +int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, snd_fx8010_irq_handler_t *handler, unsigned char gpr_running, void *private_data, @@ -438,7 +436,7 @@ static int snd_emu10k1_fx8010_register_i return 0; } -static int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, +int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, snd_emu10k1_fx8010_irq_t *irq) { snd_emu10k1_fx8010_irq_t *tmp; @@ -463,312 +461,6 @@ static int snd_emu10k1_fx8010_unregister return 0; } -/* - * PCM streams - */ - -#define INITIAL_TRAM_SHIFT 14 -#define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1) - -static void snd_emu10k1_fx8010_playback_irq(emu10k1_t *emu, void *private_data) -{ - snd_pcm_substream_t *substream = snd_magic_cast(snd_pcm_substream_t, private_data, return); - snd_pcm_period_elapsed(substream); -} - -static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, - unsigned short *dst_right, - unsigned short *src, - unsigned int count, - unsigned int tram_shift) -{ - // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); - if ((tram_shift & 1) == 0) { - while (count--) { - *dst_left-- = *src++; - *dst_right-- = *src++; - } - } else { - while (count--) { - *dst_right-- = *src++; - *dst_left-- = *src++; - } - } -} - -static void snd_emu10k1_fx8010_playback_tram_poke(emu10k1_t *emu, - unsigned int *tram_pos, - unsigned int *tram_shift, - unsigned int tram_size, - unsigned short *src, - unsigned int frames) -{ - unsigned int count; - - while (frames > *tram_pos) { - count = *tram_pos + 1; - snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos, - (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2, - src, count, *tram_shift); - src += count * 2; - frames -= count; - *tram_pos = (tram_size / 2) - 1; - (*tram_shift)++; - } - snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos, - (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2, - src, frames, *tram_shift++); - *tram_pos -= frames; -} - -static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; - snd_pcm_sframes_t diff = appl_ptr - pcm->appl_ptr; - snd_pcm_uframes_t buffer_size = pcm->buffer_size / 2; - - if (diff) { - if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) - diff += runtime->boundary; - pcm->sw_ready += diff; - pcm->appl_ptr = appl_ptr; - } - while (pcm->hw_ready < buffer_size && - pcm->sw_ready > 0) { - size_t hw_to_end = buffer_size - pcm->hw_data; - size_t sw_to_end = (runtime->buffer_size << 2) - pcm->sw_data; - size_t tframes = buffer_size - pcm->hw_ready; - if (pcm->sw_ready < tframes) - tframes = pcm->sw_ready; - if (hw_to_end < tframes) - tframes = hw_to_end; - if (sw_to_end < tframes) - tframes = sw_to_end; - snd_emu10k1_fx8010_playback_tram_poke(emu, &pcm->tram_pos, &pcm->tram_shift, - pcm->buffer_size, - (unsigned short *)(runtime->dma_area + (pcm->sw_data << 2)), - tframes); - pcm->hw_data += tframes; - if (pcm->hw_data == buffer_size) - pcm->hw_data = 0; - pcm->sw_data += tframes; - if (pcm->sw_data == runtime->buffer_size) - pcm->sw_data = 0; - pcm->hw_ready += tframes; - pcm->sw_ready -= tframes; - } - return 0; -} - -static int snd_emu10k1_fx8010_playback_hw_params(snd_pcm_substream_t * substream, - snd_pcm_hw_params_t * hw_params) -{ - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); -} - -static int snd_emu10k1_fx8010_playback_hw_free(snd_pcm_substream_t * substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - unsigned int i; - - for (i = 0; i < pcm->channels; i++) - snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0); - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int snd_emu10k1_fx8010_playback_prepare(snd_pcm_substream_t * substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - unsigned int i; - - // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); - pcm->sw_data = pcm->sw_io = pcm->sw_ready = 0; - pcm->hw_data = pcm->hw_io = pcm->hw_ready = 0; - pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); - pcm->tram_shift = 0; - pcm->appl_ptr = 0; - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size); - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size); - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size); - for (i = 0; i < pcm->channels; i++) - snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels)); - return 0; -} - -static int snd_emu10k1_fx8010_playback_trigger(snd_pcm_substream_t * substream, int cmd) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - unsigned long flags; - int result = 0; - - spin_lock_irqsave(&emu->reg_lock, flags); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* follow thru */ - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -#ifdef EMU10K1_SET_AC3_IEC958 - { - int i; - for (i = 0; i < 3; i++) { - unsigned int bits; - bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | - 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA; - snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits); - } - } -#endif - result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq); - if (result < 0) - goto __err; - snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); - pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); - pcm->tram_shift = 0; - break; - default: - result = -EINVAL; - break; - } - __err: - spin_unlock_irqrestore(&emu->reg_lock, flags); - return result; -} - -static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t * substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - size_t ptr; - snd_pcm_sframes_t frames; - - if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0)) - return 0; - ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0); - frames = ptr - pcm->hw_io; - if (frames < 0) - frames += runtime->buffer_size; - pcm->hw_io = ptr; - pcm->hw_ready -= frames; - pcm->sw_io += frames; - if (pcm->sw_io >= runtime->buffer_size) - pcm->sw_io -= runtime->buffer_size; - snd_emu10k1_fx8010_playback_transfer(substream); - return pcm->sw_io; -} - -static snd_pcm_hardware_t snd_emu10k1_fx8010_playback = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), - .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 1, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 1024, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - -static int snd_emu10k1_fx8010_playback_open(snd_pcm_substream_t * substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - - runtime->hw = snd_emu10k1_fx8010_playback; - runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels; - runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2; - spin_lock(&emu->reg_lock); - if (pcm->valid == 0) { - spin_unlock(&emu->reg_lock); - return -ENODEV; - } - pcm->opened = 1; - spin_unlock(&emu->reg_lock); - return 0; -} - -static int snd_emu10k1_fx8010_playback_close(snd_pcm_substream_t * substream) -{ - emu10k1_t *emu = snd_pcm_substream_chip(substream); - snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; - - spin_lock(&emu->reg_lock); - pcm->opened = 0; - spin_unlock(&emu->reg_lock); - return 0; -} - -static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = { - .open = snd_emu10k1_fx8010_playback_open, - .close = snd_emu10k1_fx8010_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_emu10k1_fx8010_playback_hw_params, - .hw_free = snd_emu10k1_fx8010_playback_hw_free, - .prepare = snd_emu10k1_fx8010_playback_prepare, - .trigger = snd_emu10k1_fx8010_playback_trigger, - .pointer = snd_emu10k1_fx8010_playback_pointer, - .ack = snd_emu10k1_fx8010_playback_transfer, -}; - -static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm) -{ - emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); - emu->pcm_fx8010 = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 8, 0, &pcm)) < 0) - return err; - - pcm->private_data = emu; - pcm->private_free = snd_emu10k1_fx8010_pcm_free; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); - - pcm->info_flags = 0; - strcpy(pcm->name, "EMU10K1 FX8010"); - emu->pcm_fx8010 = pcm; - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 0); - - if (rpcm) - *rpcm = pcm; - - return 0; -} - /************************************************************************* * EMU10K1 effect manager *************************************************************************/ @@ -1193,7 +885,7 @@ static int snd_emu10k1_ipcm_peek(emu10k1 #define SND_EMU10K1_GPR_CONTROLS 41 #define SND_EMU10K1_INPUTS 10 -#define SND_EMU10K1_PLAYBACK_CHANNELS 6 +#define SND_EMU10K1_PLAYBACK_CHANNELS 8 #define SND_EMU10K1_CAPTURE_CHANNELS 4 static void __devinit snd_emu10k1_init_mono_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval) @@ -1262,9 +954,9 @@ static int __devinit _snd_emu10k1_audigy spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); - if ((icode = snd_kcalloc(sizeof(emu10k1_fx8010_code_t), GFP_KERNEL)) == NULL) + if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL) return -ENOMEM; - if ((controls = snd_kcalloc(sizeof(emu10k1_fx8010_control_gpr_t) * SND_EMU10K1_GPR_CONTROLS, GFP_KERNEL)) == NULL) { + if ((controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(*controls), GFP_KERNEL)) == NULL) { kfree(icode); return -ENOMEM; } @@ -1292,6 +984,14 @@ static int __devinit _snd_emu10k1_audigy A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100); gpr += 2; + + /* PCM Side Playback (independent from stereo mix) */ + if (emu->spk71) { + A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); + gpr += 2; + } /* PCM Center Playback (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); @@ -1440,6 +1140,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); gpr++; + + if (emu->spk71) { + /* Stereo Mix Side Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0); + gpr += 2; + } /* * outputs @@ -1467,6 +1175,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ + if (emu->spk71) { + A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */ + A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */ + } + ctl = &controls[nctl + 0]; ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -1497,7 +1210,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j; } } - for (z = 0; z < 3; z++) { /* front/rear/center-lfe */ + for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */ int j, k, l, d; for (j = 0; j < 2; j++) { /* left/right */ k = 0xb0 + (z * 8) + (j * 4); @@ -1529,7 +1242,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G #undef BASS_GPR #undef TREBLE_GPR - for (z = 0; z < 6; z++) { + for (z = 0; z < 8; z++) { A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0); A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0); A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); @@ -1540,12 +1253,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G /* Master volume (will be renamed later) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS)); + snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); gpr += 2; /* analog speakers */ @@ -1553,6 +1268,8 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); + if (emu->spk71) + A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); /* headphone */ A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); @@ -1674,13 +1391,13 @@ static int __devinit _snd_emu10k1_init_e spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); - if ((icode = snd_kcalloc(sizeof(emu10k1_fx8010_code_t), GFP_KERNEL)) == NULL) + if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL) return -ENOMEM; - if ((controls = snd_kcalloc(sizeof(emu10k1_fx8010_control_gpr_t) * SND_EMU10K1_GPR_CONTROLS, GFP_KERNEL)) == NULL) { + if ((controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(emu10k1_fx8010_control_gpr_t), GFP_KERNEL)) == NULL) { kfree(icode); return -ENOMEM; } - if ((ipcm = snd_kcalloc(sizeof(emu10k1_fx8010_pcm_t), GFP_KERNEL)) == NULL) { + if ((ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL)) == NULL) { kfree(controls); kfree(icode); return -ENOMEM; @@ -2297,7 +2014,7 @@ static int snd_emu10k1_fx8010_info(emu10 static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, hw->private_data, return -ENXIO); + emu10k1_t *emu = hw->private_data; emu10k1_fx8010_info_t *info; emu10k1_fx8010_code_t *icode; emu10k1_fx8010_pcm_t *ipcm; @@ -2364,7 +2081,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_ case SNDRV_EMU10K1_IOCTL_PCM_PEEK: if (emu->audigy) return -EINVAL; - ipcm = (emu10k1_fx8010_pcm_t *)snd_kcalloc(sizeof(*ipcm), GFP_KERNEL); + ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL); if (ipcm == NULL) return -ENOMEM; if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { --- linux-2.6.8-rc1/sound/pci/emu10k1/emumixer.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/emu10k1/emumixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -32,8 +32,6 @@ #include #include -#define chip_t emu10k1_t - #define AC97_ID_STAC9758 0x83847658 static int snd_emu10k1_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) @@ -421,7 +419,7 @@ static snd_kcontrol_new_t snd_audigy_sha */ static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, ac97->private_data, return); + emu10k1_t *emu = ac97->private_data; emu->ac97 = NULL; } --- linux-2.6.8-rc1/sound/pci/emu10k1/emupcm.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/emu10k1/emupcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -34,8 +34,6 @@ #include #include -#define chip_t emu10k1_t - static void snd_emu10k1_pcm_interrupt(emu10k1_t *emu, emu10k1_voice_t *voice) { emu10k1_pcm_t *epcm; @@ -354,7 +352,7 @@ static int snd_emu10k1_playback_hw_param { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; int err; if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) @@ -383,7 +381,7 @@ static int snd_emu10k1_playback_hw_free( if (runtime->private_data == NULL) return 0; - epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + epcm = runtime->private_data; if (epcm->extra) { snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; @@ -409,7 +407,7 @@ static int snd_emu10k1_playback_prepare( { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; unsigned int start_addr, end_addr; start_addr = epcm->start_addr; @@ -443,7 +441,7 @@ static int snd_emu10k1_capture_prepare(s { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; int idx; snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0); @@ -452,7 +450,11 @@ static int snd_emu10k1_capture_prepare(s snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); break; case CAPTURE_EFX: - snd_emu10k1_ptr_write(emu, FXWC, 0, 0); + if (emu->audigy) { + snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); + snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); + } else + snd_emu10k1_ptr_write(emu, FXWC, 0, 0); break; default: break; @@ -565,7 +567,7 @@ static int snd_emu10k1_playback_trigger( { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; unsigned long flags; int result = 0; @@ -602,7 +604,7 @@ static int snd_emu10k1_capture_trigger(s { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; unsigned long flags; int result = 0; @@ -618,7 +620,11 @@ static int snd_emu10k1_capture_trigger(s snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); break; case CAPTURE_EFX: - snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); + if (emu->audigy) { + snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); + snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); + } else + snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); break; default: break; @@ -637,7 +643,11 @@ static int snd_emu10k1_capture_trigger(s snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); break; case CAPTURE_EFX: - snd_emu10k1_ptr_write(emu, FXWC, 0, 0); + if (emu->audigy) { + snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); + snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); + } else + snd_emu10k1_ptr_write(emu, FXWC, 0, 0); break; default: break; @@ -654,7 +664,7 @@ static snd_pcm_uframes_t snd_emu10k1_pla { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; unsigned int ptr; if (!epcm->running) @@ -681,7 +691,7 @@ static snd_pcm_uframes_t snd_emu10k1_cap { emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return -ENXIO); + emu10k1_pcm_t *epcm = runtime->private_data; unsigned int ptr; if (!epcm->running) @@ -767,10 +777,10 @@ static void snd_emu10k1_pcm_mixer_notify static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) { - emu10k1_pcm_t *epcm = snd_magic_cast(emu10k1_pcm_t, runtime->private_data, return); + emu10k1_pcm_t *epcm = runtime->private_data; if (epcm) - snd_magic_kfree(epcm); + kfree(epcm); } static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream) @@ -781,7 +791,7 @@ static int snd_emu10k1_playback_open(snd snd_pcm_runtime_t *runtime = substream->runtime; int i, err; - epcm = snd_magic_kcalloc(emu10k1_pcm_t, 0, GFP_KERNEL); + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -791,11 +801,11 @@ static int snd_emu10k1_playback_open(snd runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_playback; if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { - snd_magic_kfree(epcm); + kfree(epcm); return err; } if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) { - snd_magic_kfree(epcm); + kfree(epcm); return err; } mix = &emu->pcm_mixer[substream->number]; @@ -826,7 +836,7 @@ static int snd_emu10k1_capture_open(snd_ snd_pcm_runtime_t *runtime = substream->runtime; emu10k1_pcm_t *epcm; - epcm = snd_magic_kcalloc(emu10k1_pcm_t, 0, GFP_KERNEL); + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -862,7 +872,7 @@ static int snd_emu10k1_capture_mic_open( emu10k1_pcm_t *epcm; snd_pcm_runtime_t *runtime = substream->runtime; - epcm = snd_magic_kcalloc(emu10k1_pcm_t, 0, GFP_KERNEL); + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -903,7 +913,7 @@ static int snd_emu10k1_capture_efx_open( int nefx = emu->audigy ? 64 : 32; int idx; - epcm = snd_magic_kcalloc(emu10k1_pcm_t, 0, GFP_KERNEL); + epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -970,7 +980,7 @@ static snd_pcm_ops_t snd_emu10k1_capture static void snd_emu10k1_pcm_free(snd_pcm_t *pcm) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); + emu10k1_t *emu = pcm->private_data; emu->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1024,7 +1034,7 @@ static snd_pcm_ops_t snd_emu10k1_capture static void snd_emu10k1_pcm_mic_free(snd_pcm_t *pcm) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); + emu10k1_t *emu = pcm->private_data; emu->pcm_mic = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1125,9 +1135,239 @@ static snd_pcm_ops_t snd_emu10k1_capture .pointer = snd_emu10k1_capture_pointer, }; + +/* EFX playback */ + +#define INITIAL_TRAM_SHIFT 14 +#define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1) + +static void snd_emu10k1_fx8010_playback_irq(emu10k1_t *emu, void *private_data) +{ + snd_pcm_substream_t *substream = private_data; + snd_pcm_period_elapsed(substream); +} + +static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, + unsigned short *dst_right, + unsigned short *src, + unsigned int count, + unsigned int tram_shift) +{ + // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); + if ((tram_shift & 1) == 0) { + while (count--) { + *dst_left-- = *src++; + *dst_right-- = *src++; + } + } else { + while (count--) { + *dst_right-- = *src++; + *dst_left-- = *src++; + } + } +} + +static void fx8010_pb_trans_copy(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + unsigned int tram_size = pcm->buffer_size; + unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data); + unsigned int frames = bytes >> 2, count; + unsigned int tram_pos = pcm->tram_pos; + unsigned int tram_shift = pcm->tram_shift; + + while (frames > tram_pos) { + count = tram_pos + 1; + snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, + (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, + src, count, tram_shift); + src += count * 2; + frames -= count; + tram_pos = (tram_size / 2) - 1; + tram_shift++; + } + snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, + (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, + src, frames, tram_shift++); + tram_pos -= frames; + pcm->tram_pos = tram_pos; + pcm->tram_shift = tram_shift; +} + +static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + + snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, fx8010_pb_trans_copy); + return 0; +} + +static int snd_emu10k1_fx8010_playback_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); +} + +static int snd_emu10k1_fx8010_playback_hw_free(snd_pcm_substream_t * substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + unsigned int i; + + for (i = 0; i < pcm->channels; i++) + snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0); + snd_pcm_lib_free_pages(substream); + return 0; +} + +static int snd_emu10k1_fx8010_playback_prepare(snd_pcm_substream_t * substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + unsigned int i; + + // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); + memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); + pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ + pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); + pcm->tram_shift = 0; + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */ + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */ + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size); + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */ + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size); + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size); + for (i = 0; i < pcm->channels; i++) + snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels)); + return 0; +} + +static int snd_emu10k1_fx8010_playback_trigger(snd_pcm_substream_t * substream, int cmd) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + unsigned long flags; + int result = 0; + + spin_lock_irqsave(&emu->reg_lock, flags); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* follow thru */ + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +#ifdef EMU10K1_SET_AC3_IEC958 + { + int i; + for (i = 0; i < 3; i++) { + unsigned int bits; + bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | + 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA; + snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits); + } + } +#endif + result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq); + if (result < 0) + goto __err; + snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */ + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; + snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); + pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); + pcm->tram_shift = 0; + break; + default: + result = -EINVAL; + break; + } + __err: + spin_unlock_irqrestore(&emu->reg_lock, flags); + return result; +} + +static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t * substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + size_t ptr; /* byte pointer */ + + if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0)) + return 0; + ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2; + return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr); +} + +static snd_pcm_hardware_t snd_emu10k1_fx8010_playback = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 1024, + .period_bytes_max = (128*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static int snd_emu10k1_fx8010_playback_open(snd_pcm_substream_t * substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + + runtime->hw = snd_emu10k1_fx8010_playback; + runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels; + runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2; + spin_lock(&emu->reg_lock); + if (pcm->valid == 0) { + spin_unlock(&emu->reg_lock); + return -ENODEV; + } + pcm->opened = 1; + spin_unlock(&emu->reg_lock); + return 0; +} + +static int snd_emu10k1_fx8010_playback_close(snd_pcm_substream_t * substream) +{ + emu10k1_t *emu = snd_pcm_substream_chip(substream); + snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; + + spin_lock(&emu->reg_lock); + pcm->opened = 0; + spin_unlock(&emu->reg_lock); + return 0; +} + +static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = { + .open = snd_emu10k1_fx8010_playback_open, + .close = snd_emu10k1_fx8010_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_emu10k1_fx8010_playback_hw_params, + .hw_free = snd_emu10k1_fx8010_playback_hw_free, + .prepare = snd_emu10k1_fx8010_playback_prepare, + .trigger = snd_emu10k1_fx8010_playback_trigger, + .pointer = snd_emu10k1_fx8010_playback_pointer, + .ack = snd_emu10k1_fx8010_playback_transfer, +}; + static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); + emu10k1_t *emu = pcm->private_data; emu->pcm_efx = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1140,12 +1380,13 @@ int __devinit snd_emu10k1_pcm_efx(emu10k if (rpcm) *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 0, 1, &pcm)) < 0) + if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) return err; pcm->private_data = emu; pcm->private_free = snd_emu10k1_pcm_efx_free; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops); pcm->info_flags = 0; --- linux-2.6.8-rc1/sound/pci/emu10k1/emuproc.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/emu10k1/emuproc.c 2004-07-13 17:09:19.000000000 -0700 @@ -71,31 +71,32 @@ static void snd_emu10k1_proc_spdif_statu static void snd_emu10k1_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - static char *outputs[32] = { - /* 00 */ "PCM Left", - /* 01 */ "PCM Right", - /* 02 */ "PCM Surround Left", - /* 03 */ "PCM Surround Right", - /* 04 */ "MIDI Left", - /* 05 */ "MIDI Right", - /* 06 */ "PCM Center", - /* 07 */ "PCM LFE", - /* 08 */ "???", - /* 09 */ "???", - /* 10 */ "???", - /* 11 */ "???", - /* 12 */ "MIDI Reverb", - /* 13 */ "MIDI Chorus", - /* 14 */ "???", + /* FIXME - output names are in emufx.c too */ + static char *creative_outs[32] = { + /* 00 */ "AC97 Left", + /* 01 */ "AC97 Right", + /* 02 */ "Optical IEC958 Left", + /* 03 */ "Optical IEC958 Right", + /* 04 */ "Center", + /* 05 */ "LFE", + /* 06 */ "Headphone Left", + /* 07 */ "Headphone Right", + /* 08 */ "Surround Left", + /* 09 */ "Surround Right", + /* 10 */ "PCM Capture Left", + /* 11 */ "PCM Capture Right", + /* 12 */ "MIC Capture", + /* 13 */ "AC97 Surround Left", + /* 14 */ "AC97 Surround Right", /* 15 */ "???", /* 16 */ "???", - /* 17 */ "???", - /* 18 */ "ADC Left / CDROM S/PDIF Left", - /* 19 */ "ADC Right / CDROM S/PDIF Right", - /* 20 */ "MIC / Zoom Video Left", - /* 21 */ "Zoom Video Right", - /* 22 */ "S/PDIF Left", - /* 23 */ "S/PDIF Right", + /* 17 */ "Analog Center", + /* 18 */ "Analog LFE", + /* 19 */ "???", + /* 20 */ "???", + /* 21 */ "???", + /* 22 */ "???", + /* 23 */ "???", /* 24 */ "???", /* 25 */ "???", /* 26 */ "???", @@ -105,9 +106,78 @@ static void snd_emu10k1_proc_read(snd_in /* 30 */ "???", /* 31 */ "???" }; - emu10k1_t *emu = snd_magic_cast(emu10k1_t, entry->private_data, return); + + static char *audigy_outs[64] = { + /* 00 */ "Digital Front Left", + /* 01 */ "Digital Front Right", + /* 02 */ "Digital Center", + /* 03 */ "Digital LEF", + /* 04 */ "Headphone Left", + /* 05 */ "Headphone Right", + /* 06 */ "Digital Rear Left", + /* 07 */ "Digital Rear Right", + /* 08 */ "Front Left", + /* 09 */ "Front Right", + /* 10 */ "Center", + /* 11 */ "LFE", + /* 12 */ "???", + /* 13 */ "???", + /* 14 */ "Rear Left", + /* 15 */ "Rear Right", + /* 16 */ "AC97 Front Left", + /* 17 */ "AC97 Front Right", + /* 18 */ "ADC Caputre Left", + /* 19 */ "ADC Capture Right", + /* 20 */ "???", + /* 21 */ "???", + /* 22 */ "???", + /* 23 */ "???", + /* 24 */ "???", + /* 25 */ "???", + /* 26 */ "???", + /* 27 */ "???", + /* 28 */ "???", + /* 29 */ "???", + /* 30 */ "???", + /* 31 */ "???", + /* 32 */ "???", + /* 33 */ "???", + /* 34 */ "???", + /* 35 */ "???", + /* 36 */ "???", + /* 37 */ "???", + /* 38 */ "???", + /* 39 */ "???", + /* 40 */ "???", + /* 41 */ "???", + /* 42 */ "???", + /* 43 */ "???", + /* 44 */ "???", + /* 45 */ "???", + /* 46 */ "???", + /* 47 */ "???", + /* 48 */ "???", + /* 49 */ "???", + /* 50 */ "???", + /* 51 */ "???", + /* 52 */ "???", + /* 53 */ "???", + /* 54 */ "???", + /* 55 */ "???", + /* 56 */ "???", + /* 57 */ "???", + /* 58 */ "???", + /* 59 */ "???", + /* 60 */ "???", + /* 61 */ "???", + /* 62 */ "???", + /* 33 */ "???" + }; + + emu10k1_t *emu = entry->private_data; unsigned int val; int nefx = emu->audigy ? 64 : 32; + char **outputs = emu->audigy ? audigy_outs : creative_outs; int idx; snd_iprintf(buffer, "EMU10K1\n\n"); @@ -135,7 +205,7 @@ static void snd_emu10k1_proc_read(snd_in snd_iprintf(buffer, "\nCaptured FX Outputs :\n"); for (idx = 0; idx < nefx; idx++) { if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) - snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx%32]); + snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); } snd_iprintf(buffer, "\nAll FX Outputs :\n"); for (idx = 0; idx < 32; idx++) @@ -155,7 +225,7 @@ static void snd_emu10k1_proc_acode_read( snd_info_buffer_t * buffer) { u32 pc; - emu10k1_t *emu = snd_magic_cast(emu10k1_t, entry->private_data, return); + emu10k1_t *emu = entry->private_data; snd_iprintf(buffer, "FX8010 Instruction List '%s'\n", emu->fx8010.name); snd_iprintf(buffer, " Code dump :\n"); @@ -194,7 +264,7 @@ static long snd_emu10k1_fx8010_read(snd_ struct file *file, char __user *buf, long count) { long size; - emu10k1_t *emu = snd_magic_cast(emu10k1_t, entry->private_data, return -ENXIO); + emu10k1_t *emu = entry->private_data; unsigned int offset; if (!strcmp(entry->name, "fx8010_tram_addr")) { --- linux-2.6.8-rc1/sound/pci/emu10k1/io.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/sound/pci/emu10k1/io.c 2004-07-13 17:09:19.000000000 -0700 @@ -231,7 +231,7 @@ void snd_emu10k1_wait(emu10k1_t *emu, un unsigned short snd_emu10k1_ac97_read(ac97_t *ac97, unsigned short reg) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, ac97->private_data, return -ENXIO); + emu10k1_t *emu = ac97->private_data; unsigned long flags; unsigned short val; @@ -244,7 +244,7 @@ unsigned short snd_emu10k1_ac97_read(ac9 void snd_emu10k1_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short data) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, ac97->private_data, return); + emu10k1_t *emu = ac97->private_data; unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); --- linux-2.6.8-rc1/sound/pci/emu10k1/irq.c 2003-08-08 22:55:15.000000000 -0700 +++ 25/sound/pci/emu10k1/irq.c 2004-07-13 17:09:19.000000000 -0700 @@ -32,7 +32,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - emu10k1_t *emu = snd_magic_cast(emu10k1_t, dev_id, return IRQ_NONE); + emu10k1_t *emu = dev_id; unsigned int status, orig_status; int handled = 0; --- linux-2.6.8-rc1/sound/pci/emu10k1/memory.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/emu10k1/memory.c 2004-07-13 17:09:19.000000000 -0700 @@ -291,7 +291,7 @@ snd_util_memblk_t * snd_emu10k1_alloc_pages(emu10k1_t *emu, snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - struct snd_sg_buf *sgbuf = runtime->dma_private; + struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); snd_util_memhdr_t *hdr; emu10k1_memblk_t *blk; int page, err, idx; --- linux-2.6.8-rc1/sound/pci/ens1370.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ens1370.c 2004-07-13 17:09:19.000000000 -0700 @@ -40,8 +40,6 @@ #include #include -#define chip_t ensoniq_t - #ifndef CHIP1371 #undef CHIP1370 #define CHIP1370 @@ -56,15 +54,14 @@ MODULE_AUTHOR("Jaroslav Kysela , Thomas Sailer "); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); #ifdef CHIP1370 MODULE_DESCRIPTION("Ensoniq AudioPCI ES1370"); -MODULE_DEVICES("{{Ensoniq,AudioPCI-97 ES1370}," +MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI-97 ES1370}," "{Creative Labs,SB PCI64/128 (ES1370)}}"); #endif #ifdef CHIP1371 MODULE_DESCRIPTION("Ensoniq/Creative AudioPCI ES1371+"); -MODULE_DEVICES("{{Ensoniq,AudioPCI ES1371/73}," +MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI ES1371/73}," "{Ensoniq,AudioPCI ES1373}," "{Creative Labs,Ectiva EV1938}," "{Creative Labs,SB PCI64/128 (ES1371/73)}," @@ -90,22 +87,17 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Ensoniq AudioPCI soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Ensoniq AudioPCI soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Ensoniq AudioPCI soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #ifdef SUPPORT_JOYSTICK #ifdef CHIP1371 module_param_array(joystick_port, int, boot_devs, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address."); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x208},{0x210},{0x218}},dialog:list"); #else module_param_array(joystick, bool, boot_devs, 0444); MODULE_PARM_DESC(joystick, "Enable joystick."); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); #endif #endif /* SUPPORT_JOYSTICK */ @@ -581,7 +573,7 @@ static void snd_es1371_src_write(ensoniq static void snd_es1370_codec_write(ak4531_t *ak4531, unsigned short reg, unsigned short val) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ak4531->private_data, return); + ensoniq_t *ensoniq = ak4531->private_data; unsigned long flags; unsigned long end_time = jiffies + HZ / 10; @@ -611,7 +603,7 @@ static void snd_es1370_codec_write(ak453 static void snd_es1371_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ac97->private_data, return); + ensoniq_t *ensoniq = ac97->private_data; unsigned long flags; unsigned int t, x; @@ -649,7 +641,7 @@ static void snd_es1371_codec_write(ac97_ static unsigned short snd_es1371_codec_read(ac97_t *ac97, unsigned short reg) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ac97->private_data, return -ENXIO); + ensoniq_t *ensoniq = ac97->private_data; unsigned long flags; unsigned int t, x, fail = 0; @@ -1214,7 +1206,7 @@ static snd_pcm_ops_t snd_ensoniq_capture static void snd_ensoniq_pcm_free(snd_pcm_t *pcm) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, pcm->private_data, return); + ensoniq_t *ensoniq = pcm->private_data; ensoniq->pcm1 = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1261,7 +1253,7 @@ static int __devinit snd_ensoniq_pcm(ens static void snd_ensoniq_pcm_free2(snd_pcm_t *pcm) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, pcm->private_data, return); + ensoniq_t *ensoniq = pcm->private_data; ensoniq->pcm2 = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1565,7 +1557,7 @@ static snd_kcontrol_new_t snd_ens1373_li static void snd_ensoniq_mixer_free_ac97(ac97_t *ac97) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ac97->private_data, return); + ensoniq_t *ensoniq = ac97->private_data; ensoniq->u.es1371.ac97 = NULL; } @@ -1703,7 +1695,7 @@ ENSONIQ_CONTROL("Mic +5V bias", ES_1370_ static void snd_ensoniq_mixer_free_ak4531(ak4531_t *ak4531) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ak4531->private_data, return); + ensoniq_t *ensoniq = ak4531->private_data; ensoniq->u.es1370.ak4531 = NULL; } @@ -1785,7 +1777,7 @@ static void snd_ensoniq_joystick_free(en static void snd_ensoniq_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, entry->private_data, return); + ensoniq_t *ensoniq = entry->private_data; #ifdef CHIP1370 snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n"); @@ -1841,13 +1833,13 @@ static int snd_ensoniq_free(ensoniq_t *e } if (ensoniq->irq >= 0) free_irq(ensoniq->irq, (void *)ensoniq); - snd_magic_kfree(ensoniq); + kfree(ensoniq); return 0; } static int snd_ensoniq_dev_free(snd_device_t *device) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, device->device_data, return -ENXIO); + ensoniq_t *ensoniq = device->device_data; return snd_ensoniq_free(ensoniq); } @@ -1894,7 +1886,7 @@ static int __devinit snd_ensoniq_create( *rensoniq = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - ensoniq = snd_magic_kcalloc(ensoniq_t, 0, GFP_KERNEL); + ensoniq = kcalloc(1, sizeof(*ensoniq), GFP_KERNEL); if (ensoniq == NULL) return -ENOMEM; spin_lock_init(&ensoniq->reg_lock); @@ -2075,7 +2067,7 @@ static void snd_ensoniq_midi_interrupt(e static int snd_ensoniq_midi_input_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return -ENXIO); + ensoniq_t *ensoniq = substream->rmidi->private_data; spin_lock_irqsave(&ensoniq->reg_lock, flags); ensoniq->uartm |= ES_MODE_INPUT; @@ -2092,7 +2084,7 @@ static int snd_ensoniq_midi_input_open(s static int snd_ensoniq_midi_input_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return -ENXIO); + ensoniq_t *ensoniq = substream->rmidi->private_data; spin_lock_irqsave(&ensoniq->reg_lock, flags); if (!(ensoniq->uartm & ES_MODE_OUTPUT)) { @@ -2110,7 +2102,7 @@ static int snd_ensoniq_midi_input_close( static int snd_ensoniq_midi_output_open(snd_rawmidi_substream_t * substream) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return -ENXIO); + ensoniq_t *ensoniq = substream->rmidi->private_data; spin_lock_irqsave(&ensoniq->reg_lock, flags); ensoniq->uartm |= ES_MODE_OUTPUT; @@ -2127,7 +2119,7 @@ static int snd_ensoniq_midi_output_open( static int snd_ensoniq_midi_output_close(snd_rawmidi_substream_t * substream) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return -ENXIO); + ensoniq_t *ensoniq = substream->rmidi->private_data; spin_lock_irqsave(&ensoniq->reg_lock, flags); if (!(ensoniq->uartm & ES_MODE_INPUT)) { @@ -2145,7 +2137,7 @@ static int snd_ensoniq_midi_output_close static void snd_ensoniq_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return); + ensoniq_t *ensoniq = substream->rmidi->private_data; int idx; spin_lock_irqsave(&ensoniq->reg_lock, flags); @@ -2169,7 +2161,7 @@ static void snd_ensoniq_midi_input_trigg static void snd_ensoniq_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, substream->rmidi->private_data, return); + ensoniq_t *ensoniq = substream->rmidi->private_data; unsigned char byte; spin_lock_irqsave(&ensoniq->reg_lock, flags); @@ -2240,7 +2232,7 @@ static int __devinit snd_ensoniq_midi(en static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, dev_id, return IRQ_NONE); + ensoniq_t *ensoniq = dev_id; unsigned int status, sctrl; if (ensoniq == NULL) --- linux-2.6.8-rc1/sound/pci/es1938.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/es1938.c 2004-07-13 17:09:19.000000000 -0700 @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -63,13 +64,10 @@ #include -#define chip_t es1938_t - MODULE_AUTHOR("Jaromir Koutek "); MODULE_DESCRIPTION("ESS Solo-1"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ESS,ES1938}," +MODULE_SUPPORTED_DEVICE("{{ESS,ES1938}," "{ESS,ES1946}," "{ESS,ES1969}," "{TerraTec,128i PCI}}"); @@ -88,13 +86,10 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ESS Solo-1 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ESS Solo-1 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ESS Solo-1 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); #define SLIO_REG(chip, x) ((chip)->io_port + ESSIO_REG_##x) @@ -573,7 +568,12 @@ static int snd_es1938_playback1_trigger( case SNDRV_PCM_TRIGGER_START: /* According to the documentation this should be: 0x13 but that value may randomly swap stereo channels */ + snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92); + udelay(10); snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x93); + /* This two stage init gives the FIFO -> DAC connection time to + * settle before first data from DMA flows in. This should ensure + * no swapping of stereo channels. Report a bug if otherwise :-) */ outb(0x0a, SLIO_REG(chip, AUDIO2MODE)); chip->active |= DAC2; break; @@ -690,6 +690,8 @@ static int snd_es1938_playback1_prepare( chip->dma2_shift = 2 - mono - is8; + snd_es1938_reset_fifo(chip); + /* set clock and counters */ snd_es1938_rate_set(chip, substream, DAC2); @@ -874,9 +876,9 @@ static snd_pcm_hardware_t snd_es1938_cap .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = 65536, + .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, - .period_bytes_max = 65536, + .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256, @@ -896,9 +898,9 @@ static snd_pcm_hardware_t snd_es1938_pla .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = 65536, + .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, - .period_bytes_max = 65536, + .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256, @@ -1129,7 +1131,7 @@ static int snd_es1938_get_hw_switch(snd_ static void snd_es1938_hwv_free(snd_kcontrol_t *kcontrol) { - es1938_t *chip = snd_magic_cast(es1938_t, _snd_kcontrol_chip(kcontrol), return); + es1938_t *chip = snd_kcontrol_chip(kcontrol); chip->master_volume = NULL; chip->master_switch = NULL; chip->hw_volume = NULL; @@ -1370,13 +1372,13 @@ static int snd_es1938_free(es1938_t *chi } if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_es1938_dev_free(snd_device_t *device) { - es1938_t *chip = snd_magic_cast(es1938_t, device->device_data, return -ENXIO); + es1938_t *chip = device->device_data; return snd_es1938_free(chip); } @@ -1402,7 +1404,7 @@ static int __devinit snd_es1938_create(s return -ENXIO; } - chip = snd_magic_kcalloc(es1938_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -1492,7 +1494,7 @@ static int __devinit snd_es1938_create(s * -------------------------------------------------------------------- */ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - es1938_t *chip = snd_magic_cast(es1938_t, dev_id, return IRQ_NONE); + es1938_t *chip = dev_id; unsigned char status, audiostatus; int handled = 0; --- linux-2.6.8-rc1/sound/pci/es1968.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/es1968.c 2004-07-13 17:09:19.000000000 -0700 @@ -109,15 +109,12 @@ #include #include -#define chip_t es1968_t - #define CARD_NAME "ESS Maestro1/2" #define DRIVER_NAME "ES1968" MODULE_DESCRIPTION("ESS Maestro"); -MODULE_CLASSES("{sound}"); MODULE_LICENSE("GPL"); -MODULE_DEVICES("{{ESS,Maestro 2e}," +MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e}," "{ESS,Maestro 2}," "{ESS,Maestro 1}," "{TerraTec,DMX}}"); @@ -142,35 +139,25 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(total_bufsize, int, boot_devs, 0444); MODULE_PARM_DESC(total_bufsize, "Total buffer size in kB."); -MODULE_PARM_SYNTAX(total_bufsize, SNDRV_ENABLED ",allows:{{1,4096}},skill:advanced"); module_param_array(pcm_substreams_p, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_substreams_p, "PCM Playback substreams for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(pcm_substreams_p, SNDRV_ENABLED ",allows:{{1,8}}"); module_param_array(pcm_substreams_c, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_substreams_c, "PCM Capture substreams for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(pcm_substreams_c, SNDRV_ENABLED ",allows:{{0,8}}"); module_param_array(clock, int, boot_devs, 0444); MODULE_PARM_DESC(clock, "Clock on " CARD_NAME " soundcard. (0 = auto-detect)"); -MODULE_PARM_SYNTAX(clock, SNDRV_ENABLED); module_param_array(use_pm, int, boot_devs, 0444); MODULE_PARM_DESC(use_pm, "Toggle power-management. (0 = off, 1 = on, 2 = auto)"); -MODULE_PARM_SYNTAX(use_pm, SNDRV_ENABLED ",allows:{{0,1,2}},default:2,skill:advanced"); module_param_array(enable_mpu, int, boot_devs, 0444); MODULE_PARM_DESC(enable_mpu, "Enable MPU401. (0 = off, 1 = on, 2 = auto)"); -MODULE_PARM_SYNTAX(enable_mpu, SNDRV_ENABLED ",allows:{{0,2}},default:2"); #ifdef SUPPORT_JOYSTICK module_param_array(joystick, bool, boot_devs, 0444); MODULE_PARM_DESC(joystick, "Enable joystick."); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); #endif @@ -522,9 +509,7 @@ enum { /* DMA Hack! */ struct snd_esm_memory { - char *buf; - unsigned long addr; - int size; + struct snd_dma_buffer buf; int empty; /* status */ struct list_head list; }; @@ -696,7 +681,7 @@ static int snd_es1968_ac97_wait(es1968_t static void snd_es1968_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - es1968_t *chip = snd_magic_cast(es1968_t, ac97->private_data, return); + es1968_t *chip = ac97->private_data; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -715,7 +700,7 @@ static void snd_es1968_ac97_write(ac97_t static unsigned short snd_es1968_ac97_read(ac97_t *ac97, unsigned short reg) { u16 data = 0; - es1968_t *chip = snd_magic_cast(es1968_t, ac97->private_data, return 0); + es1968_t *chip = ac97->private_data; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -1078,10 +1063,10 @@ static void snd_es1968_playback_setup(es for (channel = 0; channel <= high_apu; channel++) { apu = es->apu[channel]; - snd_es1968_program_wavecache(chip, es, channel, es->memory->addr, 0); + snd_es1968_program_wavecache(chip, es, channel, es->memory->buf.addr, 0); /* Offset to PCMBAR */ - pa = es->memory->addr; + pa = es->memory->buf.addr; pa -= chip->dma.addr; pa >>= 1; /* words */ @@ -1230,20 +1215,20 @@ static void snd_es1968_capture_setup(es1 /* input mixer (left/mono) */ /* parallel in crap, see maestro reg 0xC [8-11] */ init_capture_apu(chip, es, 2, - es->mixbuf->addr, ESM_MIXBUF_SIZE/4, /* in words */ + es->mixbuf->buf.addr, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x14); /* SRC (left/mono); get input from inputing apu */ - init_capture_apu(chip, es, 0, es->memory->addr, size, + init_capture_apu(chip, es, 0, es->memory->buf.addr, size, ESM_APU_SRCONVERTOR, es->apu[2]); if (es->fmt & ESS_FMT_STEREO) { /* input mixer (right) */ init_capture_apu(chip, es, 3, - es->mixbuf->addr + ESM_MIXBUF_SIZE/2, + es->mixbuf->buf.addr + ESM_MIXBUF_SIZE/2, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x15); /* SRC (right) */ init_capture_apu(chip, es, 1, - es->memory->addr + size*2, size, + es->memory->buf.addr + size*2, size, ESM_APU_SRCONVERTOR, es->apu[3]); } @@ -1281,7 +1266,7 @@ static int snd_es1968_pcm_prepare(snd_pc { es1968_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - esschan_t *es = snd_magic_cast(esschan_t, runtime->private_data, return -ENXIO); + esschan_t *es = runtime->private_data; es->dma_size = snd_pcm_lib_buffer_bytes(substream); es->frag_size = snd_pcm_lib_period_bytes(substream); @@ -1312,7 +1297,7 @@ static int snd_es1968_pcm_prepare(snd_pc static int snd_es1968_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { es1968_t *chip = snd_pcm_substream_chip(substream); - esschan_t *es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); + esschan_t *es = substream->runtime->private_data; unsigned long flags; spin_lock_irqsave(&chip->substream_lock, flags); @@ -1343,7 +1328,7 @@ static int snd_es1968_pcm_trigger(snd_pc static snd_pcm_uframes_t snd_es1968_pcm_pointer(snd_pcm_substream_t *substream) { es1968_t *chip = snd_pcm_substream_chip(substream); - esschan_t *es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); + esschan_t *es = substream->runtime->private_data; unsigned int ptr; ptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift; @@ -1408,8 +1393,8 @@ static int calc_available_memory_size(es down(&chip->memory_mutex); list_for_each(p, &chip->buf_list) { esm_memory_t *buf = list_entry(p, esm_memory_t, list); - if (buf->empty && buf->size > max_size) - max_size = buf->size; + if (buf->empty && buf->buf.bytes > max_size) + max_size = buf->buf.bytes; } up(&chip->memory_mutex); if (max_size >= 128*1024) @@ -1427,24 +1412,25 @@ static esm_memory_t *snd_es1968_new_memo down(&chip->memory_mutex); list_for_each(p, &chip->buf_list) { buf = list_entry(p, esm_memory_t, list); - if (buf->empty && buf->size >= size) + if (buf->empty && buf->buf.bytes >= size) goto __found; } up(&chip->memory_mutex); return NULL; __found: - if (buf->size > size) { + if (buf->buf.bytes > size) { esm_memory_t *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); if (chunk == NULL) { up(&chip->memory_mutex); return NULL; } - chunk->size = buf->size - size; - chunk->buf = buf->buf + size; - chunk->addr = buf->addr + size; + chunk->buf = buf->buf; + chunk->buf.bytes -= size; + chunk->buf.area += size; + chunk->buf.addr += size; chunk->empty = 1; - buf->size = size; + buf->buf.bytes = size; list_add(&chunk->list, &buf->list); } buf->empty = 0; @@ -1462,7 +1448,7 @@ static void snd_es1968_free_memory(es196 if (buf->list.prev != &chip->buf_list) { chunk = list_entry(buf->list.prev, esm_memory_t, list); if (chunk->empty) { - chunk->size += buf->size; + chunk->buf.bytes += buf->buf.bytes; list_del(&buf->list); kfree(buf); buf = chunk; @@ -1471,7 +1457,7 @@ static void snd_es1968_free_memory(es196 if (buf->list.next != &chip->buf_list) { chunk = list_entry(buf->list.next, esm_memory_t, list); if (chunk->empty) { - buf->size += chunk->size; + buf->buf.bytes += chunk->buf.bytes; list_del(&chunk->list); kfree(chunk); } @@ -1525,9 +1511,10 @@ snd_es1968_init_dmabuf(es1968_t *chip) return -ENOMEM; } memset(chip->dma.area, 0, ESM_MEM_ALIGN); - chunk->buf = chip->dma.area + ESM_MEM_ALIGN; - chunk->addr = chip->dma.addr + ESM_MEM_ALIGN; - chunk->size = chip->dma.bytes - ESM_MEM_ALIGN; + chunk->buf = chip->dma; + chunk->buf.area += ESM_MEM_ALIGN; + chunk->buf.addr += ESM_MEM_ALIGN; + chunk->buf.bytes -= ESM_MEM_ALIGN; chunk->empty = 1; list_add(&chunk->list, &chip->buf_list); @@ -1541,11 +1528,11 @@ static int snd_es1968_hw_params(snd_pcm_ { es1968_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - esschan_t *chan = snd_magic_cast(esschan_t, runtime->private_data, return -ENXIO); + esschan_t *chan = runtime->private_data; int size = params_buffer_bytes(hw_params); if (chan->memory) { - if (chan->memory->size >= size) { + if (chan->memory->buf.bytes >= size) { runtime->dma_bytes = size; return 0; } @@ -1556,9 +1543,7 @@ static int snd_es1968_hw_params(snd_pcm_ // snd_printd("cannot allocate dma buffer: size = %d\n", size); return -ENOMEM; } - runtime->dma_bytes = size; - runtime->dma_area = chan->memory->buf; - runtime->dma_addr = chan->memory->addr; + snd_pcm_set_runtime_buffer(substream, &chan->memory->buf); return 1; /* area was changed */ } @@ -1571,7 +1556,7 @@ static int snd_es1968_hw_free(snd_pcm_su if (runtime->private_data == NULL) return 0; - chan = snd_magic_cast(esschan_t, runtime->private_data, return -ENXIO); + chan = runtime->private_data; if (chan->memory) { snd_es1968_free_memory(chip, chan->memory); chan->memory = NULL; @@ -1623,7 +1608,7 @@ static int snd_es1968_playback_open(snd_ if (apu1 < 0) return apu1; - es = snd_magic_kcalloc(esschan_t, 0, GFP_KERNEL); + es = kcalloc(1, sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); return -ENOMEM; @@ -1637,6 +1622,8 @@ static int snd_es1968_playback_open(snd_ es->substream = substream; es->mode = ESM_MODE_PLAY; + substream->dma_device = chip->dma_dev; /* for mmap */ + runtime->private_data = es; runtime->hw = snd_es1968_playback; runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = @@ -1669,7 +1656,7 @@ static int snd_es1968_capture_open(snd_p return apu2; } - es = snd_magic_kcalloc(esschan_t, 0, GFP_KERNEL); + es = kcalloc(1, sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); @@ -1692,10 +1679,12 @@ static int snd_es1968_capture_open(snd_p if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); - snd_magic_kfree(es); + kfree(es); return -ENOMEM; } - memset(es->mixbuf->buf, 0, ESM_MIXBUF_SIZE); + memset(es->mixbuf->buf.area, 0, ESM_MIXBUF_SIZE); + + substream->dma_device = chip->dma_dev; /* for mmap */ runtime->private_data = es; runtime->hw = snd_es1968_capture; @@ -1720,12 +1709,12 @@ static int snd_es1968_playback_close(snd if (substream->runtime->private_data == NULL) return 0; - es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); + es = substream->runtime->private_data; spin_lock_irqsave(&chip->substream_lock, flags); list_del(&es->list); spin_unlock_irqrestore(&chip->substream_lock, flags); snd_es1968_free_apu_pair(chip, es->apu[0]); - snd_magic_kfree(es); + kfree(es); return 0; } @@ -1738,14 +1727,14 @@ static int snd_es1968_capture_close(snd_ if (substream->runtime->private_data == NULL) return 0; - es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); + es = substream->runtime->private_data; spin_lock_irqsave(&chip->substream_lock, flags); list_del(&es->list); spin_unlock_irqrestore(&chip->substream_lock, flags); snd_es1968_free_memory(chip, es->mixbuf); snd_es1968_free_apu_pair(chip, es->apu[0]); snd_es1968_free_apu_pair(chip, es->apu[2]); - snd_magic_kfree(es); + kfree(es); return 0; } @@ -1800,11 +1789,11 @@ static void __devinit es1968_measure_clo return; } - memset(memory->buf, 0, CLOCK_MEASURE_BUFSIZE); + memset(memory->buf.area, 0, CLOCK_MEASURE_BUFSIZE); - wave_set_register(chip, apu << 3, (memory->addr - 0x10) & 0xfff8); + wave_set_register(chip, apu << 3, (memory->buf.addr - 0x10) & 0xfff8); - pa = (unsigned int)((memory->addr - chip->dma.addr) >> 1); + pa = (unsigned int)((memory->buf.addr - chip->dma.addr) >> 1); pa |= 0x00400000; /* System RAM (Bit 22) */ /* initialize apu */ @@ -1879,7 +1868,7 @@ static void __devinit es1968_measure_clo static void snd_es1968_pcm_free(snd_pcm_t *pcm) { - es1968_t *esm = snd_magic_cast(es1968_t, pcm->private_data, return); + es1968_t *esm = pcm->private_data; snd_es1968_free_dmabuf(esm); esm->pcm = NULL; } @@ -1952,7 +1941,7 @@ static void snd_es1968_update_pcm(es1968 */ static void es1968_update_hw_volume(unsigned long private_data) { - es1968_t *chip = snd_magic_cast(es1968_t, (void*)private_data, return); + es1968_t *chip = (es1968_t *) private_data; int x, val; /* Figure out which volume control button was pushed, @@ -2001,7 +1990,7 @@ static void es1968_update_hw_volume(unsi */ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - es1968_t *chip = snd_magic_cast(es1968_t, dev_id, return IRQ_NONE); + es1968_t *chip = dev_id; u32 event; if (!(event = inb(chip->io_port + 0x1A))) @@ -2418,7 +2407,7 @@ static void snd_es1968_start_irq(es1968_ */ static int es1968_suspend(snd_card_t *card, unsigned int state) { - es1968_t *chip = snd_magic_cast(es1968_t, card->pm_private_data, return -EINVAL); + es1968_t *chip = card->pm_private_data; if (! chip->do_pm) return 0; @@ -2433,7 +2422,7 @@ static int es1968_suspend(snd_card_t *ca static int es1968_resume(snd_card_t *card, unsigned int state) { - es1968_t *chip = snd_magic_cast(es1968_t, card->pm_private_data, return -EINVAL); + es1968_t *chip = card->pm_private_data; if (! chip->do_pm) return 0; @@ -2470,6 +2459,8 @@ static int snd_es1968_free(es1968_t *chi outw(0, chip->io_port + ESM_PORT_HOST_IRQ); /* disable IRQ */ } + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); #ifdef SUPPORT_JOYSTICK if (chip->res_joystick) { gameport_unregister_port(&chip->gameport); @@ -2484,15 +2475,13 @@ static int snd_es1968_free(es1968_t *chi release_resource(chip->res_io_port); kfree_nocheck(chip->res_io_port); } - if (chip->irq >= 0) - free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_es1968_dev_free(snd_device_t *device) { - es1968_t *chip = snd_magic_cast(es1968_t, device->device_data, return -ENXIO); + es1968_t *chip = device->device_data; return snd_es1968_free(chip); } @@ -2540,7 +2529,7 @@ static int __devinit snd_es1968_create(s return -ENXIO; } - chip = (es1968_t *) snd_magic_kcalloc(es1968_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (! chip) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/fm801.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/fm801.c 2004-07-13 17:09:19.000000000 -0700 @@ -40,13 +40,10 @@ #define TEA575X_RADIO 1 #endif -#define chip_t fm801_t - MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ForteMedia FM801"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ForteMedia,FM801}," +MODULE_SUPPORTED_DEVICE("{{ForteMedia,FM801}," "{Genius,SoundMaker Live 5.1}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -64,16 +61,12 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for the FM801 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(tea575x_tuner, bool, boot_devs, 0444); MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); -MODULE_PARM_SYNTAX(tea575x_tuner, SNDRV_ENABLE_DESC); /* * Direct registers @@ -233,7 +226,7 @@ static void snd_fm801_codec_write(ac97_t unsigned short reg, unsigned short val) { - fm801_t *chip = snd_magic_cast(fm801_t, ac97->private_data, return); + fm801_t *chip = ac97->private_data; int idx; /* @@ -264,7 +257,7 @@ static void snd_fm801_codec_write(ac97_t static unsigned short snd_fm801_codec_read(ac97_t *ac97, unsigned short reg) { - fm801_t *chip = snd_magic_cast(fm801_t, ac97->private_data, return -ENXIO); + fm801_t *chip = ac97->private_data; int idx; /* @@ -522,7 +515,7 @@ static snd_pcm_uframes_t snd_fm801_captu static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - fm801_t *chip = snd_magic_cast(fm801_t, dev_id, return IRQ_NONE); + fm801_t *chip = dev_id; unsigned short status; unsigned int tmp; @@ -680,7 +673,7 @@ static snd_pcm_ops_t snd_fm801_capture_o static void snd_fm801_pcm_free(snd_pcm_t *pcm) { - fm801_t *chip = snd_magic_cast(fm801_t, pcm->private_data, return); + fm801_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1176,13 +1169,13 @@ FM801_SINGLE("IEC958 Playback Switch", F static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus) { - fm801_t *chip = snd_magic_cast(fm801_t, bus->private_data, return); + fm801_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_fm801_mixer_free_ac97(ac97_t *ac97) { - fm801_t *chip = snd_magic_cast(fm801_t, ac97->private_data, return); + fm801_t *chip = ac97->private_data; if (ac97->num == 0) { chip->ac97 = NULL; } else { @@ -1252,13 +1245,13 @@ static int snd_fm801_free(fm801_t *chip) if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_fm801_dev_free(snd_device_t *device) { - fm801_t *chip = snd_magic_cast(fm801_t, device->device_data, return -ENXIO); + fm801_t *chip = device->device_data; return snd_fm801_free(chip); } @@ -1279,7 +1272,7 @@ static int __devinit snd_fm801_create(sn *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(fm801_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); --- linux-2.6.8-rc1/sound/pci/ice1712/ak4xxx.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/pci/ice1712/ak4xxx.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,7 +33,6 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); static void snd_ice1712_akm4xxx_lock(akm4xxx_t *ak, int chip) { --- linux-2.6.8-rc1/sound/pci/ice1712/aureon.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/aureon.c 2004-07-13 17:09:19.000000000 -0700 @@ -149,11 +149,19 @@ static unsigned short wm_get(ice1712_t * } /* + * set the register value of WM codec + */ +static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val) +{ + aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16); +} + +/* * set the register value of WM codec and remember it */ static void wm_put(ice1712_t *ice, int reg, unsigned short val) { - aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16); + wm_put_nocache(ice, reg, val); reg <<= 1; ice->akm[0].images[reg] = val >> 8; ice->akm[0].images[reg + 1] = val; @@ -219,10 +227,7 @@ static int wm_dac_vol_get(snd_kcontrol_t unsigned short vol; down(&ice->gpio_mutex); - if (kcontrol->private_value) - idx = WM_DAC_MASTER_ATTEN; - else - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; vol = wm_get(ice, idx) & 0x7f; if (vol <= 0x1a) ucontrol->value.integer.value[0] = 0; @@ -240,18 +245,17 @@ static int wm_dac_vol_put(snd_kcontrol_t int change; snd_ice1712_save_gpio_status(ice); - if (kcontrol->private_value) - idx = WM_DAC_MASTER_ATTEN; - else - idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; nvol = ucontrol->value.integer.value[0] + 0x1a; ovol = wm_get(ice, idx) & 0x7f; change = (ovol != nvol); if (change) { if (nvol <= 0x1a && ovol <= 0x1a) change = 0; - else - wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ + else { + wm_put(ice, idx, nvol | 0x80); /* zero-detect, prelatch */ + wm_put_nocache(ice, idx, nvol | 0x180); /* update */ + } } snd_ice1712_restore_gpio_status(ice); return change; @@ -718,15 +722,15 @@ static int __devinit aureon_init(ice1712 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { ice->num_total_dacs = 6; - ice->num_total_adcs = 6; + ice->num_total_adcs = 2; } else { /* aureon 7.1 and prodigy 7.1 */ ice->num_total_dacs = 8; - ice->num_total_adcs = 8; + ice->num_total_adcs = 2; } /* to remeber the register values */ - ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); + ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); if (! ice->akm) return -ENOMEM; ice->akm_codecs = 1; --- linux-2.6.8-rc1/sound/pci/ice1712/delta.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/delta.c 2004-07-13 17:09:19.000000000 -0700 @@ -126,7 +126,7 @@ static void ap_cs8427_codec_deassert(ice /* sequential write */ static int ap_cs8427_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) { - ice1712_t *ice = snd_magic_cast(ice1712_t, device->bus->private_data, return -EIO); + ice1712_t *ice = device->bus->private_data; int res = count; unsigned char tmp; @@ -143,7 +143,7 @@ static int ap_cs8427_sendbytes(snd_i2c_d /* sequential read */ static int ap_cs8427_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count) { - ice1712_t *ice = snd_magic_cast(ice1712_t, device->bus->private_data, return -EIO); + ice1712_t *ice = device->bus->private_data; int res = count; unsigned char tmp; --- linux-2.6.8-rc1/sound/pci/ice1712/ews.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/ews.c 2004-07-13 17:09:19.000000000 -0700 @@ -45,7 +45,7 @@ /* send SDA and SCL */ static void ewx_i2c_setlines(snd_i2c_bus_t *bus, int clk, int data) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return); + ice1712_t *ice = bus->private_data; unsigned char tmp = 0; if (clk) tmp |= ICE1712_EWX2496_SERIAL_CLOCK; @@ -57,13 +57,13 @@ static void ewx_i2c_setlines(snd_i2c_bus static int ewx_i2c_getclock(snd_i2c_bus_t *bus) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return -EIO); + ice1712_t *ice = bus->private_data; return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_CLOCK ? 1 : 0; } static int ewx_i2c_getdata(snd_i2c_bus_t *bus, int ack) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return -EIO); + ice1712_t *ice = bus->private_data; int bit; /* set RW pin to low */ snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_RW); @@ -80,7 +80,7 @@ static int ewx_i2c_getdata(snd_i2c_bus_t static void ewx_i2c_start(snd_i2c_bus_t *bus) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return); + ice1712_t *ice = bus->private_data; unsigned char mask; snd_ice1712_save_gpio_status(ice); @@ -99,13 +99,13 @@ static void ewx_i2c_start(snd_i2c_bus_t static void ewx_i2c_stop(snd_i2c_bus_t *bus) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return); + ice1712_t *ice = bus->private_data; snd_ice1712_restore_gpio_status(ice); } static void ewx_i2c_direction(snd_i2c_bus_t *bus, int clock, int data) { - ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return); + ice1712_t *ice = bus->private_data; unsigned char mask = 0; if (clock) --- linux-2.6.8-rc1/sound/pci/ice1712/ice1712.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/ice1712.c 2004-07-13 17:09:19.000000000 -0700 @@ -73,8 +73,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{" +MODULE_SUPPORTED_DEVICE("{" HOONTECH_DEVICE_DESC DELTA_DEVICE_DESC EWS_DEVICE_DESC @@ -91,19 +90,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ICE1712 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ICE1712 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(omni, bool, boot_devs, 0444); MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support."); -MODULE_PARM_SYNTAX(omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); module_param_array(cs8427_timeout, int, boot_devs, 0444); MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution."); -MODULE_PARM_SYNTAX(cs8427_timeout, SNDRV_ENABLED ", allows:{{1,1000}},default=500,skill:advanced"); module_param_array(model, charp, boot_devs, 0444); MODULE_PARM_DESC(model, "Use the given board model."); @@ -416,7 +410,7 @@ int __devinit snd_ice1712_init_cs8427(ic static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ice1712_t *ice = snd_magic_cast(ice1712_t, dev_id, return IRQ_NONE); + ice1712_t *ice = dev_id; unsigned char status; int handled = 0; @@ -874,7 +868,7 @@ static snd_pcm_ops_t snd_ice1712_capture static void snd_ice1712_pcm_free(snd_pcm_t *pcm) { - ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return); + ice1712_t *ice = pcm->private_data; ice->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -912,7 +906,7 @@ static int __devinit snd_ice1712_pcm(ice static void snd_ice1712_pcm_free_ds(snd_pcm_t *pcm) { - ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return); + ice1712_t *ice = pcm->private_data; ice->pcm_ds = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1238,7 +1232,7 @@ static int snd_ice1712_capture_pro_close static void snd_ice1712_pcm_profi_free(snd_pcm_t *pcm) { - ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return); + ice1712_t *ice = pcm->private_data; ice->pcm_pro = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1511,7 +1505,7 @@ static int __devinit snd_ice1712_build_p static void snd_ice1712_mixer_free_ac97(ac97_t *ac97) { - ice1712_t *ice = snd_magic_cast(ice1712_t, ac97->private_data, return); + ice1712_t *ice = ac97->private_data; ice->ac97 = NULL; } @@ -1570,7 +1564,7 @@ static inline unsigned int eeprom_double static void snd_ice1712_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ice1712_t *ice = snd_magic_cast(ice1712_t, entry->private_data, return); + ice1712_t *ice = entry->private_data; unsigned int idx; snd_iprintf(buffer, "%s\n\n", ice->card->longname); @@ -2496,13 +2490,13 @@ static int snd_ice1712_free(ice1712_t *i kfree_nocheck(ice->res_profi_port); } snd_ice1712_akm4xxx_free(ice); - snd_magic_kfree(ice); + kfree(ice); return 0; } static int snd_ice1712_dev_free(snd_device_t *device) { - ice1712_t *ice = snd_magic_cast(ice1712_t, device->device_data, return -ENXIO); + ice1712_t *ice = device->device_data; return snd_ice1712_free(ice); } @@ -2531,7 +2525,7 @@ static int __devinit snd_ice1712_create( return -ENXIO; } - ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); + ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); if (ice == NULL) return -ENOMEM; ice->omni = omni ? 1 : 0; --- linux-2.6.8-rc1/sound/pci/ice1712/ice1712.h 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/ice1712.h 2004-07-13 17:09:19.000000000 -0700 @@ -368,8 +368,6 @@ struct _snd_ice1712 { struct semaphore gpio_mutex; }; -#define chip_t ice1712_t - /* * gpio access functions --- linux-2.6.8-rc1/sound/pci/ice1712/ice1724.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/ice1724.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,16 +44,17 @@ #include "amp.h" #include "revo.h" #include "aureon.h" +#include "vt1720_mobo.h" MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{" +MODULE_SUPPORTED_DEVICE("{" REVO_DEVICE_DESC AMP_AUDIO2000_DEVICE_DESC AUREON_DEVICE_DESC + VT1720_MOBO_DEVICE_DESC "{VIA,VT1720}," "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," @@ -68,13 +69,10 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for ICE1724 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for ICE1724 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable ICE1724 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(model, charp, boot_devs, 0444); MODULE_PARM_DESC(model, "Use the given board model."); @@ -190,21 +188,26 @@ static void snd_vt1724_set_gpio_dir(ice1 static void snd_vt1724_set_gpio_mask(ice1712_t *ice, unsigned int data) { outw(data, ICEREG1724(ice, GPIO_WRITE_MASK)); - outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22)); + if (! ice->vt1720) /* VT1720 supports only 16 GPIO bits */ + outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22)); inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */ } static void snd_vt1724_set_gpio_data(ice1712_t *ice, unsigned int data) { outw(data, ICEREG1724(ice, GPIO_DATA)); - outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22)); + if (! ice->vt1720) + outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22)); inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */ } static unsigned int snd_vt1724_get_gpio_data(ice1712_t *ice) { unsigned int data; - data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22)); + if (! ice->vt1720) + data = (unsigned int)inb(ICEREG1724(ice, GPIO_DATA_22)); + else + data = 0; data = (data << 16) | inw(ICEREG1724(ice, GPIO_DATA)); return data; } @@ -215,7 +218,7 @@ static unsigned int snd_vt1724_get_gpio_ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ice1712_t *ice = snd_magic_cast(ice1712_t, dev_id, return IRQ_NONE); + ice1712_t *ice = dev_id; unsigned char status; int handled = 0; @@ -230,7 +233,7 @@ static irqreturn_t snd_vt1724_interrupt( if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) { if (ice->rmidi[0]) snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs); - outb(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX, ICEREG1724(ice, IRQSTAT)); + outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT)); status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX); } if (status & VT1724_IRQ_MTPCM) { @@ -317,6 +320,13 @@ static snd_pcm_hw_constraint_list_t hw_c .mask = 0, }; +struct vt1724_pcm_reg { + unsigned int addr; /* ADDR register offset */ + unsigned int size; /* SIZE register offset */ + unsigned int count; /* COUNT register offset */ + unsigned int start; /* start & pause bit */ +}; + static int snd_vt1724_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { ice1712_t *ice = snd_pcm_substream_chip(substream); @@ -327,8 +337,10 @@ static int snd_vt1724_pcm_trigger(snd_pc what = 0; snd_pcm_group_for_each(pos, substream) { + struct vt1724_pcm_reg *reg; s = snd_pcm_group_substream_entry(pos); - what |= (unsigned long)(s->runtime->private_data); + reg = s->runtime->private_data; + what |= reg->start; snd_pcm_trigger_done(s, substream); } @@ -371,12 +383,26 @@ static int snd_vt1724_pcm_trigger(snd_pc #define DMA_PAUSES (VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\ VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE) +static int get_max_rate(ice1712_t *ice) +{ + if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { + if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720) + return 192000; + else + return 96000; + } else + return 48000; +} + static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force) { unsigned long flags; unsigned char val, old; unsigned int i; + if (rate > get_max_rate(ice)) + return; + spin_lock_irqsave(&ice->reg_lock, flags); if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { @@ -410,6 +436,8 @@ static void snd_vt1724_set_pro_rate(ice1 val = 0; break; } + old = inb(ICEMT1724(ice, RATE)); + val |= (old & 0xf0); outb(val, ICEMT1724(ice, RATE)); if (rate == ice->cur_rate) { spin_unlock_irqrestore(&ice->reg_lock, flags); @@ -419,7 +447,7 @@ static void snd_vt1724_set_pro_rate(ice1 ice->cur_rate = rate; /* check MT02 */ - if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) { + if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { val = old = inb(ICEMT1724(ice, I2S_FORMAT)); if (rate > 96000) val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */ @@ -446,15 +474,6 @@ static void snd_vt1724_set_pro_rate(ice1 if (ice->akm[i].ops.set_rate_val) ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); } - - /* set up AC97 registers if needed */ - if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) && ice->ac97) { - snd_ac97_set_rate(ice->ac97, AC97_PCM_FRONT_DAC_RATE, rate); - snd_ac97_set_rate(ice->ac97, AC97_PCM_SURR_DAC_RATE, rate); - snd_ac97_set_rate(ice->ac97, AC97_PCM_LFE_DAC_RATE, rate); - snd_ac97_set_rate(ice->ac97, AC97_SPDIF, rate); - snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, rate); - } } static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream, @@ -562,7 +581,9 @@ static snd_pcm_uframes_t snd_vt1724_play ptr = inl(ICEMT1724(ice, PLAYBACK_SIZE)) & 0xffffff; ptr = (ptr + 1) << 2; ptr = bytes_to_frames(substream->runtime, ptr); - if (ptr <= substream->runtime->buffer_size) + if (! ptr) + ; + else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); @@ -572,17 +593,10 @@ static snd_pcm_uframes_t snd_vt1724_play return ptr; } -struct vt1724_pcm_reg { - unsigned int addr; /* ADDR register offset */ - unsigned int size; /* SIZE register offset */ - unsigned int count; /* COUNT register offset */ - unsigned int start; /* start bit */ - unsigned int pause; /* pause bit */ -}; - -static int snd_vt1724_pcm_prepare(snd_pcm_substream_t *substream, const struct vt1724_pcm_reg *reg) +static int snd_vt1724_pcm_prepare(snd_pcm_substream_t *substream) { ice1712_t *ice = snd_pcm_substream_chip(substream); + struct vt1724_pcm_reg *reg = substream->runtime->private_data; spin_lock(&ice->reg_lock); outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); @@ -592,9 +606,10 @@ static int snd_vt1724_pcm_prepare(snd_pc return 0; } -static snd_pcm_uframes_t snd_vt1724_pcm_pointer(snd_pcm_substream_t *substream, const struct vt1724_pcm_reg *reg) +static snd_pcm_uframes_t snd_vt1724_pcm_pointer(snd_pcm_substream_t *substream) { ice1712_t *ice = snd_pcm_substream_chip(substream); + struct vt1724_pcm_reg *reg = substream->runtime->private_data; size_t ptr; if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) @@ -607,7 +622,9 @@ static snd_pcm_uframes_t snd_vt1724_pcm_ ptr = inw(ice->profi_port + reg->size); ptr = (ptr + 1) << 2; ptr = bytes_to_frames(substream->runtime, ptr); - if (ptr <= substream->runtime->buffer_size) + if (! ptr) + ; + else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); @@ -617,24 +634,20 @@ static snd_pcm_uframes_t snd_vt1724_pcm_ #endif } -const static struct vt1724_pcm_reg vt1724_capture_pro_reg = { +static struct vt1724_pcm_reg vt1724_playback_pro_reg = { + .addr = VT1724_MT_PLAYBACK_ADDR, + .size = VT1724_MT_PLAYBACK_SIZE, + .count = VT1724_MT_PLAYBACK_COUNT, + .start = VT1724_PDMA0_START, +}; + +static struct vt1724_pcm_reg vt1724_capture_pro_reg = { .addr = VT1724_MT_CAPTURE_ADDR, .size = VT1724_MT_CAPTURE_SIZE, .count = VT1724_MT_CAPTURE_COUNT, .start = VT1724_RDMA0_START, - .pause = VT1724_RDMA0_PAUSE, }; -static int snd_vt1724_capture_pro_prepare(snd_pcm_substream_t * substream) -{ - return snd_vt1724_pcm_prepare(substream, &vt1724_capture_pro_reg); -} - -static snd_pcm_uframes_t snd_vt1724_capture_pro_pointer(snd_pcm_substream_t * substream) -{ - return snd_vt1724_pcm_pointer(substream, &vt1724_capture_pro_reg); -} - static snd_pcm_hardware_t snd_vt1724_playback_pro = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -698,9 +711,10 @@ static snd_pcm_hardware_t snd_vt1724_2ch static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) { + if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { /* I2S */ - if (ice->eeprom.data[ICE_EEP2_I2S] & 0x08) + /* VT1720 doesn't support more than 96kHz */ + if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720) return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192); else { runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000; @@ -709,25 +723,14 @@ static int set_rate_constraints(ice1712_ } } else if (ice->ac97) { /* ACLINK */ - int ratec; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ratec = AC97_RATES_FRONT_DAC; - else - ratec = AC97_RATES_ADC; - runtime->hw.rates = ice->ac97->rates[ratec]; runtime->hw.rate_max = 48000; - if (runtime->hw.rates == SNDRV_PCM_RATE_48000) { - runtime->hw.rate_min = 48000; - return 0; - } else { - runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000; - return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48); - } + runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000; + return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48); } return 0; } -/* multi-channel playback needs alignment 8x32bit regarless of the channels +/* multi-channel playback needs alignment 8x32bit regardless of the channels * actually used */ #define VT1724_BUFFER_ALIGN 0x20 @@ -738,7 +741,7 @@ static int snd_vt1724_playback_pro_open( ice1712_t *ice = snd_pcm_substream_chip(substream); int chs; - runtime->private_data = (void*)VT1724_PDMA0_START; /* irq/status/trigger bit */ + runtime->private_data = &vt1724_playback_pro_reg; ice->playback_pro_substream = substream; runtime->hw = snd_vt1724_playback_pro; snd_pcm_set_sync(substream); @@ -767,12 +770,16 @@ static int snd_vt1724_capture_pro_open(s ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - runtime->private_data = (void*)VT1724_RDMA0_START; /* irq/status/trigger bit */ + runtime->private_data = &vt1724_capture_pro_reg; ice->capture_pro_substream = substream; runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); set_rate_constraints(ice, substream); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + VT1724_BUFFER_ALIGN); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + VT1724_BUFFER_ALIGN); return 0; } @@ -814,9 +821,9 @@ static snd_pcm_ops_t snd_vt1724_capture_ .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, - .prepare = snd_vt1724_capture_pro_prepare, + .prepare = snd_vt1724_pcm_prepare, .trigger = snd_vt1724_pcm_trigger, - .pointer = snd_vt1724_capture_pro_pointer, + .pointer = snd_vt1724_pcm_pointer, }; static int __devinit snd_vt1724_pcm_profi(ice1712_t * ice, int device) @@ -848,40 +855,60 @@ static int __devinit snd_vt1724_pcm_prof * SPDIF PCM */ -const static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { +static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { .addr = VT1724_MT_PDMA4_ADDR, .size = VT1724_MT_PDMA4_SIZE, .count = VT1724_MT_PDMA4_COUNT, .start = VT1724_PDMA4_START, - .pause = VT1724_PDMA4_PAUSE, }; -const static struct vt1724_pcm_reg vt1724_capture_spdif_reg = { +static struct vt1724_pcm_reg vt1724_capture_spdif_reg = { .addr = VT1724_MT_RDMA1_ADDR, .size = VT1724_MT_RDMA1_SIZE, .count = VT1724_MT_RDMA1_COUNT, .start = VT1724_RDMA1_START, - .pause = VT1724_RDMA1_PAUSE, }; -static int snd_vt1724_playback_spdif_prepare(snd_pcm_substream_t * substream) +/* update spdif control bits; call with reg_lock */ +static void update_spdif_bits(ice1712_t *ice, unsigned int val) { - return snd_vt1724_pcm_prepare(substream, &vt1724_playback_spdif_reg); -} + unsigned char cbit, disabled; -static snd_pcm_uframes_t snd_vt1724_playback_spdif_pointer(snd_pcm_substream_t * substream) -{ - return snd_vt1724_pcm_pointer(substream, &vt1724_playback_spdif_reg); + cbit = inb(ICEREG1724(ice, SPDIF_CFG)); + disabled = cbit & ~VT1724_CFG_SPDIF_OUT_EN; + if (cbit != disabled) + outb(disabled, ICEREG1724(ice, SPDIF_CFG)); + outw(val, ICEMT1724(ice, SPDIF_CTRL)); + if (cbit != disabled) + outb(cbit, ICEREG1724(ice, SPDIF_CFG)); + outw(val, ICEMT1724(ice, SPDIF_CTRL)); } -static int snd_vt1724_capture_spdif_prepare(snd_pcm_substream_t * substream) +/* update SPDIF control bits according to the given rate */ +static void update_spdif_rate(ice1712_t *ice, unsigned int rate) { - return snd_vt1724_pcm_prepare(substream, &vt1724_capture_spdif_reg); + unsigned int val, nval; + unsigned long flags; + + spin_lock_irqsave(&ice->reg_lock, flags); + nval = val = inw(ICEMT1724(ice, SPDIF_CTRL)); + nval &= ~(7 << 12); + switch (rate) { + case 44100: break; + case 48000: nval |= 2 << 12; break; + case 32000: nval |= 3 << 12; break; + } + if (val != nval) + update_spdif_bits(ice, nval); + spin_unlock_irqrestore(&ice->reg_lock, flags); } -static snd_pcm_uframes_t snd_vt1724_capture_spdif_pointer(snd_pcm_substream_t * substream) +static int snd_vt1724_playback_spdif_prepare(snd_pcm_substream_t * substream) { - return snd_vt1724_pcm_pointer(substream, &vt1724_capture_spdif_reg); + ice1712_t *ice = snd_pcm_substream_chip(substream); + if (! ice->force_pdma4) + update_spdif_rate(ice, substream->runtime->rate); + return snd_vt1724_pcm_prepare(substream); } static int snd_vt1724_playback_spdif_open(snd_pcm_substream_t *substream) @@ -889,7 +916,7 @@ static int snd_vt1724_playback_spdif_ope ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - runtime->private_data = (void*)VT1724_PDMA4_START; /* irq/status/trigger bit */ + runtime->private_data = &vt1724_playback_spdif_reg; ice->playback_con_substream = substream; if (ice->force_pdma4) { runtime->hw = snd_vt1724_2ch_stereo; @@ -898,6 +925,10 @@ static int snd_vt1724_playback_spdif_ope runtime->hw = snd_vt1724_spdif; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + VT1724_BUFFER_ALIGN); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + VT1724_BUFFER_ALIGN); return 0; } @@ -917,7 +948,7 @@ static int snd_vt1724_capture_spdif_open ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - runtime->private_data = (void*)VT1724_RDMA1_START; /* irq/status/trigger bit */ + runtime->private_data = &vt1724_capture_spdif_reg; ice->capture_con_substream = substream; if (ice->force_rdma1) { runtime->hw = snd_vt1724_2ch_stereo; @@ -926,6 +957,10 @@ static int snd_vt1724_capture_spdif_open runtime->hw = snd_vt1724_spdif; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + VT1724_BUFFER_ALIGN); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + VT1724_BUFFER_ALIGN); return 0; } @@ -948,7 +983,7 @@ static snd_pcm_ops_t snd_vt1724_playback .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_playback_spdif_prepare, .trigger = snd_vt1724_pcm_trigger, - .pointer = snd_vt1724_playback_spdif_pointer, + .pointer = snd_vt1724_pcm_pointer, }; static snd_pcm_ops_t snd_vt1724_capture_spdif_ops = { @@ -957,9 +992,9 @@ static snd_pcm_ops_t snd_vt1724_capture_ .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, - .prepare = snd_vt1724_capture_spdif_prepare, + .prepare = snd_vt1724_pcm_prepare, .trigger = snd_vt1724_pcm_trigger, - .pointer = snd_vt1724_capture_spdif_pointer, + .pointer = snd_vt1724_pcm_pointer, }; @@ -1017,27 +1052,24 @@ static int __devinit snd_vt1724_pcm_spdi * independent surround PCMs */ -const static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { +static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { { .addr = VT1724_MT_PDMA1_ADDR, .size = VT1724_MT_PDMA1_SIZE, .count = VT1724_MT_PDMA1_COUNT, .start = VT1724_PDMA1_START, - .pause = VT1724_PDMA1_PAUSE, }, { .addr = VT1724_MT_PDMA2_ADDR, .size = VT1724_MT_PDMA2_SIZE, .count = VT1724_MT_PDMA2_COUNT, .start = VT1724_PDMA2_START, - .pause = VT1724_PDMA2_PAUSE, }, { .addr = VT1724_MT_PDMA3_ADDR, .size = VT1724_MT_PDMA3_SIZE, .count = VT1724_MT_PDMA3_COUNT, .start = VT1724_PDMA3_START, - .pause = VT1724_PDMA3_PAUSE, }, }; @@ -1051,12 +1083,7 @@ static int snd_vt1724_playback_indep_pre if (inb(ICEMT1724(ice, BURST)) < val) outb(val, ICEMT1724(ice, BURST)); spin_unlock(&ice->reg_lock); - return snd_vt1724_pcm_prepare(substream, &vt1724_playback_dma_regs[substream->number]); -} - -static snd_pcm_uframes_t snd_vt1724_playback_indep_pointer(snd_pcm_substream_t * substream) -{ - return snd_vt1724_pcm_pointer(substream, &vt1724_playback_dma_regs[substream->number]); + return snd_vt1724_pcm_prepare(substream); } static int snd_vt1724_playback_indep_open(snd_pcm_substream_t *substream) @@ -1071,7 +1098,7 @@ static int snd_vt1724_playback_indep_ope return -EBUSY; /* FIXME: should handle blocking mode properly */ } up(&ice->open_mutex); - runtime->private_data = (void*)(1 << (substream->number + 4)); + runtime->private_data = &vt1724_playback_dma_regs[substream->number]; ice->playback_con_substream_ds[substream->number] = substream; runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); @@ -1100,7 +1127,7 @@ static snd_pcm_ops_t snd_vt1724_playback .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_playback_indep_prepare, .trigger = snd_vt1724_pcm_trigger, - .pointer = snd_vt1724_playback_indep_pointer, + .pointer = snd_vt1724_pcm_pointer, }; @@ -1181,7 +1208,7 @@ static inline unsigned int eeprom_triple static void snd_vt1724_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ice1712_t *ice = snd_magic_cast(ice1712_t, entry->private_data, return); + ice1712_t *ice = entry->private_data; unsigned int idx; snd_iprintf(buffer, "%s\n\n", ice->card->longname); @@ -1274,7 +1301,7 @@ static unsigned int encode_spdif_bits(sn } } else { /* consumer */ - val |= diga->status[0] & 0x04; /* copyright */ + val |= diga->status[1] & 0x04; /* copyright */ if ((diga->status[0] & IEC958_AES0_CON_EMPHASIS)== IEC958_AES0_CON_EMPHASIS_5015) val |= 1U << 3; val |= (unsigned int)(diga->status[1] & 0x3f) << 4; /* category */ @@ -1331,16 +1358,8 @@ static int snd_vt1724_spdif_default_put( val = encode_spdif_bits(&ucontrol->value.iec958); spin_lock_irqsave(&ice->reg_lock, flags); old = inw(ICEMT1724(ice, SPDIF_CTRL)); - if (val != old) { - unsigned char cbit, disabled; - cbit = inb(ICEREG1724(ice, SPDIF_CFG)); - disabled = cbit & ~VT1724_CFG_SPDIF_OUT_EN; - if (cbit != disabled) - outb(disabled, ICEREG1724(ice, SPDIF_CFG)); - outw(val, ICEMT1724(ice, SPDIF_CTRL)); - if (cbit != disabled) - outb(cbit, ICEREG1724(ice, SPDIF_CFG)); - } + if (val != old) + update_spdif_bits(ice, val); spin_unlock_irqrestore(&ice->reg_lock, flags); return (val != old); } @@ -1544,6 +1563,7 @@ static int snd_vt1724_pro_internal_clock { ice1712_t *ice = snd_kcontrol_chip(kcontrol); unsigned char oval; + int rate; int change = 0; spin_lock_irq(&ice->reg_lock); @@ -1551,10 +1571,13 @@ static int snd_vt1724_pro_internal_clock if (ucontrol->value.enumerated.item[0] == 15) { outb(oval | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); } else { - PRO_RATE_DEFAULT = rates[ucontrol->value.integer.value[0] % 15]; - spin_unlock_irq(&ice->reg_lock); - snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 1); - spin_lock_irq(&ice->reg_lock); + rate = rates[ucontrol->value.integer.value[0] % 15]; + if (rate <= get_max_rate(ice)) { + PRO_RATE_DEFAULT = rate; + spin_unlock_irq(&ice->reg_lock); + snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 1); + spin_lock_irq(&ice->reg_lock); + } } change = inb(ICEMT1724(ice, RATE)) != oval; spin_unlock_irq(&ice->reg_lock); @@ -1815,6 +1838,7 @@ static struct snd_ice1712_card_info *car snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, + snd_vt1720_mobo_cards, 0, }; @@ -1822,24 +1846,28 @@ static struct snd_ice1712_card_info *car /* */ -unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr) +static void wait_i2c_busy(ice1712_t *ice) { - long t = 0x10000; + int t = 0x10000; + while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--) + ; +} +unsigned char snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr) +{ outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); - while (t-- > 0 && (inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY)) ; + wait_i2c_busy(ice); return inb(ICEREG1724(ice, I2C_DATA)); } void snd_vt1724_write_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr, unsigned char data) { - long t = 0x10000; - + wait_i2c_busy(ice); outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(data, ICEREG1724(ice, I2C_DATA)); outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); - while (t-- > 0 && (inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY)) ; + wait_i2c_busy(ice); } static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice, const char *modelname) @@ -1930,9 +1958,6 @@ static int __devinit snd_vt1724_chip_ini outb(0, ICEREG1724(ice, POWERDOWN)); - /* read back to check the availability of SPDIF out */ - ice->eeprom.data[ICE_EEP2_SPDIF] = inb(ICEREG1724(ice, SPDIF_CFG)); - return 0; } @@ -1994,10 +2019,9 @@ static int __devinit snd_vt1724_build_co if (ice->num_total_dacs > 0) { snd_kcontrol_new_t tmp = snd_vt1724_mixer_pro_analog_route; - if (ice->vt1720) + tmp.count = ice->num_total_dacs; + if (ice->vt1720 && tmp.count > 2) tmp.count = 2; - else - tmp.count = ice->num_total_dacs; err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice)); if (err < 0) return err; @@ -2032,13 +2056,13 @@ static int snd_vt1724_free(ice1712_t *ic kfree_nocheck(ice->res_profi_port); } snd_ice1712_akm4xxx_free(ice); - snd_magic_kfree(ice); + kfree(ice); return 0; } static int snd_vt1724_dev_free(snd_device_t *device) { - ice1712_t *ice = snd_magic_cast(ice1712_t, device->device_data, return -ENXIO); + ice1712_t *ice = device->device_data; return snd_vt1724_free(ice); } @@ -2060,7 +2084,7 @@ static int __devinit snd_vt1724_create(s if ((err = pci_enable_device(pci)) < 0) return err; - ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); + ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); if (ice == NULL) return -ENOMEM; ice->vt1724 = 1; --- linux-2.6.8-rc1/sound/pci/ice1712/Makefile 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/Makefile 2004-07-13 17:09:19.000000000 -0700 @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o --- linux-2.6.8-rc1/sound/pci/ice1712/revo.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ice1712/revo.c 2004-07-13 17:09:19.000000000 -0700 @@ -128,7 +128,7 @@ static int __devinit revo_init(ice1712_t switch (ice->eeprom.subvendor) { case VT1724_SUBDEVICE_REVOLUTION71: ice->num_total_dacs = 8; - ice->num_total_adcs = 4; + ice->num_total_adcs = 2; break; default: snd_BUG(); @@ -136,7 +136,7 @@ static int __devinit revo_init(ice1712_t } /* second stage of initialization, analog parts and others */ - ak = ice->akm = snd_kcalloc(sizeof(akm4xxx_t) * 2, GFP_KERNEL); + ak = ice->akm = kcalloc(2, sizeof(akm4xxx_t), GFP_KERNEL); if (! ak) return -ENOMEM; ice->akm_codecs = 2; --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/sound/pci/ice1712/vt1720_mobo.c 2004-07-13 17:09:19.000000000 -0700 @@ -0,0 +1,97 @@ +/* + * ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT) + * + * Lowlevel functions for VT1720-based motherboards + * + * Copyright (c) 2004 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "vt1720_mobo.h" + + +static int __devinit k8x800_init(ice1712_t *ice) +{ + ice->vt1720 = 1; + + /* VT1616 codec */ + ice->num_total_dacs = 6; + ice->num_total_adcs = 2; + + /* WM8728 codec */ + /* FIXME: TODO */ + + return 0; +} + +static int __devinit k8x800_add_controls(ice1712_t *ice) +{ + /* FIXME: needs some quirks for VT1616? */ + return 0; +} + +/* EEPROM image */ + +static unsigned char k8x800_eeprom[] __devinitdata = { + 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ + 0x02, /* ACLINK: ACLINK, packed */ + 0x00, /* I2S: - */ + 0x00, /* SPDIF: - */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x00, /* - */ + 0xff, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0x00, /* - */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* - */ +}; + + +/* entry point */ +struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { + { + .subvendor = VT1720_SUBDEVICE_K8X800, + .name = "Albatron K8X800 Pro II", + .model = "k8x800", + .chip_init = k8x800_init, + .build_controls = k8x800_add_controls, + .eeprom_size = sizeof(k8x800_eeprom), + .eeprom_data = k8x800_eeprom, + }, + { + .subvendor = VT1720_SUBDEVICE_ZNF3_150, + .name = "Chaintech ZNF3-150", + /* identical with k8x800 */ + .chip_init = k8x800_init, + .build_controls = k8x800_add_controls, + .eeprom_size = sizeof(k8x800_eeprom), + .eeprom_data = k8x800_eeprom, + }, + { } /* terminator */ +}; + --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25/sound/pci/ice1712/vt1720_mobo.h 2004-07-13 17:09:19.000000000 -0700 @@ -0,0 +1,35 @@ +#ifndef __SOUND_VT1720_MOBO_H +#define __SOUND_VT1720_MOBO_H + +/* + * ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT) + * + * Lowlevel functions for VT1720-based motherboards + * + * Copyright (c) 2004 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define VT1720_MOBO_DEVICE_DESC "{Albatron,K8X800 Pro II},"\ + "{Chaintech,ZNF3-150}," + +#define VT1720_SUBDEVICE_K8X800 0xf217052c +#define VT1720_SUBDEVICE_ZNF3_150 0x0f2741f6 + +extern struct snd_ice1712_card_info snd_vt1720_mobo_cards[]; + +#endif /* __SOUND_VT1720_MOBO_H */ --- linux-2.6.8-rc1/sound/pci/intel8x0.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/pci/intel8x0.c 2004-07-13 17:09:19.000000000 -0700 @@ -48,8 +48,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Intel,82801AA-ICH}," +MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{Intel,82901AB-ICH0}," "{Intel,82801BA-ICH2}," "{Intel,82801CA-ICH3}," @@ -85,28 +84,21 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(ac97_clock, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); -MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0"); module_param_array(ac97_quirk, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1"); #ifdef SUPPORT_JOYSTICK module_param_array(joystick, bool, boot_devs, 0444); MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard."); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); #endif #ifdef SUPPORT_MIDI module_param_array(mpu_port, int, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU401 port # for Intel i8x0 driver."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x300}},dialog:list"); #endif /* @@ -149,6 +141,9 @@ MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABL #ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a #endif +#ifndef PCI_DEVICE_ID_NVIDIA_CK8_AUDIO +#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a +#endif #ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #endif @@ -397,7 +392,6 @@ typedef struct { } ichdev_t; typedef struct _snd_intel8x0 intel8x0_t; -#define chip_t intel8x0_t struct _snd_intel8x0 { unsigned int device_type; @@ -463,6 +457,7 @@ static struct pci_device_id snd_intel8x0 { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7012 */ { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */ { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */ + { 0x10de, 0x008a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8 */ { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */ { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8S */ { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ @@ -605,7 +600,7 @@ static void snd_intel8x0_codec_write(ac9 unsigned short reg, unsigned short val) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + intel8x0_t *chip = ac97->private_data; spin_lock(&chip->ac97_lock); if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { @@ -619,7 +614,7 @@ static void snd_intel8x0_codec_write(ac9 static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, unsigned short reg) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0); + intel8x0_t *chip = ac97->private_data; unsigned short res; unsigned int tmp; @@ -669,7 +664,7 @@ static int snd_intel8x0_ali_codec_semaph static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short reg) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0); + intel8x0_t *chip = ac97->private_data; unsigned short data = 0xffff; spin_lock(&chip->ac97_lock); @@ -689,7 +684,7 @@ static unsigned short snd_intel8x0_ali_c static void snd_intel8x0_ali_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + intel8x0_t *chip = ac97->private_data; spin_lock(&chip->ac97_lock); if (snd_intel8x0_ali_codec_semaphore(chip)) { @@ -822,7 +817,7 @@ static inline void snd_intel8x0_update(i static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, dev_id, return IRQ_NONE); + intel8x0_t *chip = dev_id; ichdev_t *ichdev; unsigned int status; unsigned int i; @@ -1058,17 +1053,23 @@ static snd_pcm_uframes_t snd_intel8x0_pc { intel8x0_t *chip = snd_pcm_substream_chip(substream); ichdev_t *ichdev = get_ichdev(substream); - unsigned long flags; size_t ptr1, ptr; + int civ, timeout = 10; + unsigned int position; - ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift; - if (ptr1 != 0) - ptr = ichdev->fragsize1 - ptr1; - else - ptr = 0; - spin_lock_irqsave(&chip->reg_lock, flags); - ptr += ichdev->position; - spin_unlock_irqrestore(&chip->reg_lock, flags); + do { + civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); + ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); + position = ichdev->position; + if (ptr1 == 0) + udelay(1); + if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && + ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) + break; + } while (timeout--); + ptr1 <<= ichdev->pos_shift; + ptr = ichdev->fragsize1 - ptr1; + ptr += position; if (ptr >= ichdev->size) return 0; return bytes_to_frames(substream->runtime, ptr); @@ -1627,13 +1628,13 @@ static int __devinit snd_intel8x0_pcm(in static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return); + intel8x0_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + intel8x0_t *chip = ac97->private_data; chip->ac97[ac97->num] = NULL; } @@ -2198,7 +2199,7 @@ static int snd_intel8x0_free(intel8x0_t } if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } @@ -2208,7 +2209,7 @@ static int snd_intel8x0_free(intel8x0_t */ static int intel8x0_suspend(snd_card_t *card, unsigned int state) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL); + intel8x0_t *chip = card->pm_private_data; int i; for (i = 0; i < chip->pcm_devs; i++) @@ -2223,7 +2224,7 @@ static int intel8x0_suspend(snd_card_t * static int intel8x0_resume(snd_card_t *card, unsigned int state) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL); + intel8x0_t *chip = card->pm_private_data; int i; pci_restore_state(chip->pci, chip->pci_state); @@ -2346,7 +2347,7 @@ static void __devinit intel8x0_measure_a static void snd_intel8x0_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, entry->private_data, return); + intel8x0_t *chip = entry->private_data; unsigned int tmp; snd_iprintf(buffer, "Intel8x0\n\n"); @@ -2379,7 +2380,7 @@ static void __devinit snd_intel8x0_proc_ static int snd_intel8x0_dev_free(snd_device_t *device) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, device->device_data, return -ENXIO); + intel8x0_t *chip = device->device_data; return snd_intel8x0_free(chip); } @@ -2438,7 +2439,7 @@ static int __devinit snd_intel8x0_create if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(intel8x0_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -2614,6 +2615,7 @@ static struct shortname_table { { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, { PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" }, + { PCI_DEVICE_ID_NVIDIA_CK8_AUDIO, "NVidia CK8" }, { 0x746d, "AMD AMD8111" }, { 0x7445, "AMD AMD768" }, { 0x5455, "ALi M5455" }, --- linux-2.6.8-rc1/sound/pci/intel8x0m.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/intel8x0m.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,8 +42,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440 modem"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Intel,82801AA-ICH}," +MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{Intel,82901AB-ICH0}," "{Intel,82801BA-ICH2}," "{Intel,82801CA-ICH3}," @@ -60,16 +59,12 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Intel i8x0 modemcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Intel i8x0 modemcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(ac97_clock, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); -MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0"); /* * Direct registers @@ -228,7 +223,6 @@ typedef struct { } ichdev_t; typedef struct _snd_intel8x0m intel8x0_t; -#define chip_t intel8x0_t struct _snd_intel8x0m { unsigned int device_type; @@ -408,7 +402,7 @@ static void snd_intel8x0_codec_write(ac9 unsigned short reg, unsigned short val) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + intel8x0_t *chip = ac97->private_data; spin_lock(&chip->ac97_lock); if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { @@ -422,7 +416,7 @@ static void snd_intel8x0_codec_write(ac9 static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, unsigned short reg) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0); + intel8x0_t *chip = ac97->private_data; unsigned short res; unsigned int tmp; @@ -542,7 +536,7 @@ static inline void snd_intel8x0_update(i static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, dev_id, return IRQ_NONE); + intel8x0_t *chip = dev_id; ichdev_t *ichdev; unsigned int status; unsigned int i; @@ -872,13 +866,13 @@ static int __devinit snd_intel8x0_pcm(in static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return); + intel8x0_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + intel8x0_t *chip = ac97->private_data; chip->ac97 = NULL; } @@ -1071,7 +1065,7 @@ static int snd_intel8x0_free(intel8x0_t } if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } @@ -1081,7 +1075,7 @@ static int snd_intel8x0_free(intel8x0_t */ static int intel8x0m_suspend(snd_card_t *card, unsigned int state) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL); + intel8x0_t *chip = card->pm_private_data; int i; for (i = 0; i < chip->pcm_devs; i++) @@ -1094,7 +1088,7 @@ static int intel8x0m_suspend(snd_card_t static int intel8x0m_resume(snd_card_t *card, unsigned int state) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->pm_private_data, return -EINVAL); + intel8x0_t *chip = card->pm_private_data; pci_enable_device(chip->pci); pci_set_master(chip->pci); snd_intel8x0_chip_init(chip, 0); @@ -1109,7 +1103,7 @@ static int intel8x0m_resume(snd_card_t * static void snd_intel8x0m_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, entry->private_data, return); + intel8x0_t *chip = entry->private_data; unsigned int tmp; snd_iprintf(buffer, "Intel8x0m\n\n"); @@ -1135,7 +1129,7 @@ static void __devinit snd_intel8x0m_proc static int snd_intel8x0_dev_free(snd_device_t *device) { - intel8x0_t *chip = snd_magic_cast(intel8x0_t, device->device_data, return -ENXIO); + intel8x0_t *chip = device->device_data; return snd_intel8x0_free(chip); } @@ -1168,7 +1162,7 @@ static int __devinit snd_intel8x0m_creat if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(intel8x0_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); --- linux-2.6.8-rc1/sound/pci/korg1212/korg1212.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/korg1212/korg1212.c 2004-07-13 17:09:19.000000000 -0700 @@ -411,8 +411,7 @@ struct _snd_korg1212 { MODULE_DESCRIPTION("korg1212"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{KORG,korg1212}}"); +MODULE_SUPPORTED_DEVICE("{{KORG,korg1212}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -421,13 +420,10 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Korg 1212 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Korg 1212 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_AUTHOR("Haroldo Gamal "); static struct pci_device_id snd_korg1212_ids[] = { @@ -637,7 +633,7 @@ static void snd_korg1212_SendStopAndWait /* timer callback for checking the ack of stop request */ static void snd_korg1212_timer_func(unsigned long data) { - korg1212_t *korg1212 = snd_magic_cast(korg1212_t, (void*)data, return); + korg1212_t *korg1212 = (korg1212_t *) data; spin_lock(&korg1212->lock); if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0) { @@ -1143,7 +1139,7 @@ static void snd_korg1212_OnDSPDownloadCo static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u32 doorbellValue; - korg1212_t *korg1212 = snd_magic_cast(korg1212_t, dev_id, return IRQ_NONE); + korg1212_t *korg1212 = dev_id; if(irq != korg1212->irq) return IRQ_NONE; @@ -1407,20 +1403,21 @@ static void snd_korg1212_free_pcm(snd_pc static int snd_korg1212_playback_open(snd_pcm_substream_t *substream) { unsigned long flags; - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]); #endif + substream->dma_device = korg1212->dma_dev; /* set for mmap */ + snd_pcm_set_sync(substream); // ??? snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_playback_info; - runtime->dma_area = (char *) korg1212->playDataBufsPtr; - runtime->dma_bytes = K1212_BUF_SIZE; + snd_pcm_set_runtime_buffer(substream, &korg1212->dma_play); spin_lock_irqsave(&korg1212->lock, flags); @@ -1438,20 +1435,21 @@ static int snd_korg1212_playback_open(sn static int snd_korg1212_capture_open(snd_pcm_substream_t *substream) { unsigned long flags; - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]); #endif + substream->dma_device = korg1212->dma_dev; /* set for mmap */ + snd_pcm_set_sync(substream); // ??? snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_capture_info; - runtime->dma_area = (char *) korg1212->recordDataBufsPtr; - runtime->dma_bytes = K1212_BUF_SIZE; + snd_pcm_set_runtime_buffer(substream, &korg1212->dma_rec); spin_lock_irqsave(&korg1212->lock, flags); @@ -1468,7 +1466,7 @@ static int snd_korg1212_capture_open(snd static int snd_korg1212_playback_close(snd_pcm_substream_t *substream) { unsigned long flags; - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n", stateName[korg1212->cardState]); @@ -1490,7 +1488,7 @@ static int snd_korg1212_playback_close(s static int snd_korg1212_capture_close(snd_pcm_substream_t *substream) { unsigned long flags; - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_close [%s]\n", stateName[korg1212->cardState]); @@ -1532,7 +1530,7 @@ static int snd_korg1212_hw_params(snd_pc snd_pcm_hw_params_t *params) { unsigned long flags; - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); int err; #if K1212_DEBUG_LEVEL > 0 @@ -1560,7 +1558,7 @@ static int snd_korg1212_hw_params(snd_pc static int snd_korg1212_prepare(snd_pcm_substream_t *substream) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); int rc; #if K1212_DEBUG_LEVEL > 0 @@ -1595,7 +1593,7 @@ static int snd_korg1212_prepare(snd_pcm_ static int snd_korg1212_trigger(snd_pcm_substream_t *substream, int cmd) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); int rc; #if K1212_DEBUG_LEVEL > 0 @@ -1640,7 +1638,7 @@ static int snd_korg1212_trigger(snd_pcm_ static snd_pcm_uframes_t snd_korg1212_playback_pointer(snd_pcm_substream_t *substream) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); snd_pcm_uframes_t pos; pos = korg1212->currentBuffer * kPlayBufferFrames; @@ -1655,7 +1653,7 @@ static snd_pcm_uframes_t snd_korg1212_pl static snd_pcm_uframes_t snd_korg1212_capture_pointer(snd_pcm_substream_t *substream) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); snd_pcm_uframes_t pos; pos = korg1212->currentBuffer * kPlayBufferFrames; @@ -1674,7 +1672,7 @@ static int snd_korg1212_playback_copy(sn void __user *src, snd_pcm_uframes_t count) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); #if K1212_DEBUG_LEVEL > 2 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count); @@ -1689,7 +1687,7 @@ static int snd_korg1212_playback_silence snd_pcm_uframes_t pos, snd_pcm_uframes_t count) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", stateName[korg1212->cardState]); @@ -1704,7 +1702,7 @@ static int snd_korg1212_capture_copy(snd void __user *dst, snd_pcm_uframes_t count) { - korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); + korg1212_t *korg1212 = snd_pcm_substream_chip(substream); #if K1212_DEBUG_LEVEL > 2 K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count); @@ -1749,7 +1747,7 @@ static int snd_korg1212_control_phase_in static int snd_korg1212_control_phase_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int i = kcontrol->private_value; @@ -1767,7 +1765,7 @@ static int snd_korg1212_control_phase_ge static int snd_korg1212_control_phase_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change = 0; int i, val; @@ -1814,7 +1812,7 @@ static int snd_korg1212_control_volume_i static int snd_korg1212_control_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int i; @@ -1833,7 +1831,7 @@ static int snd_korg1212_control_volume_g static int snd_korg1212_control_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change = 0; int i; @@ -1878,7 +1876,7 @@ static int snd_korg1212_control_route_in static int snd_korg1212_control_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int i; @@ -1897,7 +1895,7 @@ static int snd_korg1212_control_route_ge static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change = 0, i; @@ -1933,7 +1931,7 @@ static int snd_korg1212_control_info(snd static int snd_korg1212_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); @@ -1948,7 +1946,7 @@ static int snd_korg1212_control_get(snd_ static int snd_korg1212_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change = 0; @@ -1985,7 +1983,7 @@ static int snd_korg1212_control_sync_inf static int snd_korg1212_control_sync_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); @@ -1998,7 +1996,7 @@ static int snd_korg1212_control_sync_get static int snd_korg1212_control_sync_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol); + korg1212_t *korg1212 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -2171,13 +2169,13 @@ snd_korg1212_free(korg1212_t *korg1212) korg1212->dma_shared.area = NULL; } - snd_magic_kfree(korg1212); + kfree(korg1212); return 0; } static int snd_korg1212_dev_free(snd_device_t *device) { - korg1212_t *korg1212 = snd_magic_cast(korg1212_t, device->device_data, return -ENXIO); + korg1212_t *korg1212 = device->device_data; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: Freeing device\n"); #endif @@ -2201,7 +2199,7 @@ static int __devinit snd_korg1212_create if ((err = pci_enable_device(pci)) < 0) return err; - korg1212 = snd_magic_kcalloc(korg1212_t, 0, GFP_KERNEL); + korg1212 = kcalloc(1, sizeof(*korg1212), GFP_KERNEL); if (korg1212 == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/maestro3.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/maestro3.c 2004-07-13 17:09:19.000000000 -0700 @@ -51,8 +51,7 @@ MODULE_AUTHOR("Zach Brown , Takashi Iwai "); MODULE_DESCRIPTION("ESS Maestro3 PCI"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{ESS,Maestro3 PCI}," +MODULE_SUPPORTED_DEVICE("{{ESS,Maestro3 PCI}," "{ESS,ES1988}," "{ESS,Allegro PCI}," "{ESS,Allegro-1 PCI}," @@ -67,19 +66,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable this soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(external_amp, bool, boot_devs, 0444); MODULE_PARM_DESC(external_amp, "Enable external amp for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(external_amp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); module_param_array(amp_gpio, int, boot_devs, 0444); MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); -MODULE_PARM_SYNTAX(amp_gpio, SNDRV_ENABLED); #define MAX_PLAYBACKS 2 #define MAX_CAPTURES 1 @@ -776,8 +770,6 @@ MODULE_PARM_SYNTAX(amp_gpio, SNDRV_ENABL typedef struct snd_m3_dma m3_dma_t; typedef struct snd_m3 m3_t; -#define chip_t m3_t - /* quirk lists */ struct m3_quirk { @@ -1573,7 +1565,7 @@ static void snd_m3_update_ptr(m3_t *chip static irqreturn_t snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - m3_t *chip = snd_magic_cast(m3_t, dev_id, ); + m3_t *chip = dev_id; u8 status; int i; @@ -1848,7 +1840,7 @@ static int snd_m3_ac97_wait(m3_t *chip) static unsigned short snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) { - m3_t *chip = snd_magic_cast(m3_t, ac97->private_data, return -ENXIO); + m3_t *chip = ac97->private_data; unsigned short ret = 0; unsigned long flags; @@ -1867,7 +1859,7 @@ __error: static void snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - m3_t *chip = snd_magic_cast(m3_t, ac97->private_data, return); + m3_t *chip = ac97->private_data; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -2402,7 +2394,7 @@ static int snd_m3_free(m3_t *chip) if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } @@ -2413,7 +2405,7 @@ static int snd_m3_free(m3_t *chip) #ifdef CONFIG_PM static int m3_suspend(snd_card_t *card, unsigned int state) { - m3_t *chip = snd_magic_cast(m3_t, card->pm_private_data, return -EINVAL); + m3_t *chip = card->pm_private_data; int i, index; if (chip->suspend_mem == NULL) @@ -2444,7 +2436,7 @@ static int m3_suspend(snd_card_t *card, static int m3_resume(snd_card_t *card, unsigned int state) { - m3_t *chip = snd_magic_cast(m3_t, card->pm_private_data, return -EINVAL); + m3_t *chip = card->pm_private_data; int i, index; if (chip->suspend_mem == NULL) @@ -2489,7 +2481,7 @@ static int m3_resume(snd_card_t *card, u static int snd_m3_dev_free(snd_device_t *device) { - m3_t *chip = snd_magic_cast(m3_t, device->device_data, return -ENXIO); + m3_t *chip = device->device_data; return snd_m3_free(chip); } @@ -2519,7 +2511,7 @@ snd_m3_create(snd_card_t *card, struct p return -ENXIO; } - chip = snd_magic_kcalloc(m3_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -2562,7 +2554,7 @@ snd_m3_create(snd_card_t *card, struct p chip->num_substreams = NR_DSPS; chip->substreams = kmalloc(sizeof(m3_dma_t) * chip->num_substreams, GFP_KERNEL); if (chip->substreams == NULL) { - snd_magic_kfree(chip); + kfree(chip); return -ENOMEM; } memset(chip->substreams, 0, sizeof(m3_dma_t) * chip->num_substreams); --- linux-2.6.8-rc1/sound/pci/mixart/mixart.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/mixart/mixart.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,25 +42,19 @@ MODULE_AUTHOR("Digigram "); MODULE_DESCRIPTION("Digigram " CARD_NAME); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); +MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int boot_devs; -#define chip_t mixart_t - module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); /* */ @@ -247,21 +241,27 @@ mixart_pipe_t* snd_mixart_add_ref_pipe( /* pipe is not yet defined */ if( pipe->status == PIPE_UNDEFINED ) { int err, i; - mixart_streaming_group_t streaming_group_resp; - mixart_streaming_group_req_t streaming_group_req; + struct { + mixart_streaming_group_req_t sgroup_req; + mixart_streaming_group_t sgroup_resp; + } *buf; snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number); + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + request.uid = (mixart_uid_t){0,0}; /* should be StreamManagerUID, but zero is OK if there is only one ! */ - request.data = &streaming_group_req; - request.size = sizeof(streaming_group_req); + request.data = &buf->sgroup_req; + request.size = sizeof(buf->sgroup_req); - memset(&streaming_group_req, 0, sizeof(streaming_group_req)); + memset(&buf->sgroup_req, 0, sizeof(buf->sgroup_req)); - streaming_group_req.stream_count = stream_count; - streaming_group_req.channel_count = 2; - streaming_group_req.latency = 256; - streaming_group_req.connector = pipe->uid_left_connector; /* the left connector */ + buf->sgroup_req.stream_count = stream_count; + buf->sgroup_req.channel_count = 2; + buf->sgroup_req.latency = 256; + buf->sgroup_req.connector = pipe->uid_left_connector; /* the left connector */ for (i=0; isgroup_req.stream_info[i].size_max_byte_frame = 1024; + buf->sgroup_req.stream_info[i].size_max_sample_frame = 256; + buf->sgroup_req.stream_info[i].nb_bytes_max_per_sample = MIXART_FLOAT_P__4_0_TO_HEX; /* is 4.0f */ /* find the right bufferinfo_array */ j = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i; if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */ - streaming_group_req.flow_entry[i] = j; + buf->sgroup_req.flow_entry[i] = j; flowinfo = (struct mixart_flowinfo *)chip->mgr->flowinfo.area; flowinfo[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo.addr + (j * sizeof(mixart_bufferinfo_t)); @@ -294,17 +294,19 @@ mixart_pipe_t* snd_mixart_add_ref_pipe( } } - err = snd_mixart_send_msg(chip->mgr, &request, sizeof(streaming_group_resp), &streaming_group_resp); - if((err < 0) || (streaming_group_resp.status != 0)) { - snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, streaming_group_resp.status); + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp); + if((err < 0) || (buf->sgroup_resp.status != 0)) { + snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status); + kfree(buf); return NULL; } - pipe->group_uid = streaming_group_resp.group; /* id of the pipe, as returned by embedded */ - pipe->stream_count = streaming_group_resp.stream_count; - /* pipe->stream_uid[i] = streaming_group_resp.stream[i].stream_uid; */ + pipe->group_uid = buf->sgroup_resp.group; /* id of the pipe, as returned by embedded */ + pipe->stream_count = buf->sgroup_resp.stream_count; + /* pipe->stream_uid[i] = buf->sgroup_resp.stream[i].stream_uid; */ pipe->status = PIPE_STOPPED; + kfree(buf); } if(monitoring) pipe->monitoring = 1; @@ -979,13 +981,13 @@ static int snd_mixart_pcm_digital(mixart static int snd_mixart_chip_free(mixart_t *chip) { - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_mixart_chip_dev_free(snd_device_t *device) { - mixart_t *chip = snd_magic_cast(mixart_t, device->device_data, return -ENXIO); + mixart_t *chip = device->device_data; return snd_mixart_chip_free(chip); } @@ -1000,7 +1002,7 @@ static int __devinit snd_mixart_create(m .dev_free = snd_mixart_chip_dev_free, }; - mgr->chip[idx] = chip = snd_magic_kcalloc(mixart_t, 0, GFP_KERNEL); + mgr->chip[idx] = chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1091,7 +1093,7 @@ static int snd_mixart_free(mixart_mgr_t mgr->bufferinfo.area = NULL; } - snd_magic_kfree(mgr); + kfree(mgr); return 0; } @@ -1156,7 +1158,7 @@ static long long snd_mixart_BA1_llseek(s static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data, struct file *file, char __user *buf, long count) { - mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); + mixart_mgr_t *mgr = entry->private_data; count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ if(count <= 0) @@ -1175,7 +1177,7 @@ static long snd_mixart_BA0_read(snd_info static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data, struct file *file, char __user *buf, long count) { - mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); + mixart_mgr_t *mgr = entry->private_data; count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ if(count <= 0) @@ -1202,7 +1204,7 @@ static struct snd_info_entry_ops snd_mix static void snd_mixart_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - mixart_t *chip = snd_magic_cast(mixart_t, entry->private_data, return); + mixart_t *chip = entry->private_data; u32 ref; snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx); @@ -1297,7 +1299,7 @@ static int __devinit snd_mixart_probe(st /* */ - mgr = snd_magic_kcalloc(mixart_mgr_t, 0, GFP_KERNEL); + mgr = kcalloc(1, sizeof(*mgr), GFP_KERNEL); if (! mgr) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/mixart/mixart_core.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/mixart/mixart_core.c 2004-07-13 17:09:19.000000000 -0700 @@ -403,7 +403,7 @@ void snd_mixart_msg_tasklet( unsigned lo irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, dev_id, return IRQ_NONE); + mixart_mgr_t *mgr = dev_id; int err; mixart_msg_t resp; --- linux-2.6.8-rc1/sound/pci/mixart/mixart_hwdep.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/mixart/mixart_hwdep.c 2004-07-13 17:09:19.000000000 -0700 @@ -146,7 +146,7 @@ static int mixart_load_elf(mixart_mgr_t static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info) { - mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO); + mixart_mgr_t *mgr = hw->private_data; strcpy(info->id, "miXart"); info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX; @@ -346,7 +346,7 @@ static int mixart_first_init(mixart_mgr_ static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) { - mixart_mgr_t* mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO); + mixart_mgr_t* mgr = hw->private_data; int err, card_index; u32 status_xilinx, status_elf, status_daught; u32 val; --- linux-2.6.8-rc1/sound/pci/mixart/mixart_mixer.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pci/mixart/mixart_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -31,8 +31,6 @@ #include #include "mixart_mixer.h" -#define chip_t mixart_t - static u32 mixart_analog_level[256] = { 0xc2c00000, /* [000] -96.0 dB */ 0xc2bf0000, /* [001] -95.5 dB */ --- linux-2.6.8-rc1/sound/pci/nm256/nm256.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/pci/nm256/nm256.c 2004-07-13 17:09:19.000000000 -0700 @@ -45,8 +45,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("NeoMagic NM256AV/ZX"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{NeoMagic,NM256AV}," +MODULE_SUPPORTED_DEVICE("{{NeoMagic,NM256AV}," "{NeoMagic,NM256ZX}}"); /* @@ -66,31 +65,22 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable this soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(playback_bufsize, int, boot_devs, 0444); MODULE_PARM_DESC(playback_bufsize, "DAC frame size in kB for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(playback_bufsize, SNDRV_ENABLED); module_param_array(capture_bufsize, int, boot_devs, 0444); MODULE_PARM_DESC(capture_bufsize, "ADC frame size in kB for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(capture_bufsize, SNDRV_ENABLED); module_param_array(force_ac97, bool, boot_devs, 0444); MODULE_PARM_DESC(force_ac97, "Force to use AC97 codec for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(force_ac97, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(buffer_top, int, boot_devs, 0444); MODULE_PARM_DESC(buffer_top, "Set the top address of audio buffer for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(buffer_top, SNDRV_ENABLED); module_param_array(use_cache, bool, boot_devs, 0444); MODULE_PARM_DESC(use_cache, "Enable the cache for coefficient table access."); -MODULE_PARM_SYNTAX(use_cache, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(vaio_hack, bool, boot_devs, 0444); MODULE_PARM_DESC(vaio_hack, "Enable workaround for Sony VAIO notebooks."); -MODULE_PARM_SYNTAX(vaio_hack, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); /* * hw definitions @@ -191,7 +181,6 @@ MODULE_PARM_SYNTAX(vaio_hack, SNDRV_ENAB typedef struct snd_nm256 nm256_t; typedef struct snd_nm256_stream nm256_stream_t; -#define chip_t nm256_t struct snd_nm256_stream { @@ -660,9 +649,9 @@ snd_nm256_capture_pointer(snd_pcm_substr return bytes_to_frames(substream->runtime, curp); } +/* Remapped I/O space can be accessible as pointer on i386 */ +/* This might be changed in the future */ #ifndef __i386__ -/* FIXME: I/O space is not accessible via pointers on all architectures */ - /* * silence / copy for playback */ @@ -757,10 +746,8 @@ snd_nm256_capture_update(nm256_t *chip) */ static snd_pcm_hardware_t snd_nm256_playback = { - .info = -#ifdef __i386__ - SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID| -#endif + .info = SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID| + SNDRV_PCM_INFO_MMAP_IOMEM| SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, @@ -779,10 +766,8 @@ static snd_pcm_hardware_t snd_nm256_play static snd_pcm_hardware_t snd_nm256_capture = { - .info = -#ifdef __i386__ - SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID| -#endif + .info = SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID| + SNDRV_PCM_INFO_MMAP_IOMEM| SNDRV_PCM_INFO_INTERLEAVED | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME, @@ -981,7 +966,7 @@ snd_nm256_intr_check(nm256_t *chip) static irqreturn_t snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy) { - nm256_t *chip = snd_magic_cast(nm256_t, dev_id, return IRQ_NONE); + nm256_t *chip = dev_id; u16 status; u8 cbyte; @@ -1048,7 +1033,7 @@ snd_nm256_interrupt(int irq, void *dev_i static irqreturn_t snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy) { - nm256_t *chip = snd_magic_cast(nm256_t, dev_id, return IRQ_NONE); + nm256_t *chip = dev_id; u32 status; u8 cbyte; @@ -1139,7 +1124,7 @@ snd_nm256_ac97_ready(nm256_t *chip) static unsigned short snd_nm256_ac97_read(ac97_t *ac97, unsigned short reg) { - nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return -ENXIO); + nm256_t *chip = ac97->private_data; int res; if (reg >= 128) @@ -1159,7 +1144,7 @@ static void snd_nm256_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { - nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return); + nm256_t *chip = ac97->private_data; int tries = 2; u32 base; @@ -1181,7 +1166,7 @@ snd_nm256_ac97_write(ac97_t *ac97, static void snd_nm256_ac97_reset(ac97_t *ac97) { - nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return); + nm256_t *chip = ac97->private_data; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -1206,7 +1191,7 @@ snd_nm256_mixer(nm256_t *chip) /* looks like nm256 hangs up when unexpected registers are touched... */ static int mixer_regs[] = { AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO, - AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, + AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD, AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL, AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL, AC97_EXTENDED_ID, @@ -1290,7 +1275,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) */ static int nm256_suspend(snd_card_t *card, unsigned int state) { - nm256_t *chip = snd_magic_cast(nm256_t, card->pm_private_data, return -EINVAL); + nm256_t *chip = card->pm_private_data; snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -1301,7 +1286,7 @@ static int nm256_suspend(snd_card_t *car static int nm256_resume(snd_card_t *card, unsigned int state) { - nm256_t *chip = snd_magic_cast(nm256_t, card->pm_private_data, return -EINVAL); + nm256_t *chip = card->pm_private_data; /* Perform a full reset on the hardware */ pci_enable_device(chip->pci); @@ -1340,13 +1325,13 @@ static int snd_nm256_free(nm256_t *chip) if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_nm256_dev_free(snd_device_t *device) { - nm256_t *chip = snd_magic_cast(nm256_t, device->device_data, return -ENXIO); + nm256_t *chip = device->device_data; return snd_nm256_free(chip); } @@ -1368,7 +1353,7 @@ snd_nm256_create(snd_card_t *card, struc *chip_ret = NULL; - chip = snd_magic_kcalloc(nm256_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/pci/rme32.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/rme32.c 2004-07-13 17:09:19.000000000 -0700 @@ -52,6 +52,19 @@ * patch would be welcome! * * **************************************************************************** + * + * "The story after the long seeking" -- tiwai + * + * Ok, the situation regarding the full duplex is now improved a bit. + * In the fullduplex mode (given by the module parameter), the hardware buffer + * is split to halves for read and write directions at the DMA pointer. + * That is, the half above the current DMA pointer is used for write, and + * the half below is used for read. To mangle this strange behavior, an + * software intermediate buffer is introduced. This is, of course, not good + * from the viewpoint of the data transfer efficiency. However, this allows + * you to use arbitrary buffer sizes, instead of the fixed I/O buffer size. + * + * **************************************************************************** */ @@ -68,6 +81,7 @@ #include #include #include +#include #include #include @@ -76,22 +90,21 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int fullduplex[SNDRV_CARDS]; // = {[0 ... (SNDRV_CARDS - 1)] = 1}; static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for RME Digi32 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for RME Digi32 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable RME Digi32 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +module_param_array(fullduplex, bool, boot_devs, 0444); +MODULE_PARM_DESC(fullduplex, "Support full-duplex mode."); MODULE_AUTHOR("Martin Langer "); MODULE_DESCRIPTION("RME Digi32, Digi32/8, Digi32 PRO"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); +MODULE_SUPPORTED_DEVICE("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); /* Defines for RME Digi32 series */ #define RME32_SPDIF_NCHANNELS 2 @@ -168,6 +181,9 @@ MODULE_DEVICES("{{RME,Digi32}," "{RME,Di /* Block sizes in bytes */ #define RME32_BLOCK_SIZE 8192 +/* Software intermediate buffer (max) size */ +#define RME32_MID_BUFFER_SIZE (1024*1024) + /* Hardware revisions */ #define RME32_32_REVISION 192 #define RME32_328_REVISION_OLD 100 @@ -213,9 +229,11 @@ typedef struct snd_rme32 { size_t playback_periodsize; /* in bytes, zero if not used */ size_t capture_periodsize; /* in bytes, zero if not used */ - snd_pcm_uframes_t playback_last_appl_ptr; - size_t playback_ptr; - size_t capture_ptr; + unsigned int fullduplex_mode; + int running; + + snd_pcm_indirect_t playback_pcm; + snd_pcm_indirect_t capture_pcm; snd_card_t *card; snd_pcm_t *spdif_pcm; @@ -243,33 +261,16 @@ static int snd_rme32_playback_prepare(sn static int snd_rme32_capture_prepare(snd_pcm_substream_t * substream); -static int -snd_rme32_playback_trigger(snd_pcm_substream_t * substream, int cmd); - -static int -snd_rme32_capture_trigger(snd_pcm_substream_t * substream, int cmd); - -static snd_pcm_uframes_t -snd_rme32_playback_pointer(snd_pcm_substream_t * substream); - -static snd_pcm_uframes_t -snd_rme32_capture_pointer(snd_pcm_substream_t * substream); +static int snd_rme32_pcm_trigger(snd_pcm_substream_t * substream, int cmd); static void snd_rme32_proc_init(rme32_t * rme32); static int snd_rme32_create_switches(snd_card_t * card, rme32_t * rme32); -static inline unsigned int snd_rme32_playback_ptr(rme32_t * rme32) +static inline unsigned int snd_rme32_pcm_byteptr(rme32_t * rme32) { - return (readl(rme32->iobase + RME32_IO_GET_POS) - & RME32_RCR_AUDIO_ADDR_MASK) >> rme32->playback_frlog; -} - -static inline unsigned int snd_rme32_capture_ptr(rme32_t * rme32) -{ - return (readl(rme32->iobase + RME32_IO_GET_POS) - & RME32_RCR_AUDIO_ADDR_MASK) >> rme32->capture_frlog; + & RME32_RCR_AUDIO_ADDR_MASK); } static int snd_rme32_ratecode(int rate) @@ -285,22 +286,24 @@ static int snd_rme32_ratecode(int rate) return 0; } +/* silence callback for halfduplex mode */ static int snd_rme32_playback_silence(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, snd_pcm_uframes_t count) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->playback_frlog; pos <<= rme32->playback_frlog; memset_io(rme32->iobase + RME32_IO_DATA_BUFFER + pos, 0, count); return 0; } +/* copy callback for halfduplex mode */ static int snd_rme32_playback_copy(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->playback_frlog; pos <<= rme32->playback_frlog; if (copy_from_user_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos, @@ -309,11 +312,12 @@ static int snd_rme32_playback_copy(snd_p return 0; } +/* copy callback for halfduplex mode */ static int snd_rme32_capture_copy(snd_pcm_substream_t * substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); count <<= rme32->capture_frlog; pos <<= rme32->capture_frlog; if (copy_to_user_fromio(dst, @@ -324,13 +328,15 @@ static int snd_rme32_capture_copy(snd_pc } /* - * Digital output capabilites (S/PDIF) + * SPDIF I/O capabilites (half-duplex mode) */ -static snd_pcm_hardware_t snd_rme32_playback_spdif_info = { +static snd_pcm_hardware_t snd_rme32_spdif_info = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -349,13 +355,40 @@ static snd_pcm_hardware_t snd_rme32_play }; /* - * Digital input capabilites (S/PDIF) + * ADAT I/O capabilites (half-duplex mode) + */ +static snd_pcm_hardware_t snd_rme32_adat_info = +{ + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), + .formats= SNDRV_PCM_FMTBIT_S16_LE, + .rates = (SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000), + .rate_min = 44100, + .rate_max = 48000, + .channels_min = 8, + .channels_max = 8, + .buffer_bytes_max = RME32_BUFFER_SIZE, + .period_bytes_min = RME32_BLOCK_SIZE, + .period_bytes_max = RME32_BLOCK_SIZE, + .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, + .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, + .fifo_size = 0, +}; + +/* + * SPDIF I/O capabilites (full-duplex mode) */ -static snd_pcm_hardware_t snd_rme32_capture_spdif_info = { +static snd_pcm_hardware_t snd_rme32_spdif_fd_info = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = (SNDRV_PCM_RATE_32000 | @@ -365,23 +398,24 @@ static snd_pcm_hardware_t snd_rme32_capt .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = RME32_BUFFER_SIZE, + .buffer_bytes_max = RME32_MID_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, - .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, - .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, + .periods_min = 2, + .periods_max = RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0, }; /* - * Digital output capabilites (ADAT) + * ADAT I/O capabilites (full-duplex mode) */ -static snd_pcm_hardware_t snd_rme32_playback_adat_info = +static snd_pcm_hardware_t snd_rme32_adat_fd_info = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE), + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START), .formats= SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000), @@ -389,38 +423,14 @@ static snd_pcm_hardware_t snd_rme32_play .rate_max = 48000, .channels_min = 8, .channels_max = 8, - .buffer_bytes_max = RME32_BUFFER_SIZE, + .buffer_bytes_max = RME32_MID_BUFFER_SIZE, .period_bytes_min = RME32_BLOCK_SIZE, .period_bytes_max = RME32_BLOCK_SIZE, - .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, - .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, + .periods_min = 2, + .periods_max = RME32_MID_BUFFER_SIZE / RME32_BLOCK_SIZE, .fifo_size = 0, }; -/* - * Digital input capabilites (ADAT) - */ -static snd_pcm_hardware_t snd_rme32_capture_adat_info = -{ - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = (SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000), - .rate_min = 44100, - .rate_max = 48000, - .channels_min = 8, - .channels_max = 8, - .buffer_bytes_max = RME32_BUFFER_SIZE, - .period_bytes_min = RME32_BLOCK_SIZE, - .period_bytes_max = RME32_BLOCK_SIZE, - .periods_min = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, - .periods_max = RME32_BUFFER_SIZE / RME32_BLOCK_SIZE, - .fifo_size = 0, -}; - static void snd_rme32_reset_dac(rme32_t *rme32) { writel(rme32->wcreg | RME32_WCR_PD, @@ -677,11 +687,19 @@ snd_rme32_playback_hw_params(snd_pcm_sub snd_pcm_hw_params_t * params) { int err, rate, dummy; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + if (rme32->fullduplex_mode) { + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (err < 0) + return err; + } else { + runtime->dma_area = (void *)(rme32->iobase + RME32_IO_DATA_BUFFER); + runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; + runtime->dma_bytes = RME32_BUFFER_SIZE; + } - if ((err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(params))) < 0) - return err; spin_lock_irq(&rme32->lock); if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { @@ -719,24 +737,25 @@ snd_rme32_playback_hw_params(snd_pcm_sub return 0; } -static int snd_rme32_playback_hw_free(snd_pcm_substream_t * substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - static int snd_rme32_capture_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * params) { unsigned long flags; int err, isadat, rate; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - if ((err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(params))) < 0) - return err; + if (rme32->fullduplex_mode) { + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (err < 0) + return err; + } else { + runtime->dma_area = (void *)rme32->iobase + RME32_IO_DATA_BUFFER; + runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; + runtime->dma_bytes = RME32_BUFFER_SIZE; + } + spin_lock_irqsave(&rme32->lock, flags); /* enable AutoSync for record-preparing */ rme32->wcreg |= RME32_WCR_AUTOSYNC; @@ -780,25 +799,15 @@ snd_rme32_capture_hw_params(snd_pcm_subs return 0; } -static int snd_rme32_capture_hw_free(snd_pcm_substream_t * substream) +static int snd_rme32_pcm_hw_free(snd_pcm_substream_t * substream) { - snd_pcm_lib_free_pages(substream); - return 0; -} - -static void snd_rme32_playback_start(rme32_t * rme32, int from_pause) -{ - if (!from_pause) { - writel(0, rme32->iobase + RME32_IO_RESET_POS); - rme32->playback_last_appl_ptr = 0; - rme32->playback_ptr = 0; - } - - rme32->wcreg |= RME32_WCR_START; - writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); + rme32_t *rme32 = snd_pcm_substream_chip(substream); + if (! rme32->fullduplex_mode) + return 0; + return snd_pcm_lib_free_pages(substream); } -static void snd_rme32_capture_start(rme32_t * rme32, int from_pause) +static void snd_rme32_pcm_start(rme32_t * rme32, int from_pause) { if (!from_pause) { writel(0, rme32->iobase + RME32_IO_RESET_POS); @@ -808,7 +817,7 @@ static void snd_rme32_capture_start(rme3 writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); } -static void snd_rme32_playback_stop(rme32_t * rme32) +static void snd_rme32_pcm_stop(rme32_t * rme32, int to_pause) { /* * Check if there is an unconfirmed IRQ, if so confirm it, or else @@ -822,16 +831,8 @@ static void snd_rme32_playback_stop(rme3 if (rme32->wcreg & RME32_WCR_SEL) rme32->wcreg |= RME32_WCR_MUTE; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); -} - -static void snd_rme32_capture_stop(rme32_t * rme32) -{ - rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER); - if (rme32->rcreg & RME32_RCR_IRQ) { - writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ); - } - rme32->wcreg &= ~RME32_WCR_START; - writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); + if (! to_pause) + writel(0, rme32->iobase + RME32_IO_RESET_POS); } static irqreturn_t @@ -865,11 +866,23 @@ static snd_pcm_hw_constraint_list_t hw_c .mask = 0 }; +static void snd_rme32_set_buffer_constraint(rme32_t *rme32, snd_pcm_runtime_t *runtime) +{ + if (! rme32->fullduplex_mode) { + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + &hw_constraints_period_bytes); + } +} + static int snd_rme32_playback_spdif_open(snd_pcm_substream_t * substream) { unsigned long flags; int rate, dummy; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -882,11 +895,12 @@ static int snd_rme32_playback_spdif_open rme32->wcreg &= ~RME32_WCR_ADAT; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); rme32->playback_substream = substream; - rme32->playback_last_appl_ptr = 0; - rme32->playback_ptr = 0; spin_unlock_irqrestore(&rme32->lock, flags); - runtime->hw = snd_rme32_playback_spdif_info; + if (rme32->fullduplex_mode) + runtime->hw = snd_rme32_spdif_fd_info; + else + runtime->hw = snd_rme32_spdif_info; if (rme32->pci->device == PCI_DEVICE_ID_DIGI32_PRO) { runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; @@ -898,12 +912,8 @@ static int snd_rme32_playback_spdif_open runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - &hw_constraints_period_bytes); + + snd_rme32_set_buffer_constraint(rme32, runtime); rme32->wcreg_spdif_stream = rme32->wcreg_spdif; rme32->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; @@ -916,7 +926,7 @@ static int snd_rme32_capture_spdif_open( { unsigned long flags; int isadat, rate; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -927,10 +937,12 @@ static int snd_rme32_capture_spdif_open( return -EBUSY; } rme32->capture_substream = substream; - rme32->capture_ptr = 0; spin_unlock_irqrestore(&rme32->lock, flags); - runtime->hw = snd_rme32_capture_spdif_info; + if (rme32->fullduplex_mode) + runtime->hw = snd_rme32_spdif_fd_info; + else + runtime->hw = snd_rme32_spdif_info; if (RME32_PRO_WITH_8414(rme32)) { runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; @@ -944,12 +956,7 @@ static int snd_rme32_capture_spdif_open( runtime->hw.rate_max = rate; } - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - &hw_constraints_period_bytes); + snd_rme32_set_buffer_constraint(rme32, runtime); return 0; } @@ -959,7 +966,7 @@ snd_rme32_playback_adat_open(snd_pcm_sub { unsigned long flags; int rate, dummy; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -972,11 +979,12 @@ snd_rme32_playback_adat_open(snd_pcm_sub rme32->wcreg |= RME32_WCR_ADAT; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); rme32->playback_substream = substream; - rme32->playback_last_appl_ptr = 0; - rme32->playback_ptr = 0; spin_unlock_irqrestore(&rme32->lock, flags); - runtime->hw = snd_rme32_playback_adat_info; + if (rme32->fullduplex_mode) + runtime->hw = snd_rme32_adat_fd_info; + else + runtime->hw = snd_rme32_adat_info; if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ @@ -984,10 +992,8 @@ snd_rme32_playback_adat_open(snd_pcm_sub runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - &hw_constraints_period_bytes); + + snd_rme32_set_buffer_constraint(rme32, runtime); return 0; } @@ -996,10 +1002,13 @@ snd_rme32_capture_adat_open(snd_pcm_subs { unsigned long flags; int isadat, rate; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - runtime->hw = snd_rme32_capture_adat_info; + if (rme32->fullduplex_mode) + runtime->hw = snd_rme32_adat_fd_info; + else + runtime->hw = snd_rme32_adat_info; if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) { if (!isadat) { return -EIO; @@ -1017,20 +1026,16 @@ snd_rme32_capture_adat_open(snd_pcm_subs return -EBUSY; } rme32->capture_substream = substream; - rme32->capture_ptr = 0; spin_unlock_irqrestore(&rme32->lock, flags); - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - &hw_constraints_period_bytes); + snd_rme32_set_buffer_constraint(rme32, runtime); return 0; } static int snd_rme32_playback_close(snd_pcm_substream_t * substream) { unsigned long flags; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); int spdif = 0; spin_lock_irqsave(&rme32->lock, flags); @@ -1050,7 +1055,7 @@ static int snd_rme32_playback_close(snd_ static int snd_rme32_capture_close(snd_pcm_substream_t * substream) { unsigned long flags; - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); spin_lock_irqsave(&rme32->lock, flags); rme32->capture_substream = NULL; @@ -1061,195 +1066,171 @@ static int snd_rme32_capture_close(snd_p static int snd_rme32_playback_prepare(snd_pcm_substream_t * substream) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); - unsigned long flags; + rme32_t *rme32 = snd_pcm_substream_chip(substream); - spin_lock_irqsave(&rme32->lock, flags); - if (RME32_ISWORKING(rme32)) { - snd_rme32_playback_stop(rme32); + spin_lock(&rme32->lock); + if (rme32->fullduplex_mode) { + memset(&rme32->playback_pcm, 0, sizeof(rme32->playback_pcm)); + rme32->playback_pcm.hw_buffer_size = RME32_BUFFER_SIZE; + rme32->playback_pcm.hw_queue_size = RME32_BUFFER_SIZE / 2; + rme32->playback_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + } else { + writel(0, rme32->iobase + RME32_IO_RESET_POS); } - writel(0, rme32->iobase + RME32_IO_RESET_POS); if (rme32->wcreg & RME32_WCR_SEL) rme32->wcreg &= ~RME32_WCR_MUTE; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); - spin_unlock_irqrestore(&rme32->lock, flags); + spin_unlock(&rme32->lock); return 0; } static int snd_rme32_capture_prepare(snd_pcm_substream_t * substream) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); - unsigned long flags; + rme32_t *rme32 = snd_pcm_substream_chip(substream); - spin_lock_irqsave(&rme32->lock, flags); - if (RME32_ISWORKING(rme32)) { - snd_rme32_capture_stop(rme32); + spin_lock(&rme32->lock); + if (rme32->fullduplex_mode) { + memset(&rme32->capture_pcm, 0, sizeof(rme32->capture_pcm)); + rme32->capture_pcm.hw_buffer_size = RME32_BUFFER_SIZE; + rme32->capture_pcm.hw_queue_size = RME32_BUFFER_SIZE / 2; + rme32->capture_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); + } else { + writel(0, rme32->iobase + RME32_IO_RESET_POS); } - writel(0, rme32->iobase + RME32_IO_RESET_POS); - spin_unlock_irqrestore(&rme32->lock, flags); + spin_unlock(&rme32->lock); return 0; } static int -snd_rme32_playback_trigger(snd_pcm_substream_t * substream, int cmd) +snd_rme32_pcm_trigger(snd_pcm_substream_t * substream, int cmd) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (!RME32_ISWORKING(rme32)) { - if (substream != rme32->playback_substream) { - return -EBUSY; + rme32_t *rme32 = snd_pcm_substream_chip(substream); + struct list_head *pos; + snd_pcm_substream_t *s; + + spin_lock(&rme32->lock); + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s != rme32->playback_substream && + s != rme32->capture_substream) + continue; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + rme32->running |= (1 << s->stream); + if (rme32->fullduplex_mode) { + /* remember the current DMA position */ + if (s == rme32->playback_substream) { + rme32->playback_pcm.hw_data = snd_rme32_pcm_byteptr(rme32); + s->ops->ack(s); /* prefill buffer */ + } else { + rme32->capture_pcm.hw_data = snd_rme32_pcm_byteptr(rme32); + } } - snd_rme32_playback_start(rme32, 0); + break; + case SNDRV_PCM_TRIGGER_STOP: + rme32->running &= ~(1 << s->stream); + break; } + snd_pcm_trigger_done(s, substream); + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (rme32->running && ! RME32_ISWORKING(rme32)) + snd_rme32_pcm_start(rme32, 0); break; - case SNDRV_PCM_TRIGGER_STOP: - if (RME32_ISWORKING(rme32)) { - if (substream != rme32->playback_substream) { - return -EBUSY; - } - snd_rme32_playback_stop(rme32); - } + if (! rme32->running && RME32_ISWORKING(rme32)) + snd_rme32_pcm_stop(rme32, 0); break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (RME32_ISWORKING(rme32)) { - snd_rme32_playback_stop(rme32); - } + if (rme32->running && RME32_ISWORKING(rme32)) + snd_rme32_pcm_stop(rme32, 1); break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!RME32_ISWORKING(rme32)) { - snd_rme32_playback_start(rme32, 1); - } + if (rme32->running && ! RME32_ISWORKING(rme32)) + snd_rme32_pcm_start(rme32, 1); break; - - default: - return -EINVAL; } + spin_unlock(&rme32->lock); return 0; } -static int -snd_rme32_capture_trigger(snd_pcm_substream_t * substream, int cmd) +/* pointer callback for halfduplex mode */ +static snd_pcm_uframes_t +snd_rme32_playback_pointer(snd_pcm_substream_t * substream) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); + rme32_t *rme32 = snd_pcm_substream_chip(substream); + return snd_rme32_pcm_byteptr(rme32) >> rme32->playback_frlog; +} - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (!RME32_ISWORKING(rme32)) { - if (substream != rme32->capture_substream) { - return -EBUSY; - } - snd_rme32_capture_start(rme32, 0); - } - break; +static snd_pcm_uframes_t +snd_rme32_capture_pointer(snd_pcm_substream_t * substream) +{ + rme32_t *rme32 = snd_pcm_substream_chip(substream); + return snd_rme32_pcm_byteptr(rme32) >> rme32->capture_frlog; +} - case SNDRV_PCM_TRIGGER_STOP: - if (RME32_ISWORKING(rme32)) { - if (substream != rme32->capture_substream) { - return -EBUSY; - } - snd_rme32_capture_stop(rme32); - } - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (RME32_ISWORKING(rme32)) { - snd_rme32_capture_stop(rme32); - } - break; +/* ack and pointer callbacks for fullduplex mode */ +static void snd_rme32_pb_trans_copy(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes) +{ + rme32_t *rme32 = snd_pcm_substream_chip(substream); + memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data, + substream->runtime->dma_area + rec->sw_data, bytes); +} - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!RME32_ISWORKING(rme32)) { - snd_rme32_capture_start(rme32, 1); - } - break; +static int snd_rme32_playback_fd_ack(snd_pcm_substream_t *substream) +{ + rme32_t *rme32 = snd_pcm_substream_chip(substream); + snd_pcm_indirect_playback_transfer(substream, &rme32->playback_pcm, + snd_rme32_pb_trans_copy); + return 0; +} - default: - return -EINVAL; - } +static void snd_rme32_cp_trans_copy(snd_pcm_substream_t *substream, + snd_pcm_indirect_t *rec, size_t bytes) +{ + rme32_t *rme32 = snd_pcm_substream_chip(substream); + memcpy_fromio(substream->runtime->dma_area + rec->sw_data, + rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data, + bytes); +} +static int snd_rme32_capture_fd_ack(snd_pcm_substream_t *substream) +{ + rme32_t *rme32 = snd_pcm_substream_chip(substream); + snd_pcm_indirect_capture_transfer(substream, &rme32->capture_pcm, + snd_rme32_cp_trans_copy); return 0; } static snd_pcm_uframes_t -snd_rme32_playback_pointer(snd_pcm_substream_t * substream) +snd_rme32_playback_fd_pointer(snd_pcm_substream_t * substream) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_sframes_t diff; - size_t bytes; - - - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - diff = runtime->control->appl_ptr - - rme32->playback_last_appl_ptr; - rme32->playback_last_appl_ptr = runtime->control->appl_ptr; - if (diff != 0 && diff < -(snd_pcm_sframes_t) (runtime->boundary >> 1)) { - diff += runtime->boundary; - } - bytes = diff << rme32->playback_frlog; - if (bytes > RME32_BUFFER_SIZE - rme32->playback_ptr) { - memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), - runtime->dma_area + rme32->playback_ptr, - RME32_BUFFER_SIZE - rme32->playback_ptr); - bytes -= RME32_BUFFER_SIZE - rme32->playback_ptr; - if (bytes > RME32_BUFFER_SIZE) { - bytes = RME32_BUFFER_SIZE; - } - memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER), - runtime->dma_area, bytes); - rme32->playback_ptr = bytes; - } else if (bytes != 0) { - memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), - runtime->dma_area + rme32->playback_ptr, bytes); - rme32->playback_ptr += bytes; - } - } - return snd_rme32_playback_ptr(rme32); + rme32_t *rme32 = snd_pcm_substream_chip(substream); + return snd_pcm_indirect_playback_pointer(substream, &rme32->playback_pcm, + snd_rme32_pcm_byteptr(rme32)); } static snd_pcm_uframes_t -snd_rme32_capture_pointer(snd_pcm_substream_t * substream) +snd_rme32_capture_fd_pointer(snd_pcm_substream_t * substream) { - rme32_t *rme32 = _snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t frameptr; - size_t ptr; - - frameptr = snd_rme32_capture_ptr(rme32); - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - ptr = frameptr << rme32->capture_frlog; - if (ptr > rme32->capture_ptr) { - memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr), - ptr - rme32->capture_ptr); - rme32->capture_ptr += ptr - rme32->capture_ptr; - } else if (ptr < rme32->capture_ptr) { - memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr), - RME32_BUFFER_SIZE - rme32->capture_ptr); - memcpy_fromio(runtime->dma_area, - (void *)(rme32->iobase + RME32_IO_DATA_BUFFER), - ptr); - rme32->capture_ptr = ptr; - } - } - return frameptr; + rme32_t *rme32 = snd_pcm_substream_chip(substream); + return snd_pcm_indirect_capture_pointer(substream, &rme32->capture_pcm, + snd_rme32_pcm_byteptr(rme32)); } +/* for halfduplex mode */ static snd_pcm_ops_t snd_rme32_playback_spdif_ops = { .open = snd_rme32_playback_spdif_open, .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, - .hw_free = snd_rme32_playback_hw_free, + .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_playback_prepare, - .trigger = snd_rme32_playback_trigger, + .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, .copy = snd_rme32_playback_copy, .silence = snd_rme32_playback_silence, @@ -1260,9 +1241,9 @@ static snd_pcm_ops_t snd_rme32_capture_s .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, - .hw_free = snd_rme32_capture_hw_free, + .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_capture_prepare, - .trigger = snd_rme32_capture_trigger, + .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, .copy = snd_rme32_capture_copy, }; @@ -1272,9 +1253,8 @@ static snd_pcm_ops_t snd_rme32_playback_ .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, - .hw_free = snd_rme32_playback_hw_free, .prepare = snd_rme32_playback_prepare, - .trigger = snd_rme32_playback_trigger, + .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, .copy = snd_rme32_playback_copy, .silence = snd_rme32_playback_silence, @@ -1285,13 +1265,59 @@ static snd_pcm_ops_t snd_rme32_capture_a .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, - .hw_free = snd_rme32_capture_hw_free, .prepare = snd_rme32_capture_prepare, - .trigger = snd_rme32_capture_trigger, + .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, .copy = snd_rme32_capture_copy, }; +/* for fullduplex mode */ +static snd_pcm_ops_t snd_rme32_playback_spdif_fd_ops = { + .open = snd_rme32_playback_spdif_open, + .close = snd_rme32_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_rme32_playback_hw_params, + .hw_free = snd_rme32_pcm_hw_free, + .prepare = snd_rme32_playback_prepare, + .trigger = snd_rme32_pcm_trigger, + .pointer = snd_rme32_playback_fd_pointer, + .ack = snd_rme32_playback_fd_ack, +}; + +static snd_pcm_ops_t snd_rme32_capture_spdif_fd_ops = { + .open = snd_rme32_capture_spdif_open, + .close = snd_rme32_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_rme32_capture_hw_params, + .hw_free = snd_rme32_pcm_hw_free, + .prepare = snd_rme32_capture_prepare, + .trigger = snd_rme32_pcm_trigger, + .pointer = snd_rme32_capture_fd_pointer, + .ack = snd_rme32_capture_fd_ack, +}; + +static snd_pcm_ops_t snd_rme32_playback_adat_fd_ops = { + .open = snd_rme32_playback_adat_open, + .close = snd_rme32_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_rme32_playback_hw_params, + .prepare = snd_rme32_playback_prepare, + .trigger = snd_rme32_pcm_trigger, + .pointer = snd_rme32_playback_fd_pointer, + .ack = snd_rme32_playback_fd_ack, +}; + +static snd_pcm_ops_t snd_rme32_capture_adat_fd_ops = { + .open = snd_rme32_capture_adat_open, + .close = snd_rme32_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_rme32_capture_hw_params, + .prepare = snd_rme32_capture_prepare, + .trigger = snd_rme32_pcm_trigger, + .pointer = snd_rme32_capture_fd_pointer, + .ack = snd_rme32_capture_fd_ack, +}; + static void snd_rme32_free(void *private_data) { rme32_t *rme32 = (rme32_t *) private_data; @@ -1300,8 +1326,7 @@ static void snd_rme32_free(void *private return; } if (rme32->irq >= 0) { - snd_rme32_playback_stop(rme32); - snd_rme32_capture_stop(rme32); + snd_rme32_pcm_stop(rme32, 0); free_irq(rme32->irq, (void *) rme32); rme32->irq = -1; } @@ -1319,7 +1344,6 @@ static void snd_rme32_free_spdif_pcm(snd { rme32_t *rme32 = (rme32_t *) pcm->private_data; rme32->spdif_pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); } static void @@ -1327,7 +1351,6 @@ snd_rme32_free_adat_pcm(snd_pcm_t *pcm) { rme32_t *rme32 = (rme32_t *) pcm->private_data; rme32->adat_pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); } static int __devinit snd_rme32_create(rme32_t * rme32) @@ -1371,18 +1394,22 @@ static int __devinit snd_rme32_create(rm rme32->spdif_pcm->private_data = rme32; rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm; strcpy(rme32->spdif_pcm->name, "Digi32 IEC958"); - snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_rme32_playback_spdif_ops); - snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_rme32_capture_spdif_ops); - - rme32->spdif_pcm->info_flags = 0; - - snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - RME32_BUFFER_SIZE, - RME32_BUFFER_SIZE); + if (rme32->fullduplex_mode) { + snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_rme32_playback_spdif_fd_ops); + snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_rme32_capture_spdif_fd_ops); + snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, RME32_MID_BUFFER_SIZE); + rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + } else { + snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_rme32_playback_spdif_ops); + snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_rme32_capture_spdif_ops); + rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; + } /* set up ALSA pcm device for ADAT */ if ((pci->device == PCI_DEVICE_ID_DIGI32) || @@ -1399,18 +1426,22 @@ static int __devinit snd_rme32_create(rm rme32->adat_pcm->private_data = rme32; rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm; strcpy(rme32->adat_pcm->name, "Digi32 ADAT"); - snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_rme32_playback_adat_ops); - snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_rme32_capture_adat_ops); - - rme32->adat_pcm->info_flags = 0; - - snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - RME32_BUFFER_SIZE, - RME32_BUFFER_SIZE); + if (rme32->fullduplex_mode) { + snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_rme32_playback_adat_fd_ops); + snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_rme32_capture_adat_fd_ops); + snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, RME32_MID_BUFFER_SIZE); + rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; + } else { + snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_rme32_playback_adat_ops); + snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_rme32_capture_adat_ops); + rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; + } } @@ -1418,8 +1449,7 @@ static int __devinit snd_rme32_create(rm rme32->capture_periodsize = 0; /* make sure playback/capture is stopped, if by some reason active */ - snd_rme32_playback_stop(rme32); - snd_rme32_capture_stop(rme32); + snd_rme32_pcm_stop(rme32, 0); /* reset DAC */ snd_rme32_reset_dac(rme32); @@ -1464,6 +1494,10 @@ snd_rme32_proc_read(snd_info_entry_t * e snd_iprintf(buffer, " (index #%d)\n", rme32->card->number + 1); snd_iprintf(buffer, "\nGeneral settings\n"); + if (rme32->fullduplex_mode) + snd_iprintf(buffer, " Full-duplex mode\n"); + else + snd_iprintf(buffer, " Half-duplex mode\n"); if (RME32_PRO_WITH_8414(rme32)) { snd_iprintf(buffer, " receiver: CS8414\n"); } else { @@ -1569,7 +1603,7 @@ static int snd_rme32_get_loopback_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme32->lock, flags); @@ -1582,7 +1616,7 @@ static int snd_rme32_put_loopback_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -1605,7 +1639,7 @@ static int snd_rme32_info_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -1635,7 +1669,7 @@ static int snd_rme32_get_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int items = 3; @@ -1665,7 +1699,7 @@ static int snd_rme32_put_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change, items = 3; @@ -1714,7 +1748,7 @@ static int snd_rme32_get_clockmode_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme32->lock, flags); @@ -1726,7 +1760,7 @@ static int snd_rme32_put_clockmode_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -1770,7 +1804,7 @@ static int snd_rme32_control_spdif_info( static int snd_rme32_control_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); snd_rme32_convert_to_aes(&ucontrol->value.iec958, rme32->wcreg_spdif); @@ -1780,7 +1814,7 @@ static int snd_rme32_control_spdif_get(s static int snd_rme32_control_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -1805,7 +1839,7 @@ static int snd_rme32_control_spdif_strea snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); snd_rme32_convert_to_aes(&ucontrol->value.iec958, rme32->wcreg_spdif_stream); @@ -1816,7 +1850,7 @@ static int snd_rme32_control_spdif_strea snd_ctl_elem_value_t * ucontrol) { - rme32_t *rme32 = _snd_kcontrol_chip(kcontrol); + rme32_t *rme32 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -1907,7 +1941,7 @@ static int snd_rme32_create_switches(snd int idx, err; snd_kcontrol_t *kctl; - for (idx = 0; idx < 7; idx++) { + for (idx = 0; idx < (int)ARRAY_SIZE(snd_rme32_controls); idx++) { if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme32_controls[idx], rme32))) < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ @@ -1952,6 +1986,8 @@ snd_rme32_probe(struct pci_dev *pci, con rme32->card = card; rme32->pci = pci; snd_card_set_dev(card, &pci->dev); + if (fullduplex[dev]) + rme32->fullduplex_mode = 1; if ((err = snd_rme32_create(rme32)) < 0) { snd_card_free(card); return err; --- linux-2.6.8-rc1/sound/pci/rme9652/hdsp.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/rme9652/hdsp.c 2004-07-13 17:09:19.000000000 -0700 @@ -52,24 +52,18 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for RME Hammerfall DSP interface."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable/disable specific Hammerfall DSP soundcards."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(precise_ptr, bool, boot_devs, 0444); MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably)."); -MODULE_PARM_SYNTAX(precise_ptr, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(line_outs_monitor, bool, boot_devs, 0444); MODULE_PARM_DESC(line_outs_monitor, "Send all input and playback streams to line outs by default."); -MODULE_PARM_SYNTAX(line_outs_monitor, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); MODULE_AUTHOR("Paul Davis , Marcus Andersson, Thomas Charbonnel "); MODULE_DESCRIPTION("RME Hammerfall DSP"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{RME Hammerfall-DSP}," +MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," "{RME HDSP-9652}," "{RME HDSP-9632}}"); @@ -1563,7 +1557,7 @@ static int snd_hdsp_control_spdif_info(s static int snd_hdsp_control_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif); return 0; @@ -1571,7 +1565,7 @@ static int snd_hdsp_control_spdif_get(sn static int snd_hdsp_control_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -1593,7 +1587,7 @@ static int snd_hdsp_control_spdif_stream static int snd_hdsp_control_spdif_stream_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); snd_hdsp_convert_to_aes(&ucontrol->value.iec958, hdsp->creg_spdif_stream); return 0; @@ -1601,7 +1595,7 @@ static int snd_hdsp_control_spdif_stream static int snd_hdsp_control_spdif_stream_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -1653,7 +1647,7 @@ static int hdsp_set_spdif_input(hdsp_t * static int snd_hdsp_info_spdif_in(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"}; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1666,7 +1660,7 @@ static int snd_hdsp_info_spdif_in(snd_kc static int snd_hdsp_get_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_spdif_in(hdsp); return 0; @@ -1674,7 +1668,7 @@ static int snd_hdsp_get_spdif_in(snd_kco static int snd_hdsp_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1722,7 +1716,7 @@ static int snd_hdsp_info_spdif_bits(snd_ static int snd_hdsp_get_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp); return 0; @@ -1730,7 +1724,7 @@ static int snd_hdsp_get_spdif_out(snd_kc static int snd_hdsp_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1768,7 +1762,7 @@ static int hdsp_set_spdif_professional(h static int snd_hdsp_get_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp); return 0; @@ -1776,7 +1770,7 @@ static int snd_hdsp_get_spdif_profession static int snd_hdsp_put_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1814,7 +1808,7 @@ static int hdsp_set_spdif_emphasis(hdsp_ static int snd_hdsp_get_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp); return 0; @@ -1822,7 +1816,7 @@ static int snd_hdsp_get_spdif_emphasis(s static int snd_hdsp_put_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1860,7 +1854,7 @@ static int hdsp_set_spdif_nonaudio(hdsp_ static int snd_hdsp_get_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp); return 0; @@ -1868,7 +1862,7 @@ static int snd_hdsp_get_spdif_nonaudio(s static int snd_hdsp_put_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1895,7 +1889,7 @@ static int snd_hdsp_put_spdif_nonaudio(s static int snd_hdsp_info_spdif_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1908,7 +1902,7 @@ static int snd_hdsp_info_spdif_sample_ra static int snd_hdsp_get_spdif_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); switch (hdsp_spdif_sample_rate(hdsp)) { case 32000: @@ -1962,7 +1956,7 @@ static int snd_hdsp_info_system_sample_r static int snd_hdsp_get_system_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp->system_sample_rate; return 0; @@ -1979,7 +1973,7 @@ static int snd_hdsp_get_system_sample_ra static int snd_hdsp_info_autosync_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1992,7 +1986,7 @@ static int snd_hdsp_info_autosync_sample static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); switch (hdsp_external_sample_rate(hdsp)) { case 32000: @@ -2062,7 +2056,7 @@ static int snd_hdsp_info_system_clock_mo static int snd_hdsp_get_system_clock_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_system_clock_mode(hdsp); return 0; @@ -2159,7 +2153,7 @@ static int hdsp_set_clock_source(hdsp_t static int snd_hdsp_info_clock_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" }; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -2175,7 +2169,7 @@ static int snd_hdsp_info_clock_source(sn static int snd_hdsp_get_clock_source(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_clock_source(hdsp); return 0; @@ -2183,7 +2177,7 @@ static int snd_hdsp_get_clock_source(snd static int snd_hdsp_put_clock_source(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2266,7 +2260,7 @@ static int snd_hdsp_info_da_gain(snd_kco static int snd_hdsp_get_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp); return 0; @@ -2274,7 +2268,7 @@ static int snd_hdsp_get_da_gain(snd_kcon static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2353,7 +2347,7 @@ static int snd_hdsp_info_ad_gain(snd_kco static int snd_hdsp_get_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp); return 0; @@ -2361,7 +2355,7 @@ static int snd_hdsp_get_ad_gain(snd_kcon static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2440,7 +2434,7 @@ static int snd_hdsp_info_phone_gain(snd_ static int snd_hdsp_get_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp); return 0; @@ -2448,7 +2442,7 @@ static int snd_hdsp_get_phone_gain(snd_k static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2507,7 +2501,7 @@ static int snd_hdsp_info_xlr_breakout_ca static int snd_hdsp_get_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp); return 0; @@ -2515,7 +2509,7 @@ static int snd_hdsp_get_xlr_breakout_cab static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2573,7 +2567,7 @@ static int snd_hdsp_info_aeb(snd_kcontro static int snd_hdsp_get_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); return 0; @@ -2581,7 +2575,7 @@ static int snd_hdsp_get_aeb(snd_kcontrol static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int val; @@ -2662,7 +2656,7 @@ static int hdsp_set_pref_sync_ref(hdsp_t static int snd_hdsp_info_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" }; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -2691,7 +2685,7 @@ static int snd_hdsp_info_pref_sync_ref(s static int snd_hdsp_get_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); return 0; @@ -2699,7 +2693,7 @@ static int snd_hdsp_get_pref_sync_ref(sn static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change, max; unsigned int val; @@ -2780,7 +2774,7 @@ static int snd_hdsp_info_autosync_ref(sn static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); return 0; @@ -2806,7 +2800,7 @@ static int snd_hdsp_info_passthru(snd_kc static int snd_hdsp_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&hdsp->lock, flags); @@ -2817,7 +2811,7 @@ static int snd_hdsp_get_passthru(snd_kco static int snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -2871,7 +2865,7 @@ static int snd_hdsp_info_line_out(snd_kc static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&hdsp->lock, flags); @@ -2882,7 +2876,7 @@ static int snd_hdsp_get_line_out(snd_kco static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -2920,7 +2914,7 @@ static int snd_hdsp_info_mixer(snd_kcont static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int source; int destination; @@ -2943,7 +2937,7 @@ static int snd_hdsp_get_mixer(snd_kcontr static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; int source; @@ -3011,7 +3005,7 @@ static int hdsp_wc_sync_check(hdsp_t *hd static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_wc_sync_check(hdsp); return 0; @@ -3043,7 +3037,7 @@ static int hdsp_spdif_sync_check(hdsp_t static int snd_hdsp_get_spdif_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_spdif_sync_check(hdsp); return 0; @@ -3074,7 +3068,7 @@ static int hdsp_adatsync_sync_check(hdsp static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdsp_adatsync_sync_check(hdsp); return 0; @@ -3105,7 +3099,7 @@ static int hdsp_adat_sync_check(hdsp_t * static int snd_hdsp_get_adat_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { int offset; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + hdsp_t *hdsp = snd_kcontrol_chip(kcontrol); offset = ucontrol->id.index - 1; snd_assert(offset >= 0); @@ -3809,7 +3803,7 @@ static irqreturn_t snd_hdsp_interrupt(in static snd_pcm_uframes_t snd_hdsp_hw_pointer(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); return hdsp_hw_pointer(hdsp); } @@ -3836,7 +3830,7 @@ static char *hdsp_channel_buffer_locatio static int snd_hdsp_playback_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); @@ -3851,7 +3845,7 @@ static int snd_hdsp_playback_copy(snd_pc static int snd_hdsp_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; snd_assert(pos + count <= HDSP_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); @@ -3866,7 +3860,7 @@ static int snd_hdsp_capture_copy(snd_pcm static int snd_hdsp_hw_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); char *channel_buf; channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); @@ -3878,7 +3872,7 @@ static int snd_hdsp_hw_silence(snd_pcm_s static int snd_hdsp_reset(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); snd_pcm_substream_t *other; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) other = hdsp->capture_substream; @@ -3906,7 +3900,7 @@ static int snd_hdsp_reset(snd_pcm_substr static int snd_hdsp_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); int err; pid_t this_pid; pid_t other_pid; @@ -3989,7 +3983,7 @@ static int snd_hdsp_hw_params(snd_pcm_su static int snd_hdsp_channel_info(snd_pcm_substream_t *substream, snd_pcm_channel_info_t *info) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); int mapped_channel; snd_assert(info->channel < hdsp->max_channels, return -EINVAL); @@ -4026,7 +4020,7 @@ static int snd_hdsp_ioctl(snd_pcm_substr static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); snd_pcm_substream_t *other; int running; @@ -4105,7 +4099,7 @@ static int snd_hdsp_trigger(snd_pcm_subs static int snd_hdsp_prepare(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); int result = 0; if (hdsp_check_for_iobox (hdsp)) { @@ -4364,7 +4358,7 @@ static int snd_hdsp_hw_rule_rate_in_chan static int snd_hdsp_playback_open(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); unsigned long flags; snd_pcm_runtime_t *runtime = substream->runtime; @@ -4430,7 +4424,7 @@ static int snd_hdsp_playback_open(snd_pc static int snd_hdsp_playback_release(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&hdsp->lock, flags); @@ -4449,7 +4443,7 @@ static int snd_hdsp_playback_release(snd static int snd_hdsp_capture_open(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); unsigned long flags; snd_pcm_runtime_t *runtime = substream->runtime; @@ -4509,7 +4503,7 @@ static int snd_hdsp_capture_open(snd_pcm static int snd_hdsp_capture_release(snd_pcm_substream_t *substream) { - hdsp_t *hdsp = _snd_pcm_substream_chip(substream); + hdsp_t *hdsp = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&hdsp->lock, flags); --- linux-2.6.8-rc1/sound/pci/rme9652/rme9652.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/rme9652/rme9652.c 2004-07-13 17:09:19.000000000 -0700 @@ -46,21 +46,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for RME Digi9652 (Hammerfall) soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable/disable specific RME96{52,36} soundcards."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(precise_ptr, bool, boot_devs, 0444); MODULE_PARM_DESC(precise_ptr, "Enable precise pointer (doesn't work reliably)."); -MODULE_PARM_SYNTAX(precise_ptr, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); MODULE_AUTHOR("Paul Davis , Winfried Ritsch"); MODULE_DESCRIPTION("RME Digi9652/Digi9636"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{RME,Hammerfall}," +MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall}," "{RME,Hammerfall-Light}}"); /* The Hammerfall has two sets of 24 ADAT + 2 S/PDIF channels, one for @@ -858,7 +853,7 @@ static int snd_rme9652_control_spdif_inf static int snd_rme9652_control_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif); return 0; @@ -866,7 +861,7 @@ static int snd_rme9652_control_spdif_get static int snd_rme9652_control_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -888,7 +883,7 @@ static int snd_rme9652_control_spdif_str static int snd_rme9652_control_spdif_stream_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); snd_rme9652_convert_to_aes(&ucontrol->value.iec958, rme9652->creg_spdif_stream); return 0; @@ -896,7 +891,7 @@ static int snd_rme9652_control_spdif_str static int snd_rme9652_control_spdif_stream_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -977,7 +972,7 @@ static int snd_rme9652_info_adat1_in(snd static int snd_rme9652_get_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -988,7 +983,7 @@ static int snd_rme9652_get_adat1_in(snd_ static int snd_rme9652_put_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1050,7 +1045,7 @@ static int snd_rme9652_info_spdif_in(snd static int snd_rme9652_get_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1061,7 +1056,7 @@ static int snd_rme9652_get_spdif_in(snd_ static int snd_rme9652_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1121,7 +1116,7 @@ static int snd_rme9652_info_spdif_out(sn static int snd_rme9652_get_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1132,7 +1127,7 @@ static int snd_rme9652_get_spdif_out(snd static int snd_rme9652_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1210,7 +1205,7 @@ static int snd_rme9652_info_sync_mode(sn static int snd_rme9652_get_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1221,7 +1216,7 @@ static int snd_rme9652_get_sync_mode(snd static int snd_rme9652_put_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1291,7 +1286,7 @@ static int rme9652_set_sync_pref(rme9652 static int snd_rme9652_info_sync_pref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[4] = {"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"}; - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1304,7 +1299,7 @@ static int snd_rme9652_info_sync_pref(sn static int snd_rme9652_get_sync_pref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1315,7 +1310,7 @@ static int snd_rme9652_get_sync_pref(snd static int snd_rme9652_put_sync_pref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change, max; unsigned int val; @@ -1333,7 +1328,7 @@ static int snd_rme9652_put_sync_pref(snd static int snd_rme9652_info_thru(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = rme9652->ss_channels; uinfo->value.integer.min = 0; @@ -1343,7 +1338,7 @@ static int snd_rme9652_info_thru(snd_kco static int snd_rme9652_get_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned int k; u32 thru_bits = rme9652->thru_bits; @@ -1355,7 +1350,7 @@ static int snd_rme9652_get_thru(snd_kcon static int snd_rme9652_put_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int chn; @@ -1399,7 +1394,7 @@ static int snd_rme9652_info_passthru(snd static int snd_rme9652_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1410,7 +1405,7 @@ static int snd_rme9652_get_passthru(snd_ static int snd_rme9652_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned int val; @@ -1447,7 +1442,7 @@ static int snd_rme9652_info_spdif_rate(s static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -1477,7 +1472,7 @@ static int snd_rme9652_info_adat_sync(sn static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned int mask1, mask2, val; switch (kcontrol->private_value) { @@ -1509,7 +1504,7 @@ static int snd_rme9652_info_tc_valid(snd static int snd_rme9652_get_tc_valid(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme9652_t *rme9652 = _snd_kcontrol_chip(kcontrol); + rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = (rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0; @@ -1984,7 +1979,7 @@ static irqreturn_t snd_rme9652_interrupt static snd_pcm_uframes_t snd_rme9652_hw_pointer(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); return rme9652_hw_pointer(rme9652); } @@ -2013,7 +2008,7 @@ static char *rme9652_channel_buffer_loca static int snd_rme9652_playback_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); @@ -2030,7 +2025,7 @@ static int snd_rme9652_playback_copy(snd static int snd_rme9652_capture_copy(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; snd_assert(pos + count <= RME9652_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); @@ -2047,7 +2042,7 @@ static int snd_rme9652_capture_copy(snd_ static int snd_rme9652_hw_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); char *channel_buf; channel_buf = rme9652_channel_buffer_location (rme9652, @@ -2061,7 +2056,7 @@ static int snd_rme9652_hw_silence(snd_pc static int snd_rme9652_reset(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); snd_pcm_substream_t *other; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) other = rme9652->capture_substream; @@ -2089,7 +2084,7 @@ static int snd_rme9652_reset(snd_pcm_sub static int snd_rme9652_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); int err; pid_t this_pid; pid_t other_pid; @@ -2154,7 +2149,7 @@ static int snd_rme9652_hw_params(snd_pcm static int snd_rme9652_channel_info(snd_pcm_substream_t *substream, snd_pcm_channel_info_t *info) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); int chn; snd_assert(info->channel < RME9652_NCHANNELS, return -EINVAL); @@ -2197,7 +2192,7 @@ static void rme9652_silence_playback(rme static int snd_rme9652_trigger(snd_pcm_substream_t *substream, int cmd) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); snd_pcm_substream_t *other; int running; spin_lock(&rme9652->lock); @@ -2260,7 +2255,7 @@ static int snd_rme9652_trigger(snd_pcm_s static int snd_rme9652_prepare(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); int result = 0; spin_lock(&rme9652->lock); @@ -2386,7 +2381,7 @@ static int snd_rme9652_hw_rule_rate_chan static int snd_rme9652_playback_open(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); unsigned long flags; snd_pcm_runtime_t *runtime = substream->runtime; @@ -2429,7 +2424,7 @@ static int snd_rme9652_playback_open(snd static int snd_rme9652_playback_release(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); @@ -2448,7 +2443,7 @@ static int snd_rme9652_playback_release( static int snd_rme9652_capture_open(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); unsigned long flags; snd_pcm_runtime_t *runtime = substream->runtime; @@ -2486,7 +2481,7 @@ static int snd_rme9652_capture_open(snd_ static int snd_rme9652_capture_release(snd_pcm_substream_t *substream) { - rme9652_t *rme9652 = _snd_pcm_substream_chip(substream); + rme9652_t *rme9652 = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&rme9652->lock, flags); --- linux-2.6.8-rc1/sound/pci/rme96.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/rme96.c 2004-07-13 17:09:19.000000000 -0700 @@ -47,8 +47,7 @@ MODULE_AUTHOR("Anders Torger playback_frlog; pos <<= rme96->playback_frlog; memset_io(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, @@ -364,7 +356,7 @@ snd_rme96_playback_copy(snd_pcm_substrea void __user *src, snd_pcm_uframes_t count) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->playback_frlog; pos <<= rme96->playback_frlog; copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, @@ -379,7 +371,7 @@ snd_rme96_capture_copy(snd_pcm_substream void __user *dst, snd_pcm_uframes_t count) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->capture_frlog; pos <<= rme96->capture_frlog; copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, @@ -394,6 +386,7 @@ static snd_pcm_hardware_t snd_rme96_play { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -423,6 +416,7 @@ static snd_pcm_hardware_t snd_rme96_capt { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -452,6 +446,7 @@ static snd_pcm_hardware_t snd_rme96_play { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -477,6 +472,7 @@ static snd_pcm_hardware_t snd_rme96_capt { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -992,11 +988,14 @@ snd_rme96_playback_hw_params(snd_pcm_sub snd_pcm_hw_params_t *params) { unsigned long flags; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; int err, rate, dummy; - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0) - return err; + runtime->dma_area = (void *)(rme96->iobase + RME96_IO_PLAY_BUFFER); + runtime->dma_addr = rme96->port + RME96_IO_PLAY_BUFFER; + runtime->dma_bytes = RME96_BUFFER_SIZE; + spin_lock_irqsave(&rme96->lock, flags); if (!(rme96->wcreg & RME96_WCR_MASTER) && snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && @@ -1038,23 +1037,18 @@ snd_rme96_playback_hw_params(snd_pcm_sub } static int -snd_rme96_playback_hw_free(snd_pcm_substream_t *substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int snd_rme96_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params) { unsigned long flags; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err, isadat, rate; - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params))) < 0) - return err; + runtime->dma_area = (void *)(rme96->iobase + RME96_IO_REC_BUFFER); + runtime->dma_addr = rme96->port + RME96_IO_REC_BUFFER; + runtime->dma_bytes = RME96_BUFFER_SIZE; + spin_lock_irqsave(&rme96->lock, flags); if ((err = snd_rme96_capture_setformat(rme96, params_format(params))) < 0) { spin_unlock_irqrestore(&rme96->lock, flags); @@ -1096,21 +1090,12 @@ snd_rme96_capture_hw_params(snd_pcm_subs return 0; } -static int -snd_rme96_capture_hw_free(snd_pcm_substream_t *substream) -{ - snd_pcm_lib_free_pages(substream); - return 0; -} - static void snd_rme96_playback_start(rme96_t *rme96, int from_pause) { if (!from_pause) { writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); - rme96->playback_last_appl_ptr = 0; - rme96->playback_ptr = 0; } rme96->wcreg |= RME96_WCR_START; @@ -1123,7 +1108,6 @@ snd_rme96_capture_start(rme96_t *rme96, { if (!from_pause) { writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); - rme96->capture_ptr = 0; } rme96->wcreg |= RME96_WCR_START_2; @@ -1199,7 +1183,7 @@ snd_rme96_playback_spdif_open(snd_pcm_su { unsigned long flags; int rate, dummy; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -1212,8 +1196,6 @@ snd_rme96_playback_spdif_open(snd_pcm_su rme96->wcreg &= ~RME96_WCR_ADAT; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); rme96->playback_substream = substream; - rme96->playback_last_appl_ptr = 0; - rme96->playback_ptr = 0; spin_unlock_irqrestore(&rme96->lock, flags); runtime->hw = snd_rme96_playback_spdif_info; @@ -1241,7 +1223,7 @@ snd_rme96_capture_spdif_open(snd_pcm_sub { unsigned long flags; int isadat, rate; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -1264,7 +1246,6 @@ snd_rme96_capture_spdif_open(snd_pcm_sub return -EBUSY; } rme96->capture_substream = substream; - rme96->capture_ptr = 0; spin_unlock_irqrestore(&rme96->lock, flags); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); @@ -1278,7 +1259,7 @@ snd_rme96_playback_adat_open(snd_pcm_sub { unsigned long flags; int rate, dummy; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -1291,8 +1272,6 @@ snd_rme96_playback_adat_open(snd_pcm_sub rme96->wcreg |= RME96_WCR_ADAT; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); rme96->playback_substream = substream; - rme96->playback_last_appl_ptr = 0; - rme96->playback_ptr = 0; spin_unlock_irqrestore(&rme96->lock, flags); runtime->hw = snd_rme96_playback_adat_info; @@ -1315,7 +1294,7 @@ snd_rme96_capture_adat_open(snd_pcm_subs { unsigned long flags; int isadat, rate; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); @@ -1341,7 +1320,6 @@ snd_rme96_capture_adat_open(snd_pcm_subs return -EBUSY; } rme96->capture_substream = substream; - rme96->capture_ptr = 0; spin_unlock_irqrestore(&rme96->lock, flags); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); @@ -1353,7 +1331,7 @@ static int snd_rme96_playback_close(snd_pcm_substream_t *substream) { unsigned long flags; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); int spdif = 0; spin_lock_irqsave(&rme96->lock, flags); @@ -1376,7 +1354,7 @@ static int snd_rme96_capture_close(snd_pcm_substream_t *substream) { unsigned long flags; - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); spin_lock_irqsave(&rme96->lock, flags); if (RME96_ISRECORDING(rme96)) { @@ -1391,7 +1369,7 @@ snd_rme96_capture_close(snd_pcm_substrea static int snd_rme96_playback_prepare(snd_pcm_substream_t *substream) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -1406,7 +1384,7 @@ snd_rme96_playback_prepare(snd_pcm_subst static int snd_rme96_capture_prepare(snd_pcm_substream_t *substream) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -1422,7 +1400,7 @@ static int snd_rme96_playback_trigger(snd_pcm_substream_t *substream, int cmd) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1465,7 +1443,7 @@ static int snd_rme96_capture_trigger(snd_pcm_substream_t *substream, int cmd) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); + rme96_t *rme96 = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1508,75 +1486,15 @@ snd_rme96_capture_trigger(snd_pcm_substr static snd_pcm_uframes_t snd_rme96_playback_pointer(snd_pcm_substream_t *substream) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_sframes_t diff; - size_t bytes; - - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - diff = runtime->control->appl_ptr - - rme96->playback_last_appl_ptr; - rme96->playback_last_appl_ptr = runtime->control->appl_ptr; - if (diff != 0 && - diff < -(snd_pcm_sframes_t)(runtime->boundary >> 1)) - { - diff += runtime->boundary; - } - bytes = diff << rme96->playback_frlog; - - if (bytes > RME96_BUFFER_SIZE - rme96->playback_ptr) { - memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr), - runtime->dma_area + rme96->playback_ptr, - RME96_BUFFER_SIZE - rme96->playback_ptr); - bytes -= RME96_BUFFER_SIZE - rme96->playback_ptr; - if (bytes > RME96_BUFFER_SIZE) { - bytes = RME96_BUFFER_SIZE; - } - memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER), - runtime->dma_area, - bytes); - rme96->playback_ptr = bytes; - } else if (bytes != 0) { - memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr), - runtime->dma_area + rme96->playback_ptr, - bytes); - rme96->playback_ptr += bytes; - } - } + rme96_t *rme96 = snd_pcm_substream_chip(substream); return snd_rme96_playback_ptr(rme96); } static snd_pcm_uframes_t snd_rme96_capture_pointer(snd_pcm_substream_t *substream) { - rme96_t *rme96 = _snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_pcm_uframes_t frameptr; - size_t ptr; - - frameptr = snd_rme96_capture_ptr(rme96); - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - ptr = frameptr << rme96->capture_frlog; - if (ptr > rme96->capture_ptr) { - memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - (void *)(rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr), - ptr - rme96->capture_ptr); - rme96->capture_ptr += ptr - rme96->capture_ptr; - } else if (ptr < rme96->capture_ptr) { - memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - (void *)(rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr), - RME96_BUFFER_SIZE - rme96->capture_ptr); - memcpy_fromio(runtime->dma_area, - (void *)(rme96->iobase + RME96_IO_REC_BUFFER), - ptr); - rme96->capture_ptr = ptr; - } - } - return frameptr; + rme96_t *rme96 = snd_pcm_substream_chip(substream); + return snd_rme96_capture_ptr(rme96); } static snd_pcm_ops_t snd_rme96_playback_spdif_ops = { @@ -1584,7 +1502,6 @@ static snd_pcm_ops_t snd_rme96_playback_ .close = snd_rme96_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme96_playback_hw_params, - .hw_free = snd_rme96_playback_hw_free, .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, @@ -1597,7 +1514,6 @@ static snd_pcm_ops_t snd_rme96_capture_s .close = snd_rme96_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme96_capture_hw_params, - .hw_free = snd_rme96_capture_hw_free, .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, @@ -1609,7 +1525,6 @@ static snd_pcm_ops_t snd_rme96_playback_ .close = snd_rme96_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme96_playback_hw_params, - .hw_free = snd_rme96_playback_hw_free, .prepare = snd_rme96_playback_prepare, .trigger = snd_rme96_playback_trigger, .pointer = snd_rme96_playback_pointer, @@ -1622,7 +1537,6 @@ static snd_pcm_ops_t snd_rme96_capture_a .close = snd_rme96_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme96_capture_hw_params, - .hw_free = snd_rme96_capture_hw_free, .prepare = snd_rme96_capture_prepare, .trigger = snd_rme96_capture_trigger, .pointer = snd_rme96_capture_pointer, @@ -1661,7 +1575,6 @@ snd_rme96_free_spdif_pcm(snd_pcm_t *pcm) { rme96_t *rme96 = (rme96_t *) pcm->private_data; rme96->spdif_pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); } static void @@ -1669,7 +1582,6 @@ snd_rme96_free_adat_pcm(snd_pcm_t *pcm) { rme96_t *rme96 = (rme96_t *) pcm->private_data; rme96->adat_pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); } static int __devinit @@ -1719,12 +1631,6 @@ snd_rme96_create(rme96_t *rme96) rme96->spdif_pcm->info_flags = 0; - snd_pcm_lib_preallocate_pages_for_all(rme96->spdif_pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - RME96_BUFFER_SIZE, - RME96_BUFFER_SIZE); - /* set up ALSA pcm device for ADAT */ if (pci->device == PCI_DEVICE_ID_DIGI96) { /* ADAT is not available on the base model */ @@ -1742,12 +1648,6 @@ snd_rme96_create(rme96_t *rme96) snd_pcm_set_ops(rme96->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme96_capture_adat_ops); rme96->adat_pcm->info_flags = 0; - - snd_pcm_lib_preallocate_pages_for_all(rme96->adat_pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - RME96_BUFFER_SIZE, - RME96_BUFFER_SIZE); } rme96->playback_periodsize = 0; @@ -1958,7 +1858,7 @@ snd_rme96_info_loopback_control(snd_kcon static int snd_rme96_get_loopback_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -1969,7 +1869,7 @@ snd_rme96_get_loopback_control(snd_kcont static int snd_rme96_put_loopback_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -1987,7 +1887,7 @@ static int snd_rme96_info_inputtype_control(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *_texts[5] = { "Optical", "Coaxial", "Internal", "XLR", "Analog" }; - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); char *texts[5] = { _texts[0], _texts[1], _texts[2], _texts[3], _texts[4] }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -2023,7 +1923,7 @@ snd_rme96_info_inputtype_control(snd_kco static int snd_rme96_get_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int items = 3; @@ -2063,7 +1963,7 @@ snd_rme96_get_inputtype_control(snd_kcon static int snd_rme96_put_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change, items = 3; @@ -2120,7 +2020,7 @@ snd_rme96_info_clockmode_control(snd_kco static int snd_rme96_get_clockmode_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -2131,7 +2031,7 @@ snd_rme96_get_clockmode_control(snd_kcon static int snd_rme96_put_clockmode_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -2161,7 +2061,7 @@ snd_rme96_info_attenuation_control(snd_k static int snd_rme96_get_attenuation_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -2172,7 +2072,7 @@ snd_rme96_get_attenuation_control(snd_kc static int snd_rme96_put_attenuation_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -2203,7 +2103,7 @@ snd_rme96_info_montracks_control(snd_kco static int snd_rme96_get_montracks_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -2214,7 +2114,7 @@ snd_rme96_get_montracks_control(snd_kcon static int snd_rme96_put_montracks_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned int val; int change; @@ -2258,7 +2158,7 @@ static int snd_rme96_control_spdif_info( static int snd_rme96_control_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); snd_rme96_convert_to_aes(&ucontrol->value.iec958, rme96->wcreg_spdif); return 0; @@ -2266,7 +2166,7 @@ static int snd_rme96_control_spdif_get(s static int snd_rme96_control_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -2288,7 +2188,7 @@ static int snd_rme96_control_spdif_strea static int snd_rme96_control_spdif_stream_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); snd_rme96_convert_to_aes(&ucontrol->value.iec958, rme96->wcreg_spdif_stream); return 0; @@ -2296,7 +2196,7 @@ static int snd_rme96_control_spdif_strea static int snd_rme96_control_spdif_stream_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; u32 val; @@ -2327,7 +2227,7 @@ static int snd_rme96_control_spdif_mask_ static int snd_rme96_dac_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; @@ -2339,7 +2239,7 @@ snd_rme96_dac_volume_info(snd_kcontrol_t static int snd_rme96_dac_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&rme96->lock, flags); @@ -2353,7 +2253,7 @@ snd_rme96_dac_volume_get(snd_kcontrol_t static int snd_rme96_dac_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u) { - rme96_t *rme96 = _snd_kcontrol_chip(kcontrol); + rme96_t *rme96 = snd_kcontrol_chip(kcontrol); unsigned long flags; int change = 0; --- linux-2.6.8-rc1/sound/pci/sonicvibes.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/sonicvibes.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,8 +44,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("S3 SonicVibes PCI"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{S3,SonicVibes PCI}}"); +MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}"); #ifndef PCI_VENDOR_ID_S3 #define PCI_VENDOR_ID_S3 0x5333 @@ -64,22 +63,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(reverb, bool, boot_devs, 0444); MODULE_PARM_DESC(reverb, "Enable reverb (SRAM is present) for S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(reverb, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); module_param_array(mge, bool, boot_devs, 0444); MODULE_PARM_DESC(mge, "MIC Gain Enable for S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(mge, SNDRV_ENABLED "," SNDRV_ENABLE_DESC); module_param(dmaio, uint, 0444); MODULE_PARM_DESC(dmaio, "DDMA i/o base address for S3 SonicVibes soundcard."); -MODULE_PARM_SYNTAX(dmaio, "global," SNDRV_PORT_DESC); /* * Enhanced port direct registers @@ -207,7 +200,6 @@ MODULE_PARM_SYNTAX(dmaio, "global," SNDR */ typedef struct _snd_sonicvibes sonicvibes_t; -#define chip_t sonicvibes_t struct _snd_sonicvibes { unsigned long dma1size; @@ -599,7 +591,7 @@ static int snd_sonicvibes_trigger(sonicv static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, dev_id, return IRQ_NONE); + sonicvibes_t *sonic = dev_id; unsigned char status; status = inb(SV_REG(sonic, STATUS)); @@ -864,7 +856,7 @@ static snd_pcm_ops_t snd_sonicvibes_capt static void snd_sonicvibes_pcm_free(snd_pcm_t *pcm) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, pcm->private_data, return); + sonicvibes_t *sonic = pcm->private_data; sonic->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1113,7 +1105,7 @@ SONICVIBES_MUX("Capture Source", 0) static void snd_sonicvibes_master_free(snd_kcontrol_t *kcontrol) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, _snd_kcontrol_chip(kcontrol), return); + sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol); sonic->master_mute = NULL; sonic->master_volume = NULL; } @@ -1147,7 +1139,7 @@ static int __devinit snd_sonicvibes_mixe static void snd_sonicvibes_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, entry->private_data, return); + sonicvibes_t *sonic = entry->private_data; unsigned char tmp; tmp = sonic->srs_space & 0x0f; @@ -1223,13 +1215,13 @@ static int snd_sonicvibes_free(sonicvibe } if (sonic->irq >= 0) free_irq(sonic->irq, (void *)sonic); - snd_magic_kfree(sonic); + kfree(sonic); return 0; } static int snd_sonicvibes_dev_free(snd_device_t *device) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, device->device_data, return -ENXIO); + sonicvibes_t *sonic = device->device_data; return snd_sonicvibes_free(sonic); } @@ -1257,7 +1249,7 @@ static int __devinit snd_sonicvibes_crea return -ENXIO; } - sonic = snd_magic_kcalloc(sonicvibes_t, 0, GFP_KERNEL); + sonic = kcalloc(1, sizeof(*sonic), GFP_KERNEL); if (sonic == NULL) return -ENOMEM; spin_lock_init(&sonic->reg_lock); @@ -1408,20 +1400,20 @@ SONICVIBES_SINGLE("SonicVibes External T static int snd_sonicvibes_midi_input_open(mpu401_t * mpu) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, mpu->private_data, return -EIO); + sonicvibes_t *sonic = mpu->private_data; outb(sonic->irqmask &= ~SV_MIDI_MASK, SV_REG(sonic, IRQMASK)); return 0; } static void snd_sonicvibes_midi_input_close(mpu401_t * mpu) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, mpu->private_data, return); + sonicvibes_t *sonic = mpu->private_data; outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK)); } static int __devinit snd_sonicvibes_midi(sonicvibes_t * sonic, snd_rawmidi_t * rmidi) { - mpu401_t * mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return -ENXIO); + mpu401_t * mpu = rmidi->private_data; snd_card_t *card = sonic->card; snd_rawmidi_str_t *dir; unsigned int idx; --- linux-2.6.8-rc1/sound/pci/trident/trident.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/trident/trident.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,8 +33,7 @@ MODULE_AUTHOR("Jaroslav Kysela , "); MODULE_DESCRIPTION("Trident 4D-WaveDX/NX & SiS SI7018"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Trident,4DWave DX}," +MODULE_SUPPORTED_DEVICE("{{Trident,4DWave DX}," "{Trident,4DWave NX}," "{SiS,SI7018 PCI Audio}," "{Best Union,Miss Melody 4DWave PCI}," @@ -56,19 +55,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Trident 4DWave PCI soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Trident 4DWave PCI soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Trident 4DWave PCI soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(pcm_channels, int, boot_devs, 0444); MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); -MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",default:32,allows:{{1,32}}"); module_param_array(wavetable_size, int, boot_devs, 0444); MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); -MODULE_PARM_SYNTAX(wavetable_size, SNDRV_ENABLED ",default:8192,skill:advanced"); static struct pci_device_id snd_trident_ids[] = { { 0x1023, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Trident 4DWave DX PCI Audio */ --- linux-2.6.8-rc1/sound/pci/trident/trident_main.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/trident/trident_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -44,8 +44,6 @@ #include -#define chip_t trident_t - static int snd_trident_pcm_mixer_build(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream); static int snd_trident_pcm_mixer_free(trident_t *trident, snd_trident_voice_t * voice, snd_pcm_substream_t *substream); static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -119,7 +117,7 @@ static unsigned short snd_trident_codec_ unsigned int data = 0, treg; unsigned short count = 0xffff; unsigned long flags; - trident_t *trident = snd_magic_cast(trident_t, ac97->private_data, return -ENXIO); + trident_t *trident = ac97->private_data; spin_lock_irqsave(&trident->reg_lock, flags); if (trident->device == TRIDENT_DEVICE_ID_DX) { @@ -178,7 +176,7 @@ static void snd_trident_codec_write(ac97 unsigned int address, data; unsigned short count = 0xffff; unsigned long flags; - trident_t *trident = snd_magic_cast(trident_t, ac97->private_data, return); + trident_t *trident = ac97->private_data; data = ((unsigned long) wdata) << 16; @@ -1526,7 +1524,7 @@ static int snd_trident_trigger(snd_pcm_s val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); - if ((trident_t *) _snd_pcm_chip(s->pcm) == trident) { + if ((trident_t *) snd_pcm_substream_chip(s) == trident) { voice = (snd_trident_voice_t *) s->runtime->private_data; evoice = voice->extra; what |= 1 << (voice->number & 0x1f); @@ -2127,21 +2125,21 @@ static snd_pcm_ops_t snd_trident_spdif_7 ---------------------------------------------------------------------------*/ static void snd_trident_pcm_free(snd_pcm_t *pcm) { - trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return); + trident_t *trident = pcm->private_data; trident->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } static void snd_trident_foldback_pcm_free(snd_pcm_t *pcm) { - trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return); + trident_t *trident = pcm->private_data; trident->foldback = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } static void snd_trident_spdif_pcm_free(snd_pcm_t *pcm) { - trident_t *trident = snd_magic_cast(trident_t, pcm->private_data, return); + trident_t *trident = pcm->private_data; trident->spdif = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -2968,7 +2966,7 @@ static int __devinit snd_trident_mixer(t snd_ctl_elem_value_t *uctl; int idx, err, retries = 2; - uctl = (snd_ctl_elem_value_t *)snd_kcalloc(sizeof(*uctl), GFP_KERNEL); + uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); if (!uctl) return -ENOMEM; @@ -3132,7 +3130,7 @@ static unsigned char snd_trident_gamepor trident_gameport_t *gp = (trident_gameport_t *)gameport; trident_t *chip; snd_assert(gp, return 0); - chip = snd_magic_cast(trident_t, gp->chip, return 0); + chip = gp->chip; return inb(TRID_REG(chip, GAMEPORT_LEGACY)); } @@ -3141,7 +3139,7 @@ static void snd_trident_gameport_trigger trident_gameport_t *gp = (trident_gameport_t *)gameport; trident_t *chip; snd_assert(gp, return); - chip = snd_magic_cast(trident_t, gp->chip, return); + chip = gp->chip; outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY)); } @@ -3152,7 +3150,7 @@ static int snd_trident_gameport_cooked_r int i; snd_assert(gp, return 0); - chip = snd_magic_cast(trident_t, gp->chip, return 0); + chip = gp->chip; *buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf; @@ -3169,7 +3167,7 @@ static int snd_trident_gameport_open(str trident_gameport_t *gp = (trident_gameport_t *)gameport; trident_t *chip; snd_assert(gp, return -1); - chip = snd_magic_cast(trident_t, gp->chip, return -1); + chip = gp->chip; switch (mode) { case GAMEPORT_MODE_COOKED: @@ -3280,7 +3278,7 @@ static int snd_trident_sis_reset(trident static void snd_trident_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - trident_t *trident = snd_magic_cast(trident_t, entry->private_data, return); + trident_t *trident = entry->private_data; char *s; switch (trident->device) { @@ -3331,7 +3329,7 @@ static void __devinit snd_trident_proc_i static int snd_trident_dev_free(snd_device_t *device) { - trident_t *trident = snd_magic_cast(trident_t, device->device_data, return -ENXIO); + trident_t *trident = device->device_data; return snd_trident_free(trident); } @@ -3553,7 +3551,7 @@ int __devinit snd_trident_create(snd_car return -ENXIO; } - trident = snd_magic_kcalloc(trident_t, 0, GFP_KERNEL); + trident = kcalloc(1, sizeof(*trident), GFP_KERNEL); if (trident == NULL) return -ENOMEM; trident->device = (pci->vendor << 16) | pci->device; @@ -3703,7 +3701,7 @@ int snd_trident_free(trident_t *trident) release_resource(trident->res_port); kfree_nocheck(trident->res_port); } - snd_magic_kfree(trident); + kfree(trident); return 0; } @@ -3727,7 +3725,7 @@ int snd_trident_free(trident_t *trident) static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - trident_t *trident = snd_magic_cast(trident_t, dev_id, return IRQ_NONE); + trident_t *trident = dev_id; unsigned int audio_int, chn_int, stimer, channel, mask, tmp; int delta; snd_trident_voice_t *voice; @@ -3950,7 +3948,7 @@ void snd_trident_clear_voices(trident_t #ifdef CONFIG_PM static int snd_trident_suspend(snd_card_t *card, unsigned int state) { - trident_t *trident = snd_magic_cast(trident_t, card->pm_private_data, return -EINVAL); + trident_t *trident = card->pm_private_data; trident->in_suspend = 1; snd_pcm_suspend_all(trident->pcm); @@ -3976,7 +3974,7 @@ static int snd_trident_suspend(snd_card_ static int snd_trident_resume(snd_card_t *card, unsigned int state) { - trident_t *trident = snd_magic_cast(trident_t, card->pm_private_data, return -EINVAL); + trident_t *trident = card->pm_private_data; pci_enable_device(trident->pci); if (pci_set_dma_mask(trident->pci, 0x3fffffff) < 0 || --- linux-2.6.8-rc1/sound/pci/trident/trident_memory.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/trident/trident_memory.c 2004-07-13 17:09:19.000000000 -0700 @@ -189,7 +189,7 @@ snd_trident_alloc_sg_pages(trident_t *tr snd_util_memblk_t *blk; snd_pcm_runtime_t *runtime = substream->runtime; int idx, page; - struct snd_sg_buf *sgbuf = runtime->dma_private; + struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL); hdr = trident->tlb.memhdr; --- linux-2.6.8-rc1/sound/pci/trident/trident_synth.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/trident/trident_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -506,7 +506,7 @@ static void sample_private1(trident_t * static int snd_trident_simple_put_sample(void *private_data, simple_instrument_t * instr, char __user *data, long len, int atomic) { - trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO); + trident_t *trident = private_data; int size = instr->size; int shift = 0; @@ -559,7 +559,7 @@ static int snd_trident_simple_put_sample static int snd_trident_simple_get_sample(void *private_data, simple_instrument_t * instr, char __user *data, long len, int atomic) { - //trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO); + //trident_t *trident = private_data; int size = instr->size; int shift = 0; @@ -580,7 +580,7 @@ static int snd_trident_simple_get_sample static int snd_trident_simple_remove_sample(void *private_data, simple_instrument_t * instr, int atomic) { - trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO); + trident_t *trident = private_data; int size = instr->size; if (trident->tlb.entries) { @@ -838,7 +838,7 @@ static void snd_trident_synth_instr_noti int what) { int idx; - trident_t *trident = snd_magic_cast(trident_t, private_data, return); + trident_t *trident = private_data; snd_trident_voice_t *pvoice; unsigned long flags; --- linux-2.6.8-rc1/sound/pci/via82xx.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/via82xx.c 2004-07-13 17:09:19.000000000 -0700 @@ -67,8 +67,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("VIA VT82xx audio"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); +MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) #define SUPPORT_JOYSTICK 1 @@ -88,30 +87,22 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)"); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC); #ifdef SUPPORT_JOYSTICK module_param_array(joystick, bool, boot_devs, 0444); MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)"); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLE_DESC "," SNDRV_BOOLEAN_FALSE_DESC); #endif module_param_array(ac97_clock, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); -MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); module_param_array(ac97_quirk, int, boot_devs, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1"); module_param_array(dxs_support, int, boot_devs, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); -MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list"); /* pci ids */ @@ -318,7 +309,6 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); typedef struct _snd_via82xx via82xx_t; typedef struct via_dev viadev_t; -#define chip_t via82xx_t /* * pcm stream @@ -556,7 +546,7 @@ static int snd_via82xx_codec_valid(via82 static void snd_via82xx_codec_wait(ac97_t *ac97) { - via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return); + via82xx_t *chip = ac97->private_data; int err; err = snd_via82xx_codec_ready(chip, ac97->num); /* here we need to wait fairly for long time.. */ @@ -568,7 +558,7 @@ static void snd_via82xx_codec_write(ac97 unsigned short reg, unsigned short val) { - via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return); + via82xx_t *chip = ac97->private_data; unsigned int xval; xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; @@ -583,7 +573,7 @@ static void snd_via82xx_codec_write(ac97 static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg) { - via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return ~0); + via82xx_t *chip = ac97->private_data; unsigned int xval, val = 0xffff; int again = 0; @@ -632,7 +622,7 @@ static void snd_via82xx_channel_reset(vi static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - via82xx_t *chip = snd_magic_cast(via82xx_t, dev_id, return IRQ_NONE); + via82xx_t *chip = dev_id; unsigned int status; unsigned int i; @@ -725,7 +715,11 @@ static inline unsigned int calc_linear_p unsigned int size, res; size = viadev->idx_table[idx].size; - res = viadev->idx_table[idx].offset + size - count; + /* FIXME: is this always true? */ + if (count) + res = viadev->idx_table[idx].offset + size - count; + else + res = viadev->idx_table[idx].offset; /* check the validity of the calculated position */ if (size < count || (res < viadev->lastpos && (res >= viadev->bufsize2 || viadev->lastpos < viadev->bufsize2))) { @@ -1035,6 +1029,7 @@ static snd_pcm_hardware_t snd_via82xx_hw .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -1060,19 +1055,6 @@ static int snd_via82xx_pcm_open(via82xx_ int err; unsigned long flags; struct via_rate_lock *ratep; - struct ratetbl { - int rate; - unsigned int bit; - } ratebits[] = { - {8000, SNDRV_PCM_RATE_8000}, - {11025, SNDRV_PCM_RATE_11025}, - {16000, SNDRV_PCM_RATE_16000}, - {22050, SNDRV_PCM_RATE_22050}, - {32000, SNDRV_PCM_RATE_32000}, - {44100, SNDRV_PCM_RATE_44100}, - {48000, SNDRV_PCM_RATE_48000}, - }; - int i; runtime->hw = snd_via82xx_hw; @@ -1080,10 +1062,10 @@ static int snd_via82xx_pcm_open(via82xx_ ratep = &chip->rates[viadev->direction]; spin_lock_irqsave(&ratep->lock, flags); ratep->used++; - if (chip->spdif_on) { - runtime->hw.rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000; - runtime->hw.rate_min = 32000; - runtime->hw.rate_max = 48000; + if (chip->spdif_on && viadev->reg_offset == 0x30) { + /* DXS#3 and spdif is on */ + runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF]; + snd_pcm_limit_hw_rates(runtime); } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) { /* fixed DXS playback rate */ runtime->hw.rates = SNDRV_PCM_RATE_48000; @@ -1091,27 +1073,10 @@ static int snd_via82xx_pcm_open(via82xx_ } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; - for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) { - if (runtime->hw.rates & ratebits[i].bit) { - runtime->hw.rate_min = ratebits[i].rate; - break; - } - } - for (i = ARRAY_SIZE(ratebits) - 1; i >= 0; i--) { - if (runtime->hw.rates & ratebits[i].bit) { - runtime->hw.rate_max = ratebits[i].rate; - break; - } - } + snd_pcm_limit_hw_rates(runtime); } else { /* a fixed rate */ runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) { - if (ratep->rate == ratebits[i].rate) { - runtime->hw.rates = ratebits[i].bit; - break; - } - } runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate; } spin_unlock_irqrestore(&ratep->lock, flags); @@ -1363,6 +1328,10 @@ static int __devinit snd_via8233a_pcm_ne snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; + /* SPDIF supported? */ + if (! ac97_can_spdif(chip->ac97)) + return 0; + /* PCM #1: DXS3 playback (for spdif) */ err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 0, &pcm); if (err < 0) @@ -1567,13 +1536,13 @@ static snd_kcontrol_new_t snd_via8233_dx static void snd_via82xx_mixer_free_ac97_bus(ac97_bus_t *bus) { - via82xx_t *chip = snd_magic_cast(via82xx_t, bus->private_data, return); + via82xx_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) { - via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return); + via82xx_t *chip = ac97->private_data; chip->ac97 = NULL; } @@ -1660,9 +1629,11 @@ static int snd_via8233_init_misc(via82xx if (err < 0) return err; } - err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip)); - if (err < 0) - return err; + if (ac97_can_spdif(chip->ac97)) { + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip)); + if (err < 0) + return err; + } if (chip->chip_type != TYPE_VIA8233A) { err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip)); if (err < 0) @@ -1672,6 +1643,7 @@ static int snd_via8233_init_misc(via82xx /* select spdif data slot 10/11 */ pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val); val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011; + val &= ~VIA8233_SPDIF_DX3; /* SPDIF off as default */ pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val); return 0; @@ -1766,7 +1738,7 @@ static int snd_via686_init_misc(via82xx_ */ static void snd_via82xx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - via82xx_t *chip = snd_magic_cast(via82xx_t, entry->private_data, return); + via82xx_t *chip = entry->private_data; int i; snd_iprintf(buffer, "%s\n\n", chip->card->longname); @@ -1903,7 +1875,7 @@ static int __devinit snd_via82xx_chip_in */ static int snd_via82xx_suspend(snd_card_t *card, unsigned int state) { - via82xx_t *chip = snd_magic_cast(via82xx_t, card->pm_private_data, return -EINVAL); + via82xx_t *chip = card->pm_private_data; int i; for (i = 0; i < 2; i++) @@ -1930,7 +1902,7 @@ static int snd_via82xx_suspend(snd_card_ static int snd_via82xx_resume(snd_card_t *card, unsigned int state) { - via82xx_t *chip = snd_magic_cast(via82xx_t, card->pm_private_data, return -EINVAL); + via82xx_t *chip = card->pm_private_data; int idx, i; pci_enable_device(chip->pci); @@ -1997,13 +1969,13 @@ static int snd_via82xx_free(via82xx_t *c pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg); } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_via82xx_dev_free(snd_device_t *device) { - via82xx_t *chip = snd_magic_cast(via82xx_t, device->device_data, return -ENXIO); + via82xx_t *chip = device->device_data; return snd_via82xx_free(chip); } @@ -2023,7 +1995,7 @@ static int __devinit snd_via82xx_create( if ((err = pci_enable_device(pci)) < 0) return err; - if ((chip = snd_magic_kcalloc(via82xx_t, 0, GFP_KERNEL)) == NULL) + if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) return -ENOMEM; chip->chip_type = chip_type; @@ -2114,6 +2086,7 @@ static int __devinit check_dxs_list(stru { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/ { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ + { .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ --- linux-2.6.8-rc1/sound/pci/vx222/vx222.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/vx222/vx222.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,15 +28,12 @@ #include #include "vx222.h" -#define chip_t vx_core_t - #define CARD_NAME "VX222" MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("Digigram VX222 V2/Mic"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); +MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -47,19 +44,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(mic, bool, boot_devs, 0444); MODULE_PARM_DESC(mic, "Enable Microphone."); -MODULE_PARM_SYNTAX(mic, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); module_param_array(ibl, int, boot_devs, 0444); MODULE_PARM_DESC(ibl, "Capture IBL size."); -MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED); /* */ @@ -130,13 +122,13 @@ static int snd_vx222_free(vx_core_t *chi kfree_nocheck(vx->port_res[i]); } } - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_vx222_dev_free(snd_device_t *device) { - vx_core_t *chip = snd_magic_cast(vx_core_t, device->device_data, return -ENXIO); + vx_core_t *chip = device->device_data; return snd_vx222_free(chip); } --- linux-2.6.8-rc1/sound/pci/vx222/vx222_ops.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/vx222/vx222_ops.c 2004-07-13 17:09:19.000000000 -0700 @@ -27,8 +27,6 @@ #include #include "vx222.h" -#define chip_t vx_core_t - static int vx2_reg_offset[VX_REG_MAX] = { [VX_ICR] = 0x00, --- linux-2.6.8-rc1/sound/pci/ymfpci/ymfpci.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ymfpci/ymfpci.c 2004-07-13 17:09:19.000000000 -0700 @@ -33,8 +33,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Yamaha DS-XG PCI"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Yamaha,YMF724}," +MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724}," "{Yamaha,YMF724F}," "{Yamaha,YMF740}," "{Yamaha,YMF740C}," @@ -54,27 +53,20 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for the Yamaha DS-XG PCI soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for the Yamaha DS-XG PCI soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Yamaha DS-XG soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(mpu_port, long, boot_devs, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 Port."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED); module_param_array(fm_port, long, boot_devs, 0444); MODULE_PARM_DESC(fm_port, "FM OPL-3 Port."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED); #ifdef SUPPORT_JOYSTICK module_param_array(joystick_port, long, boot_devs, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address"); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED); #endif module_param_array(rear_switch, bool, boot_devs, 0444); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); -MODULE_PARM_SYNTAX(rear_switch, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); static struct pci_device_id snd_ymfpci_ids[] = { { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* YMF724 */ --- linux-2.6.8-rc1/sound/pci/ymfpci/ymfpci_main.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pci/ymfpci/ymfpci_main.c 2004-07-13 17:09:19.000000000 -0700 @@ -42,8 +42,6 @@ #include -#define chip_t ymfpci_t - /* * constants */ @@ -102,7 +100,7 @@ static int snd_ymfpci_codec_ready(ymfpci static void snd_ymfpci_codec_write(ac97_t *ac97, u16 reg, u16 val) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return); + ymfpci_t *chip = ac97->private_data; u32 cmd; snd_ymfpci_codec_ready(chip, 0); @@ -112,7 +110,7 @@ static void snd_ymfpci_codec_write(ac97_ static u16 snd_ymfpci_codec_read(ac97_t *ac97, u16 reg) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return -ENXIO); + ymfpci_t *chip = ac97->private_data; if (snd_ymfpci_codec_ready(chip, 0)) return ~0; @@ -330,7 +328,7 @@ static void snd_ymfpci_pcm_interrupt(ymf static void snd_ymfpci_pcm_capture_interrupt(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return); + ymfpci_pcm_t *ypcm = runtime->private_data; ymfpci_t *chip = ypcm->chip; u32 pos, delta; @@ -358,7 +356,7 @@ static int snd_ymfpci_playback_trigger(s int cmd) { ymfpci_t *chip = snd_pcm_substream_chip(substream); - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, substream->runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = substream->runtime->private_data; int result = 0; spin_lock(&chip->reg_lock); @@ -395,7 +393,7 @@ static int snd_ymfpci_capture_trigger(sn int cmd) { ymfpci_t *chip = snd_pcm_substream_chip(substream); - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, substream->runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = substream->runtime->private_data; int result = 0; u32 tmp; @@ -578,7 +576,7 @@ static int snd_ymfpci_playback_hw_params snd_pcm_hw_params_t * hw_params) { snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) @@ -596,7 +594,7 @@ static int snd_ymfpci_playback_hw_free(s if (runtime->private_data == NULL) return 0; - ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ypcm = runtime->private_data; /* wait, until the PCI operations are not finished */ snd_ymfpci_irq_wait(chip); @@ -616,7 +614,7 @@ static int snd_ymfpci_playback_prepare(s { // ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; unsigned int nvoice; ypcm->period_size = runtime->period_size; @@ -654,7 +652,7 @@ static int snd_ymfpci_capture_prepare(sn { ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; snd_ymfpci_capture_bank_t * bank; int nbank; u32 rate, format; @@ -698,7 +696,7 @@ static snd_pcm_uframes_t snd_ymfpci_play { ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; ymfpci_voice_t *voice = ypcm->voices[0]; if (!(ypcm->running && voice)) @@ -710,7 +708,7 @@ static snd_pcm_uframes_t snd_ymfpci_capt { ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; if (!ypcm->running) return 0; @@ -736,7 +734,7 @@ static void snd_ymfpci_irq_wait(ymfpci_t static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, dev_id, return IRQ_NONE); + ymfpci_t *chip = dev_id; u32 status, nvoice, mode; ymfpci_voice_t *voice; @@ -830,10 +828,10 @@ static snd_pcm_hardware_t snd_ymfpci_cap static void snd_ymfpci_pcm_free_substream(snd_pcm_runtime_t *runtime) { - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return); + ymfpci_pcm_t *ypcm = runtime->private_data; if (ypcm) - snd_magic_kfree(ypcm); + kfree(ypcm); } static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) @@ -842,7 +840,7 @@ static int snd_ymfpci_playback_open_1(sn snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; - ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL); + ypcm = kcalloc(1, sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; @@ -891,7 +889,7 @@ static int snd_ymfpci_playback_open(snd_ if ((err = snd_ymfpci_playback_open_1(substream)) < 0) return err; - ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return 0); + ypcm = runtime->private_data; ypcm->output_front = 1; ypcm->output_rear = chip->mode_dup4ch ? 1 : 0; spin_lock_irqsave(&chip->reg_lock, flags); @@ -913,7 +911,7 @@ static int snd_ymfpci_playback_spdif_ope if ((err = snd_ymfpci_playback_open_1(substream)) < 0) return err; - ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return 0); + ypcm = runtime->private_data; ypcm->output_front = 0; ypcm->output_rear = 1; spin_lock_irqsave(&chip->reg_lock, flags); @@ -941,7 +939,7 @@ static int snd_ymfpci_playback_4ch_open( if ((err = snd_ymfpci_playback_open_1(substream)) < 0) return err; - ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return 0); + ypcm = runtime->private_data; ypcm->output_front = 0; ypcm->output_rear = 1; spin_lock_irqsave(&chip->reg_lock, flags); @@ -958,7 +956,7 @@ static int snd_ymfpci_capture_open(snd_p snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; - ypcm = snd_magic_kcalloc(ymfpci_pcm_t, 0, GFP_KERNEL); + ypcm = kcalloc(1, sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; @@ -993,7 +991,7 @@ static int snd_ymfpci_playback_close_1(s static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream) { ymfpci_t *chip = snd_pcm_substream_chip(substream); - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, substream->runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = substream->runtime->private_data; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -1041,7 +1039,7 @@ static int snd_ymfpci_capture_close(snd_ { ymfpci_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - ymfpci_pcm_t *ypcm = snd_magic_cast(ymfpci_pcm_t, runtime->private_data, return -ENXIO); + ymfpci_pcm_t *ypcm = runtime->private_data; if (ypcm != NULL) { chip->capture_substream[ypcm->capture_bank_number] = NULL; @@ -1074,7 +1072,7 @@ static snd_pcm_ops_t snd_ymfpci_capture_ static void snd_ymfpci_pcm_free(snd_pcm_t *pcm) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return); + ymfpci_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1120,7 +1118,7 @@ static snd_pcm_ops_t snd_ymfpci_capture_ static void snd_ymfpci_pcm2_free(snd_pcm_t *pcm) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return); + ymfpci_t *chip = pcm->private_data; chip->pcm2 = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1166,7 +1164,7 @@ static snd_pcm_ops_t snd_ymfpci_playback static void snd_ymfpci_pcm_spdif_free(snd_pcm_t *pcm) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return); + ymfpci_t *chip = pcm->private_data; chip->pcm_spdif = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1211,7 +1209,7 @@ static snd_pcm_ops_t snd_ymfpci_playback static void snd_ymfpci_pcm_4ch_free(snd_pcm_t *pcm) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, pcm->private_data, return); + ymfpci_t *chip = pcm->private_data; chip->pcm_4ch = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1709,13 +1707,13 @@ static snd_kcontrol_new_t snd_ymfpci_rea static void snd_ymfpci_mixer_free_ac97_bus(ac97_bus_t *bus) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, bus->private_data, return); + ymfpci_t *chip = bus->private_data; chip->ac97_bus = NULL; } static void snd_ymfpci_mixer_free_ac97(ac97_t *ac97) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return); + ymfpci_t *chip = ac97->private_data; chip->ac97 = NULL; } @@ -1854,7 +1852,7 @@ int __devinit snd_ymfpci_timer(ymfpci_t static void snd_ymfpci_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, entry->private_data, return); + ymfpci_t *chip = entry->private_data; int i; snd_iprintf(buffer, "YMFPCI\n\n"); @@ -2117,13 +2115,13 @@ static int snd_ymfpci_free(ymfpci_t *chi pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_ymfpci_dev_free(snd_device_t *device) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, device->device_data, return -ENXIO); + ymfpci_t *chip = device->device_data; return snd_ymfpci_free(chip); } @@ -2159,7 +2157,7 @@ static int saved_regs_index[] = { static int snd_ymfpci_suspend(snd_card_t *card, unsigned int state) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->pm_private_data, return -EINVAL); + ymfpci_t *chip = card->pm_private_data; unsigned int i; snd_pcm_suspend_all(chip->pcm); @@ -2178,7 +2176,7 @@ static int snd_ymfpci_suspend(snd_card_t static int snd_ymfpci_resume(snd_card_t *card, unsigned int state) { - ymfpci_t *chip = snd_magic_cast(ymfpci_t, card->pm_private_data, return -EINVAL); + ymfpci_t *chip = card->pm_private_data; unsigned int i; pci_enable_device(chip->pci); @@ -2223,7 +2221,7 @@ int __devinit snd_ymfpci_create(snd_card if ((err = pci_enable_device(pci)) < 0) return err; - chip = snd_magic_kcalloc(ymfpci_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->old_legacy_ctrl = old_legacy_ctrl; --- linux-2.6.8-rc1/sound/pcmcia/pdaudiocf/pdaudiocf.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pcmcia/pdaudiocf/pdaudiocf.c 2004-07-13 17:09:19.000000000 -0700 @@ -37,8 +37,7 @@ MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Sound Core " CARD_NAME); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Sound Core," CARD_NAME "}}"); +MODULE_SUPPORTED_DEVICE("{{Sound Core," CARD_NAME "}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -49,13 +48,10 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param(irq_mask, int, 0444); MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard."); module_param_array(irq_list, int, boot_devs, 0444); @@ -103,13 +99,13 @@ static int snd_pdacf_free(pdacf_t *pdacf card_list[pdacf->index] = NULL; pdacf->card = NULL; - snd_magic_kfree(pdacf); + kfree(pdacf); return 0; } static int snd_pdacf_dev_free(snd_device_t *device) { - pdacf_t *chip = snd_magic_cast(pdacf_t, device->device_data, return -ENXIO); + pdacf_t *chip = device->device_data; return snd_pdacf_free(chip); } @@ -152,7 +148,7 @@ static dev_link_t *snd_pdacf_attach(void return NULL; if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) { - snd_magic_kfree(pdacf); + kfree(pdacf); snd_card_free(card); return NULL; } @@ -258,7 +254,7 @@ static int snd_pdacf_assign_resources(pd */ static void snd_pdacf_detach(dev_link_t *link) { - pdacf_t *chip = snd_magic_cast(pdacf_t, link->priv, return); + pdacf_t *chip = link->priv; snd_printdd(KERN_DEBUG "pdacf_detach called\n"); /* Remove the interface data from the linked list */ @@ -297,7 +293,7 @@ do { last_fn = (fn); if ((last_ret = (re static void pdacf_config(dev_link_t *link) { client_handle_t handle = link->handle; - pdacf_t *pdacf = snd_magic_cast(pdacf_t, link->priv, return); + pdacf_t *pdacf = link->priv; tuple_t tuple; cisparse_t parse; config_info_t conf; --- linux-2.6.8-rc1/sound/pcmcia/pdaudiocf/pdaudiocf_core.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pcmcia/pdaudiocf/pdaudiocf_core.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,7 +30,7 @@ */ unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg) { - pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return 0); + pdacf_t *chip = private_data; unsigned long timeout; unsigned long flags; unsigned char res; @@ -62,7 +62,7 @@ unsigned char pdacf_ak4117_read(void *pr void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val) { - pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return); + pdacf_t *chip = private_data; unsigned long timeout; unsigned long flags; @@ -130,7 +130,7 @@ void pdacf_reinit(pdacf_t *chip, int res static void pdacf_proc_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer) { - pdacf_t *chip = snd_magic_cast(pdacf_t, entry->private_data, return); + pdacf_t *chip = entry->private_data; u16 tmp; snd_iprintf(buffer, "PDAudioCF\n\n"); @@ -151,7 +151,7 @@ pdacf_t *snd_pdacf_create(snd_card_t *ca { pdacf_t *chip; - chip = snd_magic_kcalloc(pdacf_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return NULL; chip->card = card; @@ -257,7 +257,7 @@ void snd_pdacf_powerdown(pdacf_t *chip) int snd_pdacf_suspend(snd_card_t *card, unsigned int state) { - pdacf_t *chip = snd_magic_cast(pdacf_t, card->pm_private_data, return -EINVAL); + pdacf_t *chip = card->pm_private_data; u16 val; snd_pcm_suspend_all(chip->pcm); @@ -278,7 +278,7 @@ static inline int check_signal(pdacf_t * int snd_pdacf_resume(snd_card_t *card, unsigned int state) { - pdacf_t *chip = snd_magic_cast(pdacf_t, card->pm_private_data, return -EINVAL); + pdacf_t *chip = card->pm_private_data; int timeout = 40; pdacf_reinit(chip, 1); --- linux-2.6.8-rc1/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,7 +28,7 @@ */ irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs) { - pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return IRQ_NONE); + pdacf_t *chip = dev; unsigned short stat; if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| @@ -258,7 +258,7 @@ static void pdacf_transfer(pdacf_t *chip void pdacf_tasklet(unsigned long private_data) { - pdacf_t *chip = snd_magic_cast(pdacf_t, (void *)private_data, return); + pdacf_t *chip = (pdacf_t *) private_data; int size, off, cont, rdp, wdp; if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) --- linux-2.6.8-rc1/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,8 +28,6 @@ #include #include "pdaudiocf.h" -#define chip_t pdacf_t - /* * we use a vmalloc'ed (sg-)buffer @@ -331,7 +329,7 @@ static snd_pcm_ops_t pdacf_pcm_capture_o */ static void snd_pdacf_pcm_free(snd_pcm_t *pcm) { - pdacf_t *chip = snd_magic_cast(pdacf_t, pcm->private_data, return); + pdacf_t *chip = pcm->private_data; chip->pcm = NULL; } --- linux-2.6.8-rc1/sound/pcmcia/vx/vx_entry.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/pcmcia/vx/vx_entry.c 2004-07-13 17:09:19.000000000 -0700 @@ -69,13 +69,13 @@ static int snd_vxpocket_free(vx_core_t * hw->card_list[vxp->index] = NULL; chip->card = NULL; - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_vxpocket_dev_free(snd_device_t *device) { - vx_core_t *chip = snd_magic_cast(vx_core_t, device->device_data, return -ENXIO); + vx_core_t *chip = device->device_data; return snd_vxpocket_free(chip); } @@ -121,7 +121,7 @@ dev_link_t *snd_vxpocket_attach(struct s return NULL; if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) { - snd_magic_kfree(chip); + kfree(chip); snd_card_free(card); return NULL; } @@ -226,7 +226,7 @@ static int snd_vxpocket_assign_resources */ void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link) { - vx_core_t *chip = snd_magic_cast(vx_core_t, link->priv, return); + vx_core_t *chip = link->priv; snd_printdd(KERN_DEBUG "vxpocket_detach called\n"); /* Remove the interface data from the linked list */ @@ -263,7 +263,7 @@ do { last_fn = (fn); if ((last_ret = (re static void vxpocket_config(dev_link_t *link) { client_handle_t handle = link->handle; - vx_core_t *chip = snd_magic_cast(vx_core_t, link->priv, return); + vx_core_t *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; tuple_t tuple; cisparse_t parse; --- linux-2.6.8-rc1/sound/pcmcia/vx/vxp_mixer.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/sound/pcmcia/vx/vxp_mixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -25,8 +25,6 @@ #include #include "vxpocket.h" -#define chip_t vx_core_t - #define MIC_LEVEL_MIN 0 #define MIC_LEVEL_MAX 8 --- linux-2.6.8-rc1/sound/pcmcia/vx/vxpocket.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pcmcia/vx/vxpocket.c 2004-07-13 17:09:19.000000000 -0700 @@ -50,8 +50,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("Digigram " CARD_NAME); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); +MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -63,20 +62,16 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param(irq_mask, int, 0444); MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard."); module_param_array(irq_list, int, boot_devs, 0444); MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard."); module_param_array(ibl, int, boot_devs, 0444); MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard."); -MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED); /* --- linux-2.6.8-rc1/sound/pcmcia/vx/vxp_ops.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/pcmcia/vx/vxp_ops.c 2004-07-13 17:09:19.000000000 -0700 @@ -26,8 +26,6 @@ #include #include "vxpocket.h" -#define chip_t vx_core_t - static int vxp_reg_offset[VX_REG_MAX] = { [VX_ICR] = 0x00, // ICR --- linux-2.6.8-rc1/sound/ppc/awacs.c 2003-08-08 22:55:15.000000000 -0700 +++ 25/sound/ppc/awacs.c 2004-07-13 17:09:19.000000000 -0700 @@ -29,8 +29,6 @@ #include #include "pmac.h" -#define chip_t pmac_t - #ifdef CONFIG_ADB_CUDA #define PMAC_AMP_AVAIL --- linux-2.6.8-rc1/sound/ppc/burgundy.c 2003-08-08 22:55:15.000000000 -0700 +++ 25/sound/ppc/burgundy.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,8 +28,6 @@ #include "pmac.h" #include "burgundy.h" -#define chip_t pmac_t - /* Waits for busy flag to clear */ inline static void --- linux-2.6.8-rc1/sound/ppc/daca.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/ppc/daca.c 2004-07-13 17:09:19.000000000 -0700 @@ -28,8 +28,6 @@ #include #include "pmac.h" -#define chip_t pmac_t - /* i2c address */ #define DACA_I2C_ADDR 0x4d --- linux-2.6.8-rc1/sound/ppc/pmac.c 2004-07-11 14:13:30.000000000 -0700 +++ 25/sound/ppc/pmac.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,8 +36,6 @@ #include #endif -#define chip_t pmac_t - #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK) static int snd_pmac_register_sleep_notifier(pmac_t *chip); @@ -688,7 +686,7 @@ static void snd_pmac_dbdma_reset(pmac_t static irqreturn_t snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs) { - pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE); + pmac_t *chip = devid; snd_pmac_pcm_update(chip, &chip->playback); return IRQ_HANDLED; } @@ -697,7 +695,7 @@ snd_pmac_tx_intr(int irq, void *devid, s static irqreturn_t snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs) { - pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE); + pmac_t *chip = devid; snd_pmac_pcm_update(chip, &chip->capture); return IRQ_HANDLED; } @@ -706,7 +704,7 @@ snd_pmac_rx_intr(int irq, void *devid, s static irqreturn_t snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs) { - pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE); + pmac_t *chip = devid; int ctrl = in_le32(&chip->awacs->control); /*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/ @@ -802,7 +800,7 @@ static int snd_pmac_free(pmac_t *chip) release_OF_resource(chip->node, i); } } - snd_magic_kfree(chip); + kfree(chip); return 0; } @@ -812,7 +810,7 @@ static int snd_pmac_free(pmac_t *chip) */ static int snd_pmac_dev_free(snd_device_t *device) { - pmac_t *chip = snd_magic_cast(pmac_t, device->device_data, return -ENXIO); + pmac_t *chip = device->device_data; return snd_pmac_free(chip); } @@ -1069,7 +1067,7 @@ int __init snd_pmac_new(snd_card_t *card snd_runtime_check(chip_return, return -EINVAL); *chip_return = NULL; - chip = snd_magic_kcalloc(pmac_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->card = card; @@ -1206,7 +1204,7 @@ int __init snd_pmac_new(snd_card_t *card static int snd_pmac_suspend(snd_card_t *card, unsigned int state) { - pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL); + pmac_t *chip = card->pm_private_data; unsigned long flags; if (chip->suspend) @@ -1228,7 +1226,7 @@ static int snd_pmac_suspend(snd_card_t * static int snd_pmac_resume(snd_card_t *card, unsigned int state) { - pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL); + pmac_t *chip = card->pm_private_data; snd_pmac_sound_feature(chip, 1); if (chip->resume) --- linux-2.6.8-rc1/sound/ppc/powermac.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/ppc/powermac.c 2004-07-13 17:09:19.000000000 -0700 @@ -30,8 +30,7 @@ #define CHIP_NAME "PMac" MODULE_DESCRIPTION("PowerMac"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Apple,PowerMac}}"); +MODULE_SUPPORTED_DEVICE("{{Apple,PowerMac}}"); MODULE_LICENSE("GPL"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ @@ -43,17 +42,13 @@ static int enable_beep = 1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); /* module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable this soundchip."); - MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */ #ifdef PMAC_SUPPORT_PCM_BEEP module_param(enable_beep, bool, 0444); MODULE_PARM_DESC(enable_beep, "Enable beep using PCM."); -MODULE_PARM_SYNTAX(enable_beep, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); #endif --- linux-2.6.8-rc1/sound/ppc/tumbler.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/ppc/tumbler.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,8 +36,6 @@ #include "pmac.h" #include "tumbler_volume.h" -#define chip_t pmac_t - /* i2c address for tumbler */ #define TAS_I2C_ADDR 0x34 @@ -872,7 +870,7 @@ static void tumbler_update_automute(pmac /* interrupt - headphone plug changed */ static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs) { - pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE); + pmac_t *chip = devid; if (chip->update_automute && chip->initialized) { chip->update_automute(chip, 1); return IRQ_HANDLED; --- linux-2.6.8-rc1/sound/sparc/amd7930.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/sparc/amd7930.c 2004-07-13 17:09:19.000000000 -0700 @@ -54,18 +54,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Sun AMD7930 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Sun AMD7930 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Sun AMD7930 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_AUTHOR("Thomas K. Dyas and David S. Miller"); MODULE_DESCRIPTION("Sun AMD7930"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Sun,AMD7930}}"); +MODULE_SUPPORTED_DEVICE("{{Sun,AMD7930}}"); /* Device register layout. */ @@ -345,7 +341,6 @@ typedef struct snd_amd7930 { unsigned int regs_size; struct snd_amd7930 *next; } amd7930_t; -#define chip_t amd7930_t static amd7930_t *amd7930_list; @@ -764,7 +759,7 @@ static snd_pcm_ops_t snd_amd7930_capture static void snd_amd7930_pcm_free(snd_pcm_t *pcm) { - amd7930_t *amd = snd_magic_cast(amd7930_t, pcm->private_data, return); + amd7930_t *amd = pcm->private_data; amd->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); @@ -947,14 +942,14 @@ static int snd_amd7930_free(amd7930_t *a if (amd->regs) sbus_iounmap(amd->regs, amd->regs_size); - snd_magic_kfree(amd); + kfree(amd); return 0; } static int snd_amd7930_dev_free(snd_device_t *device) { - amd7930_t *amd = snd_magic_cast(amd7930_t, device->device_data, return -ENXIO); + amd7930_t *amd = device->device_data; return snd_amd7930_free(amd); } @@ -976,7 +971,7 @@ static int __init snd_amd7930_create(snd int err; *ramd = NULL; - amd = snd_magic_kcalloc(amd7930_t, 0, GFP_KERNEL); + amd = kcalloc(1, sizeof(*amd), 0, GFP_KERNEL); if (amd == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/sparc/cs4231.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/sparc/cs4231.c 2004-07-13 17:09:19.000000000 -0700 @@ -53,18 +53,14 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller"); MODULE_DESCRIPTION("Sun CS4231"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Sun,CS4231}}"); +MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); typedef struct snd_cs4231 { spinlock_t lock; @@ -112,7 +108,6 @@ typedef struct snd_cs4231 { unsigned int regs_size; struct snd_cs4231 *next; } cs4231_t; -#define chip_t cs4231_t static cs4231_t *cs4231_list; @@ -1232,7 +1227,7 @@ static void snd_cs4231_generic_interrupt #ifdef SBUS_SUPPORT static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - cs4231_t *chip = snd_magic_cast(cs4231_t, dev_id, return); + cs4231_t *chip = dev_id; u32 csr; csr = sbus_readl(chip->port + APCCSR); @@ -1256,7 +1251,7 @@ static irqreturn_t snd_cs4231_sbus_inter #ifdef EBUS_SUPPORT static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie) { - cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return); + cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) { snd_pcm_period_elapsed(chip->playback_substream); @@ -1267,7 +1262,7 @@ static void snd_cs4231_ebus_play_callbac static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie) { - cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return); + cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) { snd_pcm_period_elapsed(chip->capture_substream); @@ -1547,7 +1542,7 @@ static snd_pcm_ops_t snd_cs4231_capture_ static void snd_cs4231_pcm_free(snd_pcm_t *pcm) { - cs4231_t *chip = snd_magic_cast(cs4231_t, pcm->private_data, return); + cs4231_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1592,7 +1587,7 @@ int snd_cs4231_pcm(cs4231_t *chip) static void snd_cs4231_timer_free(snd_timer_t *timer) { - cs4231_t *chip = snd_magic_cast(cs4231_t, timer->private_data, return); + cs4231_t *chip = timer->private_data; chip->timer = NULL; } @@ -1950,14 +1945,14 @@ static int snd_cs4231_sbus_free(cs4231_t if (chip->timer) snd_device_free(chip->card, chip->timer); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_cs4231_sbus_dev_free(snd_device_t *device) { - cs4231_t *cp = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO); + cs4231_t *cp = device->device_data; return snd_cs4231_sbus_free(cp); } @@ -1975,7 +1970,7 @@ static int __init snd_cs4231_sbus_create int err; *rchip = NULL; - chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -2064,14 +2059,14 @@ static int snd_cs4231_ebus_free(cs4231_t if (chip->timer) snd_device_free(chip->card, chip->timer); - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_cs4231_ebus_dev_free(snd_device_t *device) { - cs4231_t *cp = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO); + cs4231_t *cp = device->device_data; return snd_cs4231_ebus_free(cp); } @@ -2089,7 +2084,7 @@ static int __init snd_cs4231_ebus_create int err; *rchip = NULL; - chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; --- linux-2.6.8-rc1/sound/synth/emux/emux.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/synth/emux/emux.c 2004-07-13 17:09:19.000000000 -0700 @@ -39,7 +39,7 @@ int snd_emux_new(snd_emux_t **remu) snd_emux_t *emu; *remu = NULL; - emu = snd_magic_kcalloc(snd_emux_t, 0, GFP_KERNEL); + emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); if (emu == NULL) return -ENOMEM; @@ -77,7 +77,7 @@ int snd_emux_register(snd_emux_t *emu, s emu->card = card; emu->name = snd_kmalloc_strdup(name, GFP_KERNEL); - emu->voices = snd_kcalloc(sizeof(snd_emux_voice_t) * emu->max_voices, GFP_KERNEL); + emu->voices = kcalloc(emu->max_voices, sizeof(snd_emux_voice_t), GFP_KERNEL); if (emu->voices == NULL) return -ENOMEM; @@ -143,7 +143,7 @@ int snd_emux_free(snd_emux_t *emu) if (emu->name) kfree(emu->name); - snd_magic_kfree(emu); + kfree(emu); return 0; } --- linux-2.6.8-rc1/sound/synth/emux/emux_effect.c 2003-06-14 12:18:07.000000000 -0700 +++ 25/sound/synth/emux/emux_effect.c 2004-07-13 17:09:19.000000000 -0700 @@ -278,7 +278,7 @@ void snd_emux_create_effect(snd_emux_port_t *p) { int i; - p->effect = snd_kcalloc(sizeof(snd_emux_effect_table_t) * p->chset.max_channels, GFP_KERNEL); + p->effect = kcalloc(p->chset.max_channels, sizeof(snd_emux_effect_table_t), GFP_KERNEL); if (p->effect) { for (i = 0; i < p->chset.max_channels; i++) p->chset.channels[i].private = p->effect + i; --- linux-2.6.8-rc1/sound/synth/emux/emux_hwdep.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/synth/emux/emux_hwdep.c 2004-07-13 17:09:19.000000000 -0700 @@ -104,7 +104,7 @@ snd_emux_hwdep_misc_mode(snd_emux_t *emu static int snd_emux_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) { - snd_emux_t *emu = snd_magic_cast(snd_emux_t, hw->private_data, return -ENXIO); + snd_emux_t *emu = hw->private_data; switch (cmd) { case SNDRV_EMUX_IOCTL_VERSION: --- linux-2.6.8-rc1/sound/synth/emux/emux_nrpn.c 2003-06-14 12:17:56.000000000 -0700 +++ 25/sound/synth/emux/emux_nrpn.c 2004-07-13 17:09:19.000000000 -0700 @@ -292,7 +292,7 @@ snd_emux_nrpn(void *p, snd_midi_channel_ { snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL, return); snd_assert(chan != NULL, return); @@ -382,7 +382,7 @@ snd_emux_sysex(void *p, unsigned char *b snd_emux_port_t *port; snd_emux_t *emu; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL, return); snd_assert(chset != NULL, return); emu = port->emu; --- linux-2.6.8-rc1/sound/synth/emux/emux_oss.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/synth/emux/emux_oss.c 2004-07-13 17:09:19.000000000 -0700 @@ -108,7 +108,7 @@ snd_emux_open_seq_oss(snd_seq_oss_arg_t snd_seq_port_callback_t callback; char tmpname[64]; - emu = snd_magic_cast(snd_emux_t, closure, return -EINVAL); + emu = closure; snd_assert(arg != NULL && emu != NULL, return -ENXIO); down(&emu->register_mutex); @@ -179,7 +179,7 @@ snd_emux_close_seq_oss(snd_seq_oss_arg_t snd_emux_port_t *p; snd_assert(arg != NULL, return -ENXIO); - p = snd_magic_cast(snd_emux_port_t, arg->private_data, return -EINVAL); + p = arg->private_data; snd_assert(p != NULL, return -ENXIO); emu = p->emu; @@ -208,7 +208,7 @@ snd_emux_load_patch_seq_oss(snd_seq_oss_ int rc; snd_assert(arg != NULL, return -ENXIO); - p = snd_magic_cast(snd_emux_port_t, arg->private_data, return -EINVAL); + p = arg->private_data; snd_assert(p != NULL, return -ENXIO); emu = p->emu; @@ -248,7 +248,7 @@ snd_emux_ioctl_seq_oss(snd_seq_oss_arg_t snd_emux_t *emu; snd_assert(arg != NULL, return -ENXIO); - p = snd_magic_cast(snd_emux_port_t, arg->private_data, return -EINVAL); + p = arg->private_data; snd_assert(p != NULL, return -ENXIO); emu = p->emu; @@ -278,7 +278,7 @@ snd_emux_reset_seq_oss(snd_seq_oss_arg_t snd_emux_port_t *p; snd_assert(arg != NULL, return -ENXIO); - p = snd_magic_cast(snd_emux_port_t, arg->private_data, return -EINVAL); + p = arg->private_data; snd_assert(p != NULL, return -ENXIO); snd_emux_reset_port(p); return 0; @@ -296,7 +296,7 @@ snd_emux_event_oss_input(snd_seq_event_t snd_emux_port_t *p; unsigned char cmd, *data; - p = snd_magic_cast(snd_emux_port_t, private_data, return -EINVAL); + p = private_data; snd_assert(p != NULL, return -EINVAL); emu = p->emu; snd_assert(emu != NULL, return -EINVAL); --- linux-2.6.8-rc1/sound/synth/emux/emux_proc.c 2003-06-14 12:18:33.000000000 -0700 +++ 25/sound/synth/emux/emux_proc.c 2004-07-13 17:09:19.000000000 -0700 @@ -36,7 +36,7 @@ snd_emux_proc_info_read(snd_info_entry_t snd_emux_t *emu; int i; - emu = snd_magic_cast(snd_emux_t, entry->private_data, return); + emu = entry->private_data; down(&emu->register_mutex); if (emu->name) snd_iprintf(buf, "Device: %s\n", emu->name); --- linux-2.6.8-rc1/sound/synth/emux/emux_seq.c 2004-02-17 20:48:47.000000000 -0800 +++ 25/sound/synth/emux/emux_seq.c 2004-07-13 17:09:19.000000000 -0700 @@ -146,14 +146,14 @@ snd_emux_create_port(snd_emux_t *emu, ch int i, type, cap; /* Allocate structures for this channel */ - if ((p = snd_magic_kcalloc(snd_emux_port_t, 0, GFP_KERNEL)) == NULL) { + if ((p = kcalloc(1, sizeof(*p), GFP_KERNEL)) == NULL) { snd_printk("no memory\n"); return NULL; } - p->chset.channels = snd_kcalloc(max_channels * sizeof(snd_midi_channel_t), GFP_KERNEL); + p->chset.channels = kcalloc(max_channels, sizeof(snd_midi_channel_t), GFP_KERNEL); if (p->chset.channels == NULL) { snd_printk("no memory\n"); - snd_magic_kfree(p); + kfree(p); return NULL; } for (i = 0; i < max_channels; i++) @@ -192,14 +192,14 @@ free_port(void *private_data) { snd_emux_port_t *p; - p = snd_magic_cast(snd_emux_port_t, private_data, return); + p = private_data; if (p) { #ifdef SNDRV_EMUX_USE_RAW_EFFECT snd_emux_delete_effect(p); #endif if (p->chset.channels) kfree(p->chset.channels); - snd_magic_kfree(p); + kfree(p); } } @@ -257,7 +257,7 @@ snd_emux_event_input(snd_seq_event_t *ev { snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, private_data, return -EINVAL); + port = private_data; snd_assert(port != NULL && ev != NULL, return -EINVAL); snd_midi_process_event(&emux_ops, ev, &port->chset); @@ -308,7 +308,7 @@ snd_emux_use(void *private_data, snd_seq snd_emux_port_t *p; snd_emux_t *emu; - p = snd_magic_cast(snd_emux_port_t, private_data, return -EINVAL); + p = private_data; snd_assert(p != NULL, return -EINVAL); emu = p->emu; snd_assert(emu != NULL, return -EINVAL); @@ -329,7 +329,7 @@ snd_emux_unuse(void *private_data, snd_s snd_emux_port_t *p; snd_emux_t *emu; - p = snd_magic_cast(snd_emux_port_t, private_data, return -EINVAL); + p = private_data; snd_assert(p != NULL, return -EINVAL); emu = p->emu; snd_assert(emu != NULL, return -EINVAL); @@ -383,7 +383,7 @@ int snd_emux_init_virmidi(snd_emux_t *em if (emu->midi_ports <= 0) return 0; - emu->vmidi = snd_kcalloc(sizeof(snd_rawmidi_t*) * emu->midi_ports, GFP_KERNEL); + emu->vmidi = kcalloc(emu->midi_ports, sizeof(snd_rawmidi_t*), GFP_KERNEL); if (emu->vmidi == NULL) return -ENOMEM; @@ -392,7 +392,7 @@ int snd_emux_init_virmidi(snd_emux_t *em snd_virmidi_dev_t *rdev; if (snd_virmidi_new(card, emu->midi_devidx + i, &rmidi) < 0) goto __error; - rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, continue); + rdev = rmidi->private_data; sprintf(rmidi->name, "%s Synth MIDI", emu->name); rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH; rdev->client = emu->client; --- linux-2.6.8-rc1/sound/synth/emux/emux_synth.c 2003-06-14 12:18:09.000000000 -0700 +++ 25/sound/synth/emux/emux_synth.c 2004-07-13 17:09:19.000000000 -0700 @@ -61,7 +61,7 @@ snd_emux_note_on(void *p, int note, int unsigned long flags; snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL && chan != NULL, return); emu = port->emu; @@ -160,7 +160,7 @@ snd_emux_note_off(void *p, int note, int unsigned long flags; snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL && chan != NULL, return); emu = port->emu; @@ -201,7 +201,7 @@ snd_emux_note_off(void *p, int note, int */ void snd_emux_timer_callback(unsigned long data) { - snd_emux_t *emu = snd_magic_cast(snd_emux_t, (void*)data, return); + snd_emux_t *emu = (snd_emux_t*) data; snd_emux_voice_t *vp; int ch, do_again = 0; @@ -238,7 +238,7 @@ snd_emux_key_press(void *p, int note, in unsigned long flags; snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL && chan != NULL, return); emu = port->emu; @@ -322,7 +322,7 @@ snd_emux_control(void *p, int type, snd_ { snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL && chan != NULL, return); switch (type) { @@ -402,7 +402,7 @@ snd_emux_terminate_note(void *p, int not snd_emux_t *emu; snd_emux_port_t *port; - port = snd_magic_cast(snd_emux_port_t, p, return); + port = p; snd_assert(port != NULL && chan != NULL, return); emu = port->emu; --- linux-2.6.8-rc1/sound/synth/emux/soundfont.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/synth/emux/soundfont.c 2004-07-13 17:09:19.000000000 -0700 @@ -261,7 +261,7 @@ newsf(snd_sf_list_t *sflist, int type, c } /* not found -- create a new one */ - sf = (snd_soundfont_t*)snd_kcalloc(sizeof(*sf), GFP_KERNEL); + sf = kcalloc(1, sizeof(*sf), GFP_KERNEL); if (sf == NULL) return NULL; sf->id = sflist->fonts_size; @@ -337,7 +337,7 @@ sf_zone_new(snd_sf_list_t *sflist, snd_s { snd_sf_zone_t *zp; - if ((zp = snd_kcalloc(sizeof(*zp), GFP_KERNEL)) == NULL) + if ((zp = kcalloc(1, sizeof(*zp), GFP_KERNEL)) == NULL) return NULL; zp->next = sf->zones; sf->zones = zp; @@ -368,7 +368,7 @@ sf_sample_new(snd_sf_list_t *sflist, snd { snd_sf_sample_t *sp; - if ((sp = snd_kcalloc(sizeof(*sp), GFP_KERNEL)) == NULL) + if ((sp = kcalloc(1, sizeof(*sp), GFP_KERNEL)) == NULL) return NULL; sp->next = sf->samples; @@ -1347,7 +1347,7 @@ snd_sf_new(snd_sf_callback_t *callback, { snd_sf_list_t *sflist; - if ((sflist = snd_kcalloc(sizeof(snd_sf_list_t), GFP_KERNEL)) == NULL) + if ((sflist = kcalloc(1, sizeof(*sflist), GFP_KERNEL)) == NULL) return NULL; init_MUTEX(&sflist->presets_mutex); --- linux-2.6.8-rc1/sound/synth/util_mem.c 2003-06-14 12:18:06.000000000 -0700 +++ 25/sound/synth/util_mem.c 2004-07-13 17:09:19.000000000 -0700 @@ -38,7 +38,7 @@ snd_util_memhdr_new(int memsize) { snd_util_memhdr_t *hdr; - hdr = snd_kcalloc(sizeof(*hdr), GFP_KERNEL); + hdr = kcalloc(1, sizeof(*hdr), GFP_KERNEL); if (hdr == NULL) return NULL; hdr->size = memsize; --- linux-2.6.8-rc1/sound/usb/usbaudio.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/usb/usbaudio.c 2004-07-13 17:09:19.000000000 -0700 @@ -58,8 +58,7 @@ MODULE_AUTHOR("Takashi Iwai "); MODULE_DESCRIPTION("USB Audio"); MODULE_LICENSE("GPL"); -MODULE_CLASSES("{sound}"); -MODULE_DEVICES("{{Generic,USB Audio}}"); +MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -73,25 +72,18 @@ static int boot_devs; module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); -MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for the USB audio adapter."); -MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable USB audio adapter."); -MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); module_param_array(vid, int, boot_devs, 0444); MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device."); -MODULE_PARM_SYNTAX(vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16"); module_param_array(pid, int, boot_devs, 0444); MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); -MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16"); module_param(nrpacks, int, 0444); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); -MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{1,10}}"); module_param(async_unlink, bool, 0444); MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); -MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC); /* @@ -207,8 +199,6 @@ struct snd_usb_stream { struct list_head list; }; -#define chip_t snd_usb_stream_t - /* * we keep the snd_usb_audio_t instances by ourselves for merging @@ -1183,9 +1173,9 @@ static int init_usb_sample_rate(struct u if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) { - snd_printk(KERN_ERR "%d:%d:%d: cannot get freq at ep 0x%x\n", + snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n", dev->devnum, iface, fmt->altsetting, ep); - return err; + return 0; /* some devices don't support reading */ } crate = data[0] | (data[1] << 8) | (data[2] << 16); if (crate != rate) { @@ -2001,7 +1991,7 @@ static void proc_dump_substream_status(s static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - snd_usb_stream_t *stream = snd_magic_cast(snd_usb_stream_t, entry->private_data, return); + snd_usb_stream_t *stream = entry->private_data; snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name); @@ -2089,7 +2079,7 @@ static void snd_usb_audio_stream_free(sn free_substream(&stream->substream[0]); free_substream(&stream->substream[1]); list_del(&stream->list); - snd_magic_kfree(stream); + kfree(stream); } static void snd_usb_audio_pcm_free(snd_pcm_t *pcm) @@ -2146,7 +2136,7 @@ static int add_audio_endpoint(snd_usb_au } /* create a new pcm */ - as = snd_magic_kmalloc(snd_usb_stream_t, 0, GFP_KERNEL); + as = kmalloc(sizeof(*as), GFP_KERNEL); if (! as) return -ENOMEM; memset(as, 0, sizeof(*as)); @@ -2158,7 +2148,7 @@ static int add_audio_endpoint(snd_usb_au stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, &pcm); if (err < 0) { - snd_magic_kfree(as); + kfree(as); return err; } as->pcm = pcm; @@ -2182,6 +2172,24 @@ static int add_audio_endpoint(snd_usb_au /* + * check if the device uses big-endian samples + */ +static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) +{ + /* M-Audio */ + if (dev->descriptor.idVendor == 0x0763) { + /* Quattro: captured data only */ + if (dev->descriptor.idProduct == 0x2001 && + fp->endpoint & USB_DIR_IN) + return 1; + /* Audiophile USB */ + if (dev->descriptor.idProduct == 0x2003) + return 1; + } + return 0; +} + +/* * parse the audio format type I descriptor * and returns the corresponding pcm format * @@ -2217,17 +2225,13 @@ static int parse_audio_format_i_type(str pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - /* M-Audio audiophile USB workaround */ - if (dev->descriptor.idVendor == 0x0763 && - dev->descriptor.idProduct == 0x2003) + if (is_big_endian_format(dev, fp)) pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - /* M-Audio audiophile USB workaround */ - if (dev->descriptor.idVendor == 0x0763 && - dev->descriptor.idProduct == 0x2003) + if (is_big_endian_format(dev, fp)) pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S24_3LE; @@ -2920,14 +2924,14 @@ static int snd_usb_create_quirk(snd_usb_ */ static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + snd_usb_audio_t *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); } static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) { - snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + snd_usb_audio_t *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", chip->dev->descriptor.idVendor, chip->dev->descriptor.idProduct); } @@ -2950,13 +2954,13 @@ static void snd_usb_audio_create_proc(sn static int snd_usb_audio_free(snd_usb_audio_t *chip) { - snd_magic_kfree(chip); + kfree(chip); return 0; } static int snd_usb_audio_dev_free(snd_device_t *device) { - snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, device->device_data, return -ENXIO); + snd_usb_audio_t *chip = device->device_data; return snd_usb_audio_free(chip); } @@ -2990,7 +2994,7 @@ static int snd_usb_audio_create(struct u return -ENOMEM; } - chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL); + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (! chip) { snd_card_free(card); return -ENOMEM; @@ -3182,7 +3186,7 @@ static void snd_usb_audio_disconnect(str if (ptr == (void *)-1L) return; - chip = snd_magic_cast(snd_usb_audio_t, ptr, return); + chip = ptr; card = chip->card; down(®ister_mutex); chip->shutdown = 1; --- linux-2.6.8-rc1/sound/usb/usbaudio.h 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/usb/usbaudio.h 2004-07-13 17:09:19.000000000 -0700 @@ -205,6 +205,8 @@ int snd_usb_ctl_msg(struct usb_device *d int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif); int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk); +void snd_usbmidi_input_stop(struct list_head* p); +void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p, struct usb_driver *driver); /* --- linux-2.6.8-rc1/sound/usb/usbmidi.c 2004-04-03 20:39:14.000000000 -0800 +++ 25/sound/usb/usbmidi.c 2004-07-13 17:09:19.000000000 -0700 @@ -175,7 +175,7 @@ static void snd_usbmidi_input_packet(snd */ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) { - snd_usb_midi_in_endpoint_t* ep = snd_magic_cast(snd_usb_midi_in_endpoint_t, urb->context, return); + snd_usb_midi_in_endpoint_t* ep = urb->context; if (urb->status == 0) { uint8_t* buffer = (uint8_t*)ep->urb->transfer_buffer; @@ -229,7 +229,7 @@ static void snd_usbmidi_in_midiman_compl static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) { - snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, urb->context, return); + snd_usb_midi_out_endpoint_t* ep = urb->context; if (urb->status < 0) { if (snd_usbmidi_urb_error(urb->status) < 0) @@ -417,14 +417,14 @@ static void snd_usbmidi_do_output(snd_us static void snd_usbmidi_out_tasklet(unsigned long data) { - snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, (void*)data, return); + snd_usb_midi_out_endpoint_t* ep = (snd_usb_midi_out_endpoint_t *) data; snd_usbmidi_do_output(ep); } static int snd_usbmidi_output_open(snd_rawmidi_substream_t* substream) { - snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, substream->rmidi->private_data, return -ENXIO); + snd_usb_midi_t* umidi = substream->rmidi->private_data; usbmidi_out_port_t* port = NULL; int i, j; @@ -503,7 +503,7 @@ static void snd_usbmidi_in_endpoint_dele kfree(ep->urb->transfer_buffer); usb_free_urb(ep->urb); } - snd_magic_kfree(ep); + kfree(ep); } /* @@ -571,7 +571,7 @@ static int snd_usbmidi_in_endpoint_creat int length; rep->in = NULL; - ep = snd_magic_kcalloc(snd_usb_midi_in_endpoint_t, 0, GFP_KERNEL); + ep = kcalloc(1, sizeof(*ep), GFP_KERNEL); if (!ep) return -ENOMEM; ep->umidi = umidi; @@ -631,7 +631,7 @@ static void snd_usbmidi_out_endpoint_del kfree(ep->urb->transfer_buffer); usb_free_urb(ep->urb); } - snd_magic_kfree(ep); + kfree(ep); } /* @@ -647,7 +647,7 @@ static int snd_usbmidi_out_endpoint_crea void* buffer; rep->out = NULL; - ep = snd_magic_kcalloc(snd_usb_midi_out_endpoint_t, 0, GFP_KERNEL); + ep = kcalloc(1, sizeof(*ep), GFP_KERNEL); if (!ep) return -ENOMEM; ep->umidi = umidi; @@ -695,7 +695,7 @@ static void snd_usbmidi_free(snd_usb_mid if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } - snd_magic_kfree(umidi); + kfree(umidi); } /* @@ -718,7 +718,7 @@ void snd_usbmidi_disconnect(struct list_ static void snd_usbmidi_rawmidi_free(snd_rawmidi_t* rmidi) { - snd_usb_midi_t* umidi = snd_magic_cast(snd_usb_midi_t, rmidi->private_data, return); + snd_usb_midi_t* umidi = rmidi->private_data; snd_usbmidi_free(umidi); } @@ -1145,6 +1145,44 @@ static int snd_usbmidi_create_rawmidi(sn } /* + * Temporarily stop input. + */ +void snd_usbmidi_input_stop(struct list_head* p) +{ + snd_usb_midi_t* umidi; + int i; + + umidi = list_entry(p, snd_usb_midi_t, list); + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { + snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i]; + if (ep->in) + usb_unlink_urb(ep->in->urb); + } +} + +static void snd_usbmidi_input_start_ep(snd_usb_midi_in_endpoint_t* ep) +{ + if (ep) { + struct urb* urb = ep->urb; + urb->dev = ep->umidi->chip->dev; + snd_usbmidi_submit_urb(urb, GFP_KERNEL); + } +} + +/* + * Resume input after a call to snd_usbmidi_input_stop(). + */ +void snd_usbmidi_input_start(struct list_head* p) +{ + snd_usb_midi_t* umidi; + int i; + + umidi = list_entry(p, snd_usb_midi_t, list); + for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) + snd_usbmidi_input_start_ep(umidi->endpoints[i].in); +} + +/* * Creates and registers everything needed for a MIDI streaming interface. */ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, @@ -1156,7 +1194,7 @@ int snd_usb_create_midi_interface(snd_us int out_ports, in_ports; int i, err; - umidi = snd_magic_kcalloc(snd_usb_midi_t, 0, GFP_KERNEL); + umidi = kcalloc(1, sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; umidi->chip = chip; @@ -1189,7 +1227,7 @@ int snd_usb_create_midi_interface(snd_us } } if (err < 0) { - snd_magic_kfree(umidi); + kfree(umidi); return err; } @@ -1202,7 +1240,7 @@ int snd_usb_create_midi_interface(snd_us } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { - snd_magic_kfree(umidi); + kfree(umidi); return err; } @@ -1219,8 +1257,6 @@ int snd_usb_create_midi_interface(snd_us list_add(&umidi->list, &umidi->chip->midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) - if (umidi->endpoints[i].in) - snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb, - GFP_KERNEL); + snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } --- linux-2.6.8-rc1/sound/usb/usbmixer.c 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/usb/usbmixer.c 2004-07-13 17:09:19.000000000 -0700 @@ -573,7 +573,7 @@ static struct usb_feature_control_info a static void usb_mixer_elem_free(snd_kcontrol_t *kctl) { if (kctl->private_data) { - snd_magic_kfree((void *)kctl->private_data); + kfree((void *)kctl->private_data); kctl->private_data = 0; } } @@ -635,7 +635,7 @@ static int get_min_max(usb_mixer_elem_in /* get a feature/mixer unit info */ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; if (cval->val_type == USB_MIXER_BOOLEAN || cval->val_type == USB_MIXER_INV_BOOLEAN) @@ -659,7 +659,7 @@ static int mixer_ctl_feature_info(snd_kc /* get the current value from feature/mixer unit */ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int c, cnt, val, err; if (cval->cmask) { @@ -700,7 +700,7 @@ static int mixer_ctl_feature_get(snd_kco /* put the current value to feature/mixer unit */ static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int c, cnt, val, oval, err; int changed = 0; @@ -774,7 +774,7 @@ static void build_feature_ctl(mixer_buil if (check_ignored_ctl(state, unitid, control)) return; - cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); + cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; @@ -801,7 +801,7 @@ static void build_feature_ctl(mixer_buil kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (! kctl) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); - snd_magic_kfree(cval); + kfree(cval); return; } kctl->private_free = usb_mixer_elem_free; @@ -943,7 +943,7 @@ static void build_mixer_unit_ctl(mixer_b if (check_ignored_ctl(state, unitid, 0)) return; - cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); + cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); if (! cval) return; @@ -968,7 +968,7 @@ static void build_mixer_unit_ctl(mixer_b kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (! kctl) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); - snd_magic_kfree(cval); + kfree(cval); return; } kctl->private_free = usb_mixer_elem_free; @@ -1014,7 +1014,7 @@ static int parse_audio_mixer_unit(mixer_ /* get callback for processing/extension unit */ static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); @@ -1032,7 +1032,7 @@ static int mixer_ctl_procunit_get(snd_kc /* put callback for processing/extension unit */ static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); @@ -1170,7 +1170,7 @@ static int build_audio_procunit(mixer_bu continue; if (check_ignored_ctl(state, unitid, valinfo->control)) continue; - cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); + cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; @@ -1195,7 +1195,7 @@ static int build_audio_procunit(mixer_bu kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); - snd_magic_kfree(cval); + kfree(cval); return -ENOMEM; } kctl->private_free = usb_mixer_elem_free; @@ -1244,7 +1244,7 @@ static int parse_audio_extension_unit(mi */ static int mixer_ctl_selector_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; char **itemlist = (char **)kcontrol->private_value; snd_assert(itemlist, return -EINVAL); @@ -1260,7 +1260,7 @@ static int mixer_ctl_selector_info(snd_k /* get callback for selector unit */ static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int val, err; err = get_cur_ctl_value(cval, 0, &val); @@ -1279,7 +1279,7 @@ static int mixer_ctl_selector_get(snd_kc /* put callback for selector unit */ static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL); + usb_mixer_elem_info_t *cval = kcontrol->private_data; int val, oval, err; err = get_cur_ctl_value(cval, 0, &oval); @@ -1315,9 +1315,9 @@ static void usb_mixer_selector_elem_free int i, num_ins = 0; if (kctl->private_data) { - usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kctl->private_data,); + usb_mixer_elem_info_t *cval = kctl->private_data; num_ins = cval->max; - snd_magic_kfree(cval); + kfree(cval); kctl->private_data = 0; } if (kctl->private_value) { @@ -1357,7 +1357,7 @@ static int parse_audio_selector_unit(mix if (check_ignored_ctl(state, unitid, 0)) return 0; - cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); + cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; @@ -1375,7 +1375,7 @@ static int parse_audio_selector_unit(mix namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL); if (! namelist) { snd_printk(KERN_ERR "cannot malloc\n"); - snd_magic_kfree(cval); + kfree(cval); return -ENOMEM; } #define MAX_ITEM_NAME_LEN 64 @@ -1388,7 +1388,7 @@ static int parse_audio_selector_unit(mix while (--i > 0) kfree(namelist[i]); kfree(namelist); - snd_magic_kfree(cval); + kfree(cval); return -ENOMEM; } if (check_input_term(state, desc[5 + i], &iterm) >= 0) @@ -1400,7 +1400,7 @@ static int parse_audio_selector_unit(mix kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); if (! kctl) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); - snd_magic_kfree(cval); + kfree(cval); return -ENOMEM; } kctl->private_value = (unsigned long)namelist; --- linux-2.6.8-rc1/sound/usb/usbquirks.h 2004-06-15 23:29:49.000000000 -0700 +++ 25/sound/usb/usbquirks.h 2004-07-13 17:09:19.000000000 -0700 @@ -830,11 +830,42 @@ YAMAHA_DEVICE(0x5008, "01V96"), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "M-Audio", .product_name = "Quattro", - .ifnum = 9, - .type = QUIRK_MIDI_MIDIMAN, - .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0001, - .in_cables = 0x0001 + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const snd_usb_audio_quirk_t[]) { + /* + * Interfaces 0-2 are "Windows-compatible", 16-bit only, + * and share endpoints with the other interfaces. + * Ignore them. The other interfaces can do 24 bits, + * but captured samples are big-endian (see usbaudio.c). + */ + { + .ifnum = 4, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 5, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 7, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 8, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 9, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } } } },